Compare commits
221 Commits
0f22e2021c
...
feature/au
Author | SHA1 | Date | |
---|---|---|---|
5035c6fe2f | |||
7943537276 | |||
62c1c84bb2 | |||
df36fd8ed0 | |||
8713ed587d | |||
7271ea2cd9 | |||
dff2e67991 | |||
65880d1472 | |||
326e34a4b8 | |||
3a213c87b5 | |||
1b197b2e12 | |||
092378b24a | |||
561c70668d | |||
cb15789b95 | |||
dd07cbd57d | |||
52f9638d74 | |||
e52c3f4d4b | |||
bac61d5cdc | |||
2d6ee4aef5 | |||
475a255851 | |||
f95c7973d7 | |||
aad31c2fa7 | |||
3fa6170f0c | |||
f73b264a2a | |||
e91e8c8894 | |||
eea01cd569 | |||
da60d81e90 | |||
2e73cb92d4 | |||
86fbee4116 | |||
ab3ecae54b | |||
ae915681ac | |||
cfbe54a4e5 | |||
a976b59732 | |||
d6006b17d9 | |||
c911f7958a | |||
f592aba75d | |||
190eb5eef7 | |||
979900ab07 | |||
76b514e1e6 | |||
b758d53a63 | |||
dabec5185f | |||
c189183e72 | |||
60ad323e7a | |||
2d2e356f1c | |||
710663b490 | |||
24c2ac8347 | |||
e0a0fa29d2 | |||
53817e9dc4 | |||
556931d2b1 | |||
a2004bd789 | |||
e32b3f6595 | |||
12f60bcfdf | |||
b3b8ee3104 | |||
9613f553e9 | |||
1a8a7cc4f0 | |||
702ebd9137 | |||
aa3922da50 | |||
d6c609d107 | |||
61566714a3 | |||
f4ae5c9f77 | |||
cfe3d222e6 | |||
e0d6d81907 | |||
5e8e865a99 | |||
3061540396 | |||
bb119e8636 | |||
14a98deff3 | |||
4919c90ae8 | |||
5c47587189 | |||
3223637471 | |||
389e3eac43 | |||
302e8bb994 | |||
992f8a7b37 | |||
c8c3852323 | |||
8d9ab8b088 | |||
45185b9236 | |||
5f33ec5824 | |||
e217d3254e | |||
263416a401 | |||
b4bd86ed44 | |||
277cac323e | |||
5f304b91f3 | |||
85f2a81ebb | |||
8de23a3f3b | |||
3b526c9c6f | |||
516e7a04ad | |||
84f13ced80 | |||
dcd92f7d2a | |||
2a944eeefe | |||
dc93539e23 | |||
dd58c76aba | |||
106ef6dac8 | |||
2bc99c78c2 | |||
0185c13a95 | |||
9632040ade | |||
85a34b20f9 | |||
e25f3da5a5 | |||
4c9234d07a | |||
f5853f7777 | |||
eb7fe88d59 | |||
2a3ee3de8d | |||
00ab65d648 | |||
79854f3fa1 | |||
618a152f23 | |||
ce91a19068 | |||
17b531e181 | |||
222c97d63c | |||
6a1229a4ba | |||
2bff4db1d7 | |||
a3b123a207 | |||
e698f3b224 | |||
c66baaa765 | |||
815be3126e | |||
715e953182 | |||
86915f6ec5 | |||
30b42de86f | |||
21217b067f | |||
9b160d2df0 | |||
74a9ee4f39 | |||
b0e775d299 | |||
d6b82f1556 | |||
3f642daf89 | |||
858cfe1d3c | |||
943d647a47 | |||
d96cf9470a | |||
c8b3cff5a6 | |||
547179b0ca | |||
0765f6606f | |||
12881d9345 | |||
79ed029db0 | |||
1a8da002cf | |||
c828d04f05 | |||
f919fe30fa | |||
b3db6643b9 | |||
cea3a909b5 | |||
b52d96a55e | |||
1fb71a172e | |||
27520c7ca4 | |||
af14cce3f8 | |||
75bcc91037 | |||
c78ff60231 | |||
09eb8794b8 | |||
470e54da8d | |||
19299598c3 | |||
f1c51ab8a7 | |||
b77c5d1d7f | |||
05481fc0c8 | |||
6b00452830 | |||
7e4c5dcf24 | |||
c0f30e56f7 | |||
9852646fff | |||
c2d678847e | |||
e77edf18ac | |||
3780aa6cf1 | |||
21124ec2ad | |||
0ee5fc59d3 | |||
b8dfef691e | |||
a1886b0b60 | |||
e1002b5315 | |||
fed90d4f7b | |||
dcfb329c5a | |||
b8a21a8baa | |||
7f73035b02 | |||
317437fedc | |||
26286984c2 | |||
9ae31c0146 | |||
87fd8fa96f | |||
c3401e732f | |||
4ee7373b3f | |||
64c0c5f8e6 | |||
18a597c726 | |||
|
baca596603 | ||
d993387216 | |||
aed2856df3 | |||
c78858c152 | |||
f49581259e | |||
f5bf642cd6 | |||
7687acb366 | |||
e655e1598a | |||
64ed38332f | |||
d438303aec | |||
38b3736951 | |||
6be060ea40 | |||
5c5756150f | |||
6e6f4ced7b | |||
b806f7f9e3 | |||
98c5ddad65 | |||
654cd87006 | |||
533efb328c | |||
5b1b23d3e6 | |||
bcd003a685 | |||
c4adc3f434 | |||
cba589a38e | |||
a42b29721e | |||
a102152d34 | |||
dc71dcba0d | |||
266bf0b368 | |||
88c94acd93 | |||
eede454e76 | |||
b0ddf91677 | |||
c30af40079 | |||
dd266f8cdf | |||
9c70da0b77 | |||
89bc00e5da | |||
72dc41ab79 | |||
711d46da68 | |||
a8b033dfdb | |||
ca0e1a48dc | |||
e08f8f60f2 | |||
26e257fe96 | |||
44b06d1c04 | |||
0c2b1a4699 | |||
240b61f428 | |||
64510898bb | |||
ab7bbdfc5a | |||
c1925c21c0 | |||
bd579ad83e | |||
99afb30611 | |||
bb1dafc89c | |||
5cc391391e | |||
c571a56d55 | |||
a0ee491805 |
13
.gitignore
vendored
@@ -9,8 +9,8 @@ db.sqlite3
|
||||
db.sqlite3-journal
|
||||
db.sqlite3.bak
|
||||
# user uploaded files
|
||||
media
|
||||
uploads
|
||||
static_files
|
||||
|
||||
### Django.Python Stack ###
|
||||
# Byte-compiled / optimized / DLL files
|
||||
@@ -65,12 +65,6 @@ coverage.xml
|
||||
# Translations
|
||||
*.mo
|
||||
|
||||
# Django stuff:
|
||||
# exclude migrations from repository. These should be created locally, matching local DB requirements.
|
||||
# lostplaces/manage.py makemigrations && lostplaces/manage.py migrate
|
||||
|
||||
lostplaces/lostplaces_app/migrations/
|
||||
|
||||
# pyenv
|
||||
.python-version
|
||||
|
||||
@@ -94,4 +88,7 @@ env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Editors
|
||||
.vscode
|
||||
.vscode
|
||||
|
||||
# twine / pypi
|
||||
.pypirc
|
||||
|
18
LICENSE
@@ -1,7 +1,19 @@
|
||||
Copyright 2020 Reverend, Commander1024
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
|
5
MANIFEST.in
Normal file
@@ -0,0 +1,5 @@
|
||||
include LICENSE
|
||||
include Readme.rst
|
||||
include Pipfile
|
||||
recursive-include lostplaces/static *
|
||||
recursive-include lostplaces/templates *
|
14
Pipfile
@@ -6,6 +6,12 @@ verify_ssl = true
|
||||
[dev-packages]
|
||||
pylint = "*"
|
||||
coverage = "*"
|
||||
autopep8 = "*"
|
||||
pipenv = "*"
|
||||
wheel = "*"
|
||||
twine = "*"
|
||||
pandoc = "*"
|
||||
pylint-django = "*"
|
||||
|
||||
[packages]
|
||||
django = "*"
|
||||
@@ -14,6 +20,8 @@ image = "*"
|
||||
django-widget-tweaks = "*"
|
||||
django-taggit = "*"
|
||||
|
||||
# Commented out to not explicitly specify Python 3 subversion.
|
||||
# [requires]
|
||||
# python_version = "3.8"
|
||||
[scripts]
|
||||
test = "django_lostplaces/manage.py test lostplaces"
|
||||
server = "django_lostplaces/manage.py runserver --ipv6"
|
||||
dbshell = "django_lostplaces/manage.py dbshell"
|
||||
showmigrations = "django_lostplaces/manage.py showmigrations"
|
||||
|
154
Readme.md
@@ -2,105 +2,145 @@
|
||||
|
||||
lostplaces-backend is a django (3.x) based webproject. It once wants to become a software which allows a group of urban explorers to manage, document and share the locations of lost places while not exposing too much / any information to the public.
|
||||
|
||||
The software is currently in early development status, neither scope, datalmodel(s) nor features are finalized yet. Therefore we would not recommend to download or install this piece of software anywhere - except your local django dev server.
|
||||
The software is currently in early development status, neither scope, datamodel(s) nor features are finalized yet. Therefore we would not recommend to download or install this piece of software anywhere - except your local django dev server.
|
||||
|
||||
We value privacy as a whole, all resources the frontend requires will be shipped with lostplace's distribution. We also try to minimize the use of JavaScript as far as we can and try to offer JS-less alternatives where we can.
|
||||
|
||||
## Features
|
||||
- Manage lost places with lots of useful information.
|
||||
- OSM-Maps
|
||||
- Sensitive information is not accessible for anonymous (not logged in) users.
|
||||
- User self registration using a voucher system, only people you invite can join your instance.
|
||||
- Collaboration, every user can add informations like tags, photos and external links to your place.
|
||||
|
||||
## Dependencies
|
||||
Right now it depends on the following non-core Python 3 libraries. These can be installed using the package manager of your distribution or into the venv locally.
|
||||
|
||||
* [django](https://www.djangoproject.com/) django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
|
||||
* [easy-thumbnails](https://github.com/SmileyChris/easy-thumbnails) A powerful, yet easy to implement thumbnailing application for Django 1.11+
|
||||
* [image](https://github.com/francescortiz/image) Image cropping for django
|
||||
* [django](https://www.djangoproject.com/) is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
|
||||
* [easy-thumbnails](https://github.com/SmileyChris/easy-thumbnails) A powerful, yet easy to implement thumbnailing application for Django 1.11+.
|
||||
* [image](https://github.com/francescortiz/image) Image cropping for django.
|
||||
* [django-widget-tweaks](https://github.com/jazzband/django-widget-tweaks) Tweak the form field rendering in templates, not in python-level form definitions.
|
||||
* [django-taggit](https://github.com/jazzband/django-taggit) A simpler approach to tagging with Django.
|
||||
|
||||
### Bundled Dependencies
|
||||
We also leverage some other great OpenSource projects' code. We bundle those in the distribution to obsolete the need to pull those files from monitored CDNs.
|
||||
|
||||
* [OpenLayers](https://openlayers.org/) [6.4.3] OpenLayers makes it easy to put a dynamic map in any web page. It can display map tiles, vector data and markers loaded from any source.
|
||||
* [Crimson Pro font](https://github.com/Fonthausen/CrimsonPro) [1.002] Crimson Pro is a serif typeface family: Contemporary, clear, classic and rounded/open.
|
||||
* [Montserrat](https://github.com/JulietaUla/Montserrat) [7.210] A beautiful sans serif typeface.
|
||||
|
||||
|
||||
## Development
|
||||
### Setting up a (pipenv) virtual environment for development
|
||||
# Installing a development instance
|
||||
## Clone the repository
|
||||
`git clone https://git.mowoe.com/reverend/lostplaces-backend.git`
|
||||
## Setting up a (pipenv) virtual environment for development
|
||||
|
||||
After having obtained the repository contents (either via .zip download or git clone), you can easily setup a [pipenv](https://docs.pipenv.org/) virtual environment. The repo provides a Pipfile for easy dependency management that does not mess with your system.
|
||||
|
||||
```
|
||||
```shell
|
||||
$ cd lostplaces-backend
|
||||
$ pipenv install
|
||||
$ pipenv shell
|
||||
(lostplaces-backend) $ lostplaces/manage.py makemigrations
|
||||
(lostplaces-backend) $ lostplaces/manage.py migrate
|
||||
(lostplaces-backend) $ lostplaces/manage.py createsuperuser
|
||||
(lostplaces-backend) $ lostplaces/manage.py runserver --ipv6
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py makemigrations
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py migrate
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py createsuperuser
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py runserver --ipv6
|
||||
```
|
||||
|
||||
### Returning to the venv
|
||||
```
|
||||
## Returning to the venv
|
||||
```shell
|
||||
$ cd lostplaces-backend
|
||||
$ pipenv shell
|
||||
(lostplaces-backend) $ pipenv update # If dependencies changed, or updates available
|
||||
(lostplaces-backend) $ lostplaces/manage.py makemigrations # If datamodels changed
|
||||
(lostplaces-backend) $ lostplaces/manage.py migrate # If datamodels changed
|
||||
(lostplaces-backend) $ lostplaces/manage.py runserver --ipv6
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py makemigrations # If datamodels changed
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py migrate # If datamodels changed
|
||||
(lostplaces-backend) $ django_lostplaces/manage.py runserver --ipv6
|
||||
```
|
||||
|
||||
Visit: [admin](http://localhost:8000/admin) for administrative backend or
|
||||
[frontend](http://localhost:8000/)
|
||||
[frontend](http://localhost:8000/).
|
||||
|
||||
## Installing lostplaces
|
||||
Happy developing ;-)
|
||||
|
||||
### Install dependencies
|
||||
Python3, Django3, easy-thumbnails, image, django-widget-tweaks, django-taggit
|
||||
```
|
||||
pip install --user django easy-thumbnails image django-widget-tweaks django-taggit
|
||||
```
|
||||
Or, if you use pipenv
|
||||
```
|
||||
pipenv install / update
|
||||
```
|
||||
# Installing a productive instance
|
||||
|
||||
### Add 'lostplaces_app' to your INSTALLED_APPS setting like this
|
||||
Currently there are two ways to deploy the lostplaces project:
|
||||
1. Cloning this repository, including the configured django instance.
|
||||
2. Install the package and setup the django instance yourself.
|
||||
|
||||
```
|
||||
## Cloning the repository
|
||||
|
||||
Essentially, this is the same as installing a development instance, but without the development server (manage.py runserver) and something powerful (Apache, NGINX) instead. You have to configure the webserver to work with the *SGI Api respectively, reference [django's guide for deployment](https://docs.djangoproject.com/en/3.1/howto/deployment/) for further information.
|
||||
|
||||
You also should setup a dedicated database server, the built-in SQLite file is not recommended for production use. Reference [django's guide for databases](https://docs.djangoproject.com/en/3.1/ref/databases/) for further information.
|
||||
|
||||
Before making the django instance public, you should tweak the config `settings.py`:
|
||||
1. Change the secret key, the one found in the config is already public. Choose something secure (i.e. [this](https://duckduckgo.com/?q=password+generator+64)).
|
||||
2. Turn off debug mode by setting `DEBUG = False`.
|
||||
3. Tune the localization settings, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/i18n/).
|
||||
|
||||
Run `django_lostplaces/managy.py collectstatic` and you should be ready to go.
|
||||
|
||||
|
||||
## Installing lostplaces to an existing django instance
|
||||
|
||||
### Installing django and the django_lostplaces app
|
||||
|
||||
If you haven't already setup a django instance, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/install/).
|
||||
|
||||
After that, download the desired release (probably the latest one) [from the releases page](https://git.mowoe.com/reverend/lostplaces-backend/releases) and install it using `pip install --user name-of-the-file.tar.gz`
|
||||
|
||||
*Note: You can run pip install without the --user flag, which will require root privileges and introduces potential security issues.*
|
||||
|
||||
### Configuring the django instance
|
||||
|
||||
Now configure your `settings.py` as follows:
|
||||
1. Add the following apps to the django project.
|
||||
|
||||
```python
|
||||
INSTALLED_APPS = [
|
||||
...
|
||||
'lostplaces_app',
|
||||
'django_lostplaces',
|
||||
'easy_thumbnails',
|
||||
'widget_tweaks',
|
||||
'django_taggit'
|
||||
]
|
||||
```
|
||||
|
||||
### Add this configuration to your settings.py
|
||||
2. Set the URL's and Root-directories for file handling, for example:
|
||||
|
||||
```python
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')
|
||||
|
||||
MEDIA_URL = '/uploads/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
|
||||
```
|
||||
from django.urls import reverse_lazy
|
||||
...
|
||||
AUTH_USER_MODEL = 'lostplaces_app.Explorer'
|
||||
|
||||
3. Set the URL's for login, for example:
|
||||
|
||||
```python
|
||||
LOGIN_URL = reverse_lazy('login')
|
||||
|
||||
THUMBNAIL_ALIASES = {
|
||||
'': {
|
||||
'thumbnail': {'size': (300, 300), 'crop': False},
|
||||
'hero': {'size': (700, 700), 'crop': False},
|
||||
'large': {'size': (1920, 1920), 'crop': False},
|
||||
},
|
||||
}
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('django_lostplaces_home')
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy('django_lostplaces_home')
|
||||
```
|
||||
|
||||
|
||||
### Include the lostplaces URLconf in your project urls.py like this
|
||||
|
||||
```
|
||||
from django.urls import path, include
|
||||
...
|
||||
### Configuring the URL's
|
||||
In the `urls.py` configure the `urlpatterns` like this:
|
||||
```python
|
||||
urlpatterns = [
|
||||
...
|
||||
path('lostplaces/', include('lostplaces_app.urls')),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
||||
path('admin/', admin.site.urls),
|
||||
path('signup/', SignUpView.as_view(), name='signup'), # If you want to use lostplaces' sign up view.
|
||||
path('explorers/', include('django.contrib.auth.urls')), # You can change the 'explorers/' to whatever you desire.
|
||||
path('', include('django_lostplaces.urls')), # In this configuration django_lostplaces will be at the top level of you website, change '' to 'django_lostplaces/', if you don't want this.
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) # So django can deliver user uploaded files.
|
||||
```
|
||||
|
||||
Run ``./manage.py migrate`` to create the lost places models.
|
||||
|
||||
Start the development server and visit http://localhost:8000/admin/
|
||||
|
||||
Visit http://localhost:8000/lostplaces/ to CRUD lost places.
|
||||
Before making the django instance public, you should tweak the config `settings.py`:
|
||||
1. Change the secret key, the one found in the config is already public. Choose something secure (i.e. [this](https://duckduckgo.com/?q=password+generator+64)).
|
||||
2. Turn off debug mode by setting `DEBUG = False`.
|
||||
3. Tune the localization settings, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/i18n/).
|
||||
4. Set a new (random) SECRET_KEY in settings.py, e. g.: `base64 /dev/urandom | head -c50`
|
||||
|
||||
|
||||
Happy developing ;-)
|
||||
Run `django_lostplaces/manage.py collectstatic` you should be ready to go.
|
||||
|
@@ -14,6 +14,6 @@ import os
|
||||
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lostplaces.settings')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_lostplaces.settings')
|
||||
|
||||
application = get_asgi_application()
|
@@ -4,24 +4,29 @@
|
||||
"""
|
||||
Django settings for lostplaces project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.0.8.
|
||||
!!! Instead of changing this file, you can override settings in !!!
|
||||
!!! local_settings.py. That way it won't cause merge conflicts on pull. !!!
|
||||
|
||||
Generated by 'django-admin startproject' using Django 3.1.8.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/3.0/topics/settings/
|
||||
https://docs.djangoproject.com/en/3.1/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/3.0/ref/settings/
|
||||
https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
import os
|
||||
from django.urls import reverse_lazy
|
||||
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/
|
||||
# See https://docs.djangoproject.com/en/3.1/howto/deployment/checklist/
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = 'n$(bx8(^)*wz1ygn@-ekt7rl^1km*!_c+fwwjiua8m@-x_rpl0'
|
||||
@@ -29,22 +34,22 @@ SECRET_KEY = 'n$(bx8(^)*wz1ygn@-ekt7rl^1km*!_c+fwwjiua8m@-x_rpl0'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = [ 'localhost' ]
|
||||
ALLOWED_HOSTS = ['localhost']
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'lostplaces_app',
|
||||
'lostplaces',
|
||||
'easy_thumbnails',
|
||||
'widget_tweaks',
|
||||
'taggit',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'easy_thumbnails',
|
||||
'widget_tweaks',
|
||||
'taggit'
|
||||
'django.contrib.staticfiles'
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
@@ -55,14 +60,15 @@ MIDDLEWARE = [
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
]
|
||||
|
||||
ROOT_URLCONF = 'lostplaces.urls'
|
||||
ROOT_URLCONF = 'django_lostplaces.urls'
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [os.path.join(BASE_DIR, 'templates')],
|
||||
'DIRS': [],
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
'context_processors': [
|
||||
@@ -75,11 +81,11 @@ TEMPLATES = [
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'lostplaces.wsgi.application'
|
||||
WSGI_APPLICATION = 'django_lostplaces.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#databases
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
@@ -90,7 +96,7 @@ DATABASES = {
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/3.0/ref/settings/#auth-password-validators
|
||||
# https://docs.djangoproject.com/en/3.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
@@ -109,7 +115,7 @@ AUTH_PASSWORD_VALIDATORS = [
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/3.0/topics/i18n/
|
||||
# https://docs.djangoproject.com/en/3.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en-us'
|
||||
|
||||
@@ -121,33 +127,36 @@ USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
|
||||
# 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")
|
||||
LANGUAGES = [
|
||||
('de', _('German')),
|
||||
('en', _('English')),
|
||||
]
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')
|
||||
|
||||
# Upload directory
|
||||
MEDIA_URL = '/uploads/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
|
||||
|
||||
# Use custom user model
|
||||
AUTH_USER_MODEL = 'lostplaces_app.Explorer'
|
||||
# Thumbnails
|
||||
THUMBNAIL_MEDIA_ROOT = os.path.join(MEDIA_ROOT, 'thumbs/')
|
||||
THUMBNAIL_MEDIA_URL = os.path.join(MEDIA_URL, 'thumbs/')
|
||||
THUMBNAIL_QUALITY = 75
|
||||
|
||||
# Templates to use for authentication
|
||||
LOGIN_REDIRECT_URL = 'home'
|
||||
LOGOUT_REDIRECT_URL = 'home'
|
||||
|
||||
LOGIN_URL = reverse_lazy('login')
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('lostplaces_home')
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy('lostplaces_home')
|
||||
|
||||
THUMBNAIL_ALIASES = {
|
||||
'': {
|
||||
'thumbnail': {'size': (300, 300), 'crop': False},
|
||||
'hero': {'size': (700, 700), 'crop': False},
|
||||
'large': {'size': (1920, 1920), 'crop': False},
|
||||
},
|
||||
}
|
||||
|
||||
SVG_ICONS_SOURCE_FILE = os.path.join(BASE_DIR, 'lostplaces_app', 'static', 'icons', 'icons.icomoon.json')
|
||||
# Load and override settings from local_settings.py and don't fail on errors.
|
||||
|
||||
try:
|
||||
from .local_settings import *
|
||||
except ImportError:
|
||||
pass
|
@@ -23,8 +23,11 @@ from django.conf.urls.static import static
|
||||
from django.urls import path, include
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
from lostplaces.views import SignUpView
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('signup/', SignUpView.as_view(), name='signup'),
|
||||
path('explorers/', include('django.contrib.auth.urls')),
|
||||
path('', include('lostplaces_app.urls')),
|
||||
path('', include('lostplaces.urls')),
|
||||
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
|
@@ -14,6 +14,6 @@ import os
|
||||
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lostplaces.settings')
|
||||
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_lostplaces.settings')
|
||||
|
||||
application = get_wsgi_application()
|
155
django_lostplaces/docs/developer.md
Normal file
@@ -0,0 +1,155 @@
|
||||
# django lostplaces documentation for developer
|
||||
|
||||
Greetings,
|
||||
this documentation is for anyone who wants to work with this projects codebase or is just curious about how it works.
|
||||
|
||||
|
||||
## Models
|
||||
The models contain an custom user profile, some abstract base models and the models holding the actual data for this project
|
||||
|
||||
|
||||
### Explorer user profile
|
||||
Location: `lostplaces.models.models.Explorer`
|
||||
Import from: `lostplaces.models.Explorer`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
|
||||
The class `lostplaces.models.Explorer` is our custom user profile. It has an ForeignKey pointing at django's default user model instead of providing an entire custom user model. That way this django app does not conflict with any other app that brings it's own user model.
|
||||
|
||||
You can access the explorer profile by accessing the 'explorer' attribute of any user instance
|
||||
```python
|
||||
user.explorer
|
||||
```
|
||||
|
||||
Currently the explorer profile is used by the abstract model 'Submittable' and has the following realated names/fiels:
|
||||
- [places](###place) A list containing all (lost) places the user has submitted
|
||||
- [placeimages](###placeimages) A list containing all images relating a place that a user has submitted
|
||||
- [photoalbums](###photoalbums) A list of all photo albums a explorere has submitted
|
||||
|
||||
|
||||
### Taggable
|
||||
Location: `lostplaces.models.abstract_models.Taggable`
|
||||
Import from: `lostplaces.models.Taggable`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
|
||||
The abstract model Taggable represents an model that is taggable. It depends on the django app [taggit](https://github.com/jazzband/django-taggit). It only consists of one field:
|
||||
- `tag`: TaggableManager, allows the sub class to be tagged, blank=True allows the admin form to be submitted without any tags
|
||||
|
||||
|
||||
### Mapable
|
||||
Location: `lostplaces.models.abstract_models.Mapable`
|
||||
Import from: `lostplaces.models.Mapable`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
|
||||
The abstract model Mapable represents an model that can be displayed on a map. It consists of tree attributes
|
||||
`name`
|
||||
Name of the object, displayed on the map, max length 50 characters
|
||||
`latitude`
|
||||
Latitude of the referenced location, -90 <= value <= 90
|
||||
`longitude`
|
||||
Longitude of the referenced location -180 <= value <= 180
|
||||
A mapable model has to provide its own get_absolute_url, in order to provide a link when clicked.
|
||||
|
||||
|
||||
### Submittable
|
||||
Location: `lostplaces.models.abstract_models.Submittable`
|
||||
Import from: `lostplaces.models.Submittable`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
|
||||
The abstract model Submittable represents an model that can be submitted by an user. It knows who submitted something and when:
|
||||
`submitted_by`
|
||||
Referencing the explorer profile, see [Explorer](##explorer-user-profile). If the explorer profile is deleted, this instance is kept (on_delete=models.SET_NULL). The related_name is set to the class name, lower case appending an s (%(class)ss)
|
||||
`submitted_when`
|
||||
When the object was submitted, automatically set by django (auto_now_add=True)
|
||||
|
||||
### Expireable
|
||||
Location: `lostplaces.models.abstract_models.Expireable`
|
||||
Import from: `lostplaces.models.Expireable`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
|
||||
This abstract model represents an object that can expire. It is currently used by the Voucher model. I consists of two fields:
|
||||
`created_when`
|
||||
The date the object was created, automatically set by django (auto_now_add=True)
|
||||
`expires_when`
|
||||
The date the object expires.
|
||||
|
||||
### Voucher
|
||||
Locatoin: `lostplaces.models.Voucher`
|
||||
Import from: `lostplaces.models.Voucher`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
- [lostplaces.models.Expireable](###expireable)
|
||||
|
||||
A voucher code is needed to sign up using lostplaces sign up form. The model contains
|
||||
`code`
|
||||
The voucher code, max length 30 characters
|
||||
`created_when`
|
||||
When the voucher was created automatically set by django (auto_now_add=True)
|
||||
`expires_when`
|
||||
Till what date the voucher remains valid
|
||||
|
||||
|
||||
### Place
|
||||
Location: `lostplaces.models.place.Place`
|
||||
Import from: `lostplaces.models.Place`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
- [lostplaces.models.Submittable](###submittable)-
|
||||
- [lostplaces.models.Taggable](###taggable)
|
||||
- [lostlaces.models.Mapable]
|
||||
|
||||
The place model is the heart of this project. It stores all information about a place needed.
|
||||
`location`
|
||||
Human readable location description (town, village, street), max length 50 characters
|
||||
`description`
|
||||
Describing the place in detail
|
||||
The place model uses these abstract super classes
|
||||
- Submittable, see [Submittable](##submittable) for additional fields
|
||||
- Taggable, see [Taggable](##taggable) for additional fields
|
||||
- Mapable, see [Mapable](##mapable) for additional fields
|
||||
The average_latlon function takes a list of places and returns the center point of all these places.
|
||||
|
||||
### PlaceAsset
|
||||
Location: `lostplaces.models.PlaceAsset`
|
||||
Import from: `lostplaces.models.place.PlaceAsset`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
- [lostplaces.models.Submittable](###submittable)
|
||||
|
||||
A PlaceAsset is anything that belongs to a place. The PlaceImage model for exmpaple is a subclass of PlaceAsset. A PlaceAsset is supposed to be submittable by every user. Only the user who has submitted the asset, the place the asset belongs to or both can delete a asset.
|
||||
|
||||
An PlaceAsset has the following fields
|
||||
`place`
|
||||
The Place this PlaceAsset belongs to
|
||||
|
||||
The PlaceAsset model is a subclass of Submittable, see [Submittable](###submittable) for more details.
|
||||
|
||||
### External Link
|
||||
Loacation: `lostplaces.models.external_link.ExternalLink`
|
||||
Import From: `lostplaces.models.ExternalLink`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
- [lostplaces.models.Submittable](###submittable)
|
||||
- [lostplaces.models.PlaceAsset](###placeasset)
|
||||
|
||||
This model represents an URL to an external website. External Link is an PlaceAsset, see [above](###placeasset) for more details. External Link has to fields
|
||||
`url`
|
||||
the URL to the target
|
||||
`label`
|
||||
the label that is shown on the website
|
||||
|
||||
### PhotoAlbum
|
||||
Loacation: `lostplaces.models.external_link.PhototAlbum`
|
||||
Import From: `lostplaces.models.PhotoAlbum`
|
||||
#### Super Classes
|
||||
- django's `models.Model`
|
||||
- [lostplaces.models.Submittable](###submittable)
|
||||
- [lostplaces.models.PlaceAsset](###placeasset)
|
||||
- [lostplaces.models.ExternalLink](###externallink)
|
||||
|
||||
A photo album is a link to an external site that is meant to contain photos of the place it is referenced in. It
|
||||
does not have any fields, just the ones inherited from it's super class [ExternalLink](###externallink).
|
12
django_lostplaces/lostplaces/__init__.py
Normal file
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
settings.THUMBNAIL_ALIASES = {
|
||||
'': {
|
||||
'thumbnail': {'size': (300, 200), 'sharpen': True, 'crop': True},
|
||||
'hero': {'size': (700, 466), 'sharpen': True, 'crop': True},
|
||||
'large': {'size': (1920, 1920), 'sharpen': True, 'crop': False},
|
||||
},
|
||||
}
|
39
django_lostplaces/lostplaces/admin.py
Normal file
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
''' Classes and modules for the administrative backend. '''
|
||||
|
||||
from django.contrib import admin
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.utils import timezone
|
||||
from lostplaces.models import *
|
||||
|
||||
from lostplaces.forms import ExplorerCreationForm, ExplorerChangeForm
|
||||
|
||||
# Register your models here.
|
||||
|
||||
class VoucherAdmin(admin.ModelAdmin):
|
||||
fields = ['code', 'expires_when', 'created_when']
|
||||
readonly_fields = ['created_when']
|
||||
list_display = ('__str__', 'code', 'created_when', 'expires_when', 'valid')
|
||||
|
||||
def valid(self, instance):
|
||||
return timezone.now() <= instance.expires_when
|
||||
|
||||
valid.boolean = True
|
||||
|
||||
class PhotoAlbumsAdmin(admin.ModelAdmin):
|
||||
list_display = ('label', 'place', 'url' )
|
||||
|
||||
class PlacesAdmin(admin.ModelAdmin):
|
||||
list_display = ('name', 'submitted_by', 'submitted_when')
|
||||
|
||||
class PlaceImagesAdmin(admin.ModelAdmin):
|
||||
list_display = ('__str__', 'place', 'submitted_by')
|
||||
|
||||
admin.site.register(Explorer)
|
||||
admin.site.register(Voucher, VoucherAdmin)
|
||||
admin.site.register(Place, PlacesAdmin)
|
||||
admin.site.register(PlaceImage, PlaceImagesAdmin)
|
||||
admin.site.register(PhotoAlbum, PhotoAlbumsAdmin)
|
@@ -1,4 +1,7 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
class LostplacesAppConfig(AppConfig):
|
||||
name = 'lostplaces_app'
|
||||
name = 'lostplaces'
|
@@ -4,22 +4,32 @@
|
||||
''' (web)forms that can be used elsewhere. '''
|
||||
|
||||
from django import forms
|
||||
from django.db import models
|
||||
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
|
||||
from .models import Explorer, Place, PlaceImage, Voucher
|
||||
from django.contrib.auth.models import User
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from lostplaces.models import Place, PlaceImage, Voucher
|
||||
|
||||
class ExplorerCreationForm(UserCreationForm):
|
||||
class Meta:
|
||||
model = Explorer
|
||||
model = User
|
||||
fields = ('username', 'email')
|
||||
voucher = forms.CharField(max_length=10, help_text='The Voucher you got from an administrator')
|
||||
voucher = forms.CharField(
|
||||
max_length=30,
|
||||
help_text=_('The Voucher you got from an administrator')
|
||||
)
|
||||
|
||||
def is_valid(self):
|
||||
super().is_valid()
|
||||
sumitted_voucher = self.cleaned_data.get('voucher')
|
||||
submitted_voucher = self.cleaned_data.get('voucher')
|
||||
try:
|
||||
fetched_voucher = Voucher.objects.get(code=sumitted_voucher)
|
||||
fetched_voucher = Voucher.objects.get(code=submitted_voucher)
|
||||
except Voucher.DoesNotExist:
|
||||
self.add_error('voucher', 'Invalid voucher')
|
||||
self.add_error('voucher', _('Invalid voucher'))
|
||||
return False
|
||||
|
||||
if not fetched_voucher.valid:
|
||||
self.add_error('voucher', _('Expired voucher'))
|
||||
return False
|
||||
|
||||
fetched_voucher.delete()
|
||||
@@ -27,7 +37,7 @@ class ExplorerCreationForm(UserCreationForm):
|
||||
|
||||
class ExplorerChangeForm(UserChangeForm):
|
||||
class Meta:
|
||||
model = Explorer
|
||||
model = User
|
||||
fields = ('username', 'email')
|
||||
|
||||
class PlaceForm(forms.ModelForm):
|
||||
@@ -36,7 +46,7 @@ class PlaceForm(forms.ModelForm):
|
||||
fields = '__all__'
|
||||
exclude = ['submitted_by']
|
||||
|
||||
class PlaceImageCreateForm(forms.ModelForm):
|
||||
class PlaceImageForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = PlaceImage
|
||||
fields = ['filename']
|
||||
@@ -49,10 +59,9 @@ class PlaceImageCreateForm(forms.ModelForm):
|
||||
|
||||
self.fields['filename'].required = False
|
||||
|
||||
|
||||
class TagSubmitForm(forms.Form):
|
||||
tag_list = forms.CharField(
|
||||
max_length=500,
|
||||
required=False,
|
||||
widget=forms.TextInput(attrs={'autocomplete':'off'})
|
||||
)
|
||||
)
|
377
django_lostplaces/lostplaces/locale/de/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,377 @@
|
||||
# SOME DESCRIPTIVE TITLE.
|
||||
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
|
||||
# This file is distributed under the same license as the PACKAGE package.
|
||||
# Reverend <reverend@reverend2048.de>, 2020.
|
||||
#
|
||||
#, fuzzy
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PACKAGE VERSION\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2020-10-11 07:48+0200\n"
|
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||
"Last-Translator: Commander1024 <commander@commander1024.de>\n"
|
||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||
"Language: de-DE\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
|
||||
#: forms.py:19
|
||||
msgid "The Voucher you got from an administrator"
|
||||
msgstr "Der Einladungs-Code, den Dir ein Administrator gegeben hat"
|
||||
|
||||
#: forms.py:28
|
||||
msgid "Invalid voucher"
|
||||
msgstr "Ungültiger Voucher"
|
||||
|
||||
#: forms.py:32
|
||||
msgid "Expired voucher"
|
||||
msgstr "Abgelaufener Voucher"
|
||||
|
||||
#: models/abstract_models.py:29
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
#: models/abstract_models.py:36
|
||||
msgid "Latitude"
|
||||
msgstr "Breitengrad"
|
||||
|
||||
#: models/abstract_models.py:37
|
||||
msgid "Latitude in decimal format: e. g. 41.40338"
|
||||
msgstr "Breitengrad in dezimaler Form: z. B. 51.95021"
|
||||
|
||||
#: models/abstract_models.py:44
|
||||
msgid "Longitude"
|
||||
msgstr "Längengrad"
|
||||
|
||||
#: models/abstract_models.py:45
|
||||
msgid "Longitude in decimal format: e. g. 2.17403"
|
||||
msgstr "Breitengrad in dezimaler Form: z. B. 7.4840155"
|
||||
|
||||
#: models/external_links.py:13
|
||||
msgid "URL"
|
||||
msgstr "Adresse (URL)"
|
||||
|
||||
#: models/external_links.py:17
|
||||
msgid "link text"
|
||||
msgstr "Linktext"
|
||||
|
||||
#: models/place.py:21
|
||||
msgid "Location"
|
||||
msgstr "Ort"
|
||||
|
||||
#: models/place.py:24
|
||||
msgid ""
|
||||
"Description of the place: e.g. how to get there, where to be careful, the "
|
||||
"place's history..."
|
||||
msgstr ""
|
||||
"Beschreibung des Places: z. B. wie man hin kommt, wo man vorsichtig sein "
|
||||
"sollte, seine Geschichte..."
|
||||
|
||||
#: models/place.py:25 models/place.py:84
|
||||
msgid "Description"
|
||||
msgstr "Beschreibung"
|
||||
|
||||
#: models/place.py:90
|
||||
msgid "Filename(s)"
|
||||
msgstr "Dateiname(n)"
|
||||
|
||||
#: models/place.py:91
|
||||
msgid "Optional: One or more images to upload"
|
||||
msgstr "Optional: Ein oder mehrere Bilder zum Hochladen"
|
||||
|
||||
#: templates/403.html:4
|
||||
msgid "Forbidden"
|
||||
msgstr "Nicht Erlaubt"
|
||||
|
||||
#: templates/403.html:14
|
||||
msgid "You will be redirected in 5 seconds"
|
||||
msgstr "Du wirst in 5 Sekunden weitergeleitet"
|
||||
|
||||
#: templates/403.html:14
|
||||
msgid "Go Back"
|
||||
msgstr "Zurück"
|
||||
|
||||
#: templates/global.html:32
|
||||
msgid "Logout"
|
||||
msgstr "Abmelden"
|
||||
|
||||
#: templates/global.html:34
|
||||
msgid "Admin"
|
||||
msgstr "Admin"
|
||||
|
||||
#: templates/global.html:39 templates/registration/login.html:4
|
||||
#: templates/registration/login.html:10 templates/registration/login.html:23
|
||||
msgid "Login"
|
||||
msgstr "Anmelden"
|
||||
|
||||
#: templates/global.html:40 templates/registration/login.html:29
|
||||
#: templates/signup.html:12 templates/signup.html:41
|
||||
msgid "Sign Up"
|
||||
msgstr "Registrieren"
|
||||
|
||||
#: templates/global.html:50 templates/home.html:10
|
||||
msgid "Home"
|
||||
msgstr "Startseite"
|
||||
|
||||
#: templates/global.html:51
|
||||
msgid "UrBex Codex"
|
||||
msgstr "UrBex Codex"
|
||||
|
||||
#: templates/global.html:56 templates/place/place_create.html:5
|
||||
#: templates/place/place_create.html:10
|
||||
msgid "Create Place"
|
||||
msgstr "Place erstellen"
|
||||
|
||||
#: templates/global.html:57
|
||||
msgid "All Places"
|
||||
msgstr "Alle Places"
|
||||
|
||||
#: templates/home.html:20 templates/home_unauth.html:20
|
||||
msgid "Explore the latest places"
|
||||
msgstr "Neueste Places erkunden"
|
||||
|
||||
#: templates/home_unauth.html:11
|
||||
msgid ""
|
||||
"You can create, view and share your lost places with other members of this "
|
||||
"site. You can upload photos, place links to your web galleries and "
|
||||
"contribute your knowledge by tagging other places or commenting on them. You "
|
||||
"will find detailed information on where these locations are, how to get "
|
||||
"there and what to expect from them. This might even include detailed "
|
||||
"information on the surroundings or the history of a lost place."
|
||||
msgstr ""
|
||||
"Du kannst Deine Lost Places erstellen, ansehen und mit anderen Mitgliedern "
|
||||
"auf dieser Seite teilen. Du kannst Photos hochladen, Links zu Deinen Web-"
|
||||
"Fotoalben setzen und Dein Wissen teilen indem Du andere Places mit Tags "
|
||||
"versiehst oder sie kommentierst. Du wirst detaillierte Informationen dazu "
|
||||
"finden, wo diese Orte sind, wie Du dorthin gelangst und was Dich dort "
|
||||
"erwartet. Dies können sogar detaillierte Informationen zur Umgebung oder der "
|
||||
"Geschichte eines Lost Places sein."
|
||||
|
||||
#: templates/home_unauth.html:15
|
||||
#, python-format
|
||||
msgid ""
|
||||
"Since vandalism is a growing problem these days, no sensitive information is "
|
||||
"available to the public. You have to <a class=\"LP-Link\" href="
|
||||
"\"%(signup_url)s\"><span class=\"LP-Link__Text\">sign up</span></a> with a "
|
||||
"voucher code as an invitation to join this community. Only admins can create "
|
||||
"these codes. Usually you are given a code when we know you in real life in "
|
||||
"person and when we trust you. A request from an unknown person will most "
|
||||
"probably be denied."
|
||||
msgstr ""
|
||||
"Weil Vandalismus dieser Tage ein wachsendes Problem ist, sind keine "
|
||||
"sensiblen Informationen öffentlich verfügbar. Du musst Dich mit einem "
|
||||
"Voucher-Code als Einladung <a class=\"LP-Link\" href=\"%(signup_url)s"
|
||||
"\"><span class=\"LP-Link__Text\">registrieren</span></a>um dieser Community "
|
||||
"beizutreten. Nur Administratoren können diese Codes erstellen. Üblicherweise "
|
||||
"bekommst Du einen Code, wenn wir Dich im echten Leben kennen und Dir "
|
||||
"vertrauen. Eine Anfrage von einer unbekannten Person wird "
|
||||
"höchstwahrscheinlich abgelehnt."
|
||||
|
||||
#: templates/partials/form/submit.html:3
|
||||
msgid "Submit"
|
||||
msgstr "Abschicken"
|
||||
|
||||
#: templates/partials/form/submit.html:7
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: templates/partials/nav/footer.html:64
|
||||
msgid "Made by"
|
||||
msgstr "Erstellt von"
|
||||
|
||||
#: templates/partials/nav/footer.html:65
|
||||
msgid "and"
|
||||
msgstr "und"
|
||||
|
||||
#: templates/partials/nav/footer.html:68
|
||||
msgid "Privacy Policy"
|
||||
msgstr "Datenschutzerklärung"
|
||||
|
||||
#: templates/partials/nav/footer.html:70
|
||||
msgid "Imprint"
|
||||
msgstr "Impressum"
|
||||
|
||||
#: templates/partials/nav/pagination.html:11
|
||||
#: templates/partials/nav/pagination.html:24
|
||||
msgid "First"
|
||||
msgstr "Erste"
|
||||
|
||||
#: templates/partials/nav/pagination.html:17
|
||||
#: templates/partials/nav/pagination.html:30
|
||||
msgid "Previous"
|
||||
msgstr "Vorherige"
|
||||
|
||||
#: templates/partials/nav/pagination.html:50
|
||||
#: templates/partials/nav/pagination.html:63
|
||||
msgid "Next"
|
||||
msgstr "Nächste"
|
||||
|
||||
#: templates/partials/nav/pagination.html:56
|
||||
#: templates/partials/nav/pagination.html:68
|
||||
msgid "Last"
|
||||
msgstr "Letzte"
|
||||
|
||||
#: templates/partials/tagging.html:30 templates/partials/tagging.html:34
|
||||
msgid "Add tags"
|
||||
msgstr "Tags hinzufügen"
|
||||
|
||||
#: templates/partials/welcome.html:4
|
||||
msgid "Start"
|
||||
msgstr "Start"
|
||||
|
||||
#: templates/partials/welcome.html:8
|
||||
msgid "Welcome to our Urban Exploration community catalogue,"
|
||||
msgstr "Willkommen auf unserem Urban Exploration Community-Katalog,"
|
||||
|
||||
#: templates/partials/welcome.html:12
|
||||
msgid "explorer"
|
||||
msgstr "Explorer"
|
||||
|
||||
#: templates/partials/welcome.html:17
|
||||
msgid "We strictly follow our"
|
||||
msgstr "Bitte lies unseren"
|
||||
|
||||
#: templates/partials/welcome.html:18
|
||||
msgid "UrBex codex"
|
||||
msgstr "UrBex Codex"
|
||||
|
||||
#: templates/partials/welcome.html:19
|
||||
msgid "and expect you to do so, too."
|
||||
msgstr "bevor du Places erkundest"
|
||||
|
||||
#: templates/photo_album/photo_album_create.html:4
|
||||
msgid "Submit a photo album"
|
||||
msgstr "Fotoalbum hinzufügen"
|
||||
|
||||
#: templates/photo_album/photo_album_create.html:8
|
||||
#: templates/place/place_detail.html:18
|
||||
msgid "Edit place"
|
||||
msgstr "Place bearbeiten"
|
||||
|
||||
#: templates/photo_album/photo_album_create.html:10
|
||||
#: templates/place/place_delete.html:11 templates/place/place_detail.html:19
|
||||
msgid "Delete place"
|
||||
msgstr "Place löschen"
|
||||
|
||||
#: templates/photo_album/photo_album_create.html:16
|
||||
msgid "Submit a photo album for"
|
||||
msgstr "Fotoalbum hinzufügen zu"
|
||||
|
||||
#: templates/place/place_create.html:42
|
||||
msgid "Create"
|
||||
msgstr "Erstellen"
|
||||
|
||||
#: templates/place/place_delete.html:5
|
||||
msgid "Lost Place Deletion"
|
||||
msgstr "Lost Place löschen"
|
||||
|
||||
#: templates/place/place_delete.html:15
|
||||
msgid "Are you sure you want to delete"
|
||||
msgstr "Willst Du den Ort wirklich löschen: "
|
||||
|
||||
#: templates/place/place_delete.html:19
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
#: templates/place/place_detail.html:46
|
||||
msgid "Map links"
|
||||
msgstr "Kartenlinks"
|
||||
|
||||
#: templates/place/place_detail.html:58
|
||||
msgid "Photo albums"
|
||||
msgstr "Fotoalben"
|
||||
|
||||
#: templates/place/place_detail.html:84
|
||||
msgid "Add photo album"
|
||||
msgstr "Fotoalbum hinzufügen"
|
||||
|
||||
#: templates/place/place_detail.html:93
|
||||
msgid "Images"
|
||||
msgstr "Bilder"
|
||||
|
||||
#: templates/place/place_list.html:10
|
||||
msgid "Lost Places"
|
||||
msgstr "Alle Places"
|
||||
|
||||
#: templates/place/place_list.html:16
|
||||
msgid "Listing our places"
|
||||
msgstr "Unsere Lost Places"
|
||||
|
||||
#: templates/place/place_update.html:5 templates/place/place_update.html:10
|
||||
msgid "Update place"
|
||||
msgstr "Place bearbeiten"
|
||||
|
||||
#: templates/place/place_update.html:42
|
||||
msgid "Update"
|
||||
msgstr "Aktualisieren"
|
||||
|
||||
#: templates/place_image/place_image_create.html:7
|
||||
msgid "Submit images to a place"
|
||||
msgstr "Bilder zu einem Place hinzufügen"
|
||||
|
||||
#: templates/registration/login.html:29
|
||||
msgid "Have No Account Yet?"
|
||||
msgstr "Noch kein Konto?"
|
||||
|
||||
#: templates/signup.html:6
|
||||
msgid "Sign up"
|
||||
msgstr "Registrieren"
|
||||
|
||||
#: views/base_views.py:25
|
||||
msgid "Please login to proceed"
|
||||
msgstr "Bitte log Dich ein um fortzufahren"
|
||||
|
||||
#: views/place_image_views.py:26
|
||||
msgid "Image(s) submitted successfully"
|
||||
msgstr "Bild(er) erfolgreich hinzugefügt"
|
||||
|
||||
#: views/place_image_views.py:41
|
||||
msgid "Image(s) deleted successfully"
|
||||
msgstr "Bild(er) erfolgreich gelöscht"
|
||||
|
||||
#: views/place_image_views.py:42
|
||||
msgid "You are not allowed to delete this image"
|
||||
msgstr "Du darfst dieses Bild nicht löschen"
|
||||
|
||||
#: views/place_views.py:62
|
||||
#, fuzzy
|
||||
#| msgid "Successfully deleted place"
|
||||
msgid "Successfully updated place"
|
||||
msgstr "Place erfolgreich gelöscht"
|
||||
|
||||
#: views/place_views.py:63
|
||||
msgid "You do no have permissions to alter this place"
|
||||
msgstr "Du hast nicht die Berechtigung, diesen Place zu bearbeiten"
|
||||
|
||||
#: views/place_views.py:97
|
||||
#, fuzzy
|
||||
#| msgid "Successfully deleted place"
|
||||
msgid "Successfully created place"
|
||||
msgstr "Place erfolgreich gelöscht"
|
||||
|
||||
#: views/place_views.py:112
|
||||
msgid "Successfully deleted place"
|
||||
msgstr "Place erfolgreich gelöscht"
|
||||
|
||||
#: views/place_views.py:114
|
||||
msgid "You do no have permission to delete this place"
|
||||
msgstr "Du hast nicht die Berechtigung, diesen Place zu löschen"
|
||||
|
||||
#: views/views.py:29
|
||||
msgid "User created"
|
||||
msgstr "User erstellt"
|
||||
|
||||
#: views/views.py:54
|
||||
msgid "Photo Album submitted"
|
||||
msgstr "Fotoalbum hinzugefügt"
|
||||
|
||||
#: views/views.py:59
|
||||
msgid "Photo Album deleted"
|
||||
msgstr "Fotoalbum gelöscht"
|
||||
|
||||
#: views/views.py:60
|
||||
msgid "You do not have permissions to alter this photo album"
|
||||
msgstr "Du hast nicht die Berechtigung, diesen Place zu bearbeiten"
|
90
django_lostplaces/lostplaces/migrations/0001_initial.py
Normal file
@@ -0,0 +1,90 @@
|
||||
# Generated by Django 3.1.1 on 2020-09-28 18:39
|
||||
|
||||
from django.conf import settings
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import easy_thumbnails.fields
|
||||
import lostplaces.models.place
|
||||
import taggit.managers
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('taggit', '0003_taggeditem_add_unique_index'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Expireable',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_when', models.DateTimeField(auto_now_add=True)),
|
||||
('expires_when', models.DateTimeField()),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Explorer',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='explorer', to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Place',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('name', models.CharField(max_length=50)),
|
||||
('latitude', models.FloatField(validators=[django.core.validators.MinValueValidator(-90), django.core.validators.MaxValueValidator(90)])),
|
||||
('longitude', models.FloatField(validators=[django.core.validators.MinValueValidator(-180), django.core.validators.MaxValueValidator(180)])),
|
||||
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('location', models.CharField(max_length=50)),
|
||||
('description', models.TextField()),
|
||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='places', to='lostplaces.explorer')),
|
||||
('tags', taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Voucher',
|
||||
fields=[
|
||||
('expireable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='lostplaces.expireable')),
|
||||
('code', models.CharField(max_length=30, unique=True)),
|
||||
],
|
||||
bases=('lostplaces.expireable',),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PlaceImage',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('description', models.TextField(blank=True)),
|
||||
('filename', easy_thumbnails.fields.ThumbnailerImageField(upload_to=lostplaces.models.place.generate_image_upload_path)),
|
||||
('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='placeimages', to='lostplaces.place')),
|
||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='PhotoAlbum',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
|
||||
('url', models.URLField()),
|
||||
('label', models.CharField(max_length=100)),
|
||||
('place', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='photoalbums', to='lostplaces.place')),
|
||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='photoalbums', to='lostplaces.explorer')),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
@@ -0,0 +1,22 @@
|
||||
# Generated by Django 3.1.1 on 2020-10-04 19:37
|
||||
# Edited by reverend
|
||||
|
||||
import datetime
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
from django.utils.timezone import utc
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lostplaces', '0001_initial'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='Voucher'
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Expireable'
|
||||
)
|
||||
]
|
25
django_lostplaces/lostplaces/migrations/0003_voucher.py
Normal file
@@ -0,0 +1,25 @@
|
||||
# Generated by Django 3.1.1 on 2020-10-04 19:52
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lostplaces', '0002_remove_vouchers'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Voucher',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created_when', models.DateTimeField(auto_now_add=True)),
|
||||
('expires_when', models.DateTimeField()),
|
||||
('code', models.CharField(max_length=30, unique=True)),
|
||||
],
|
||||
options={
|
||||
'abstract': False,
|
||||
},
|
||||
),
|
||||
]
|
4
django_lostplaces/lostplaces/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from lostplaces.models.abstract_models import *
|
||||
from lostplaces.models.place import *
|
||||
from lostplaces.models.external_links import *
|
||||
from lostplaces.models.models import *
|
77
django_lostplaces/lostplaces/models/abstract_models.py
Normal file
@@ -0,0 +1,77 @@
|
||||
|
||||
from django.utils import timezone
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
class Taggable(models.Model):
|
||||
'''
|
||||
This abstract model represtens an object that is taggable
|
||||
using django-taggit
|
||||
'''
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
tags = TaggableManager(blank=True)
|
||||
|
||||
class Mapable(models.Model):
|
||||
'''
|
||||
This abstract model class represents an object that can be
|
||||
displayed on a map.
|
||||
'''
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
name = models.CharField(
|
||||
max_length=50,
|
||||
verbose_name=_('Name'),
|
||||
)
|
||||
latitude = models.FloatField(
|
||||
validators=[
|
||||
MinValueValidator(-90),
|
||||
MaxValueValidator(90)
|
||||
],
|
||||
verbose_name=_('Latitude'),
|
||||
help_text=_('Latitude in decimal format: e. g. 41.40338')
|
||||
)
|
||||
longitude = models.FloatField(
|
||||
validators=[
|
||||
MinValueValidator(-180),
|
||||
MaxValueValidator(180)
|
||||
],
|
||||
verbose_name=_('Longitude'),
|
||||
help_text=_('Longitude in decimal format: e. g. 2.17403')
|
||||
)
|
||||
|
||||
class Submittable(models.Model):
|
||||
'''
|
||||
This abstract model class represents an object that can be submitted by
|
||||
an explorer.
|
||||
'''
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
submitted_when = models.DateTimeField(auto_now_add=True, null=True)
|
||||
submitted_by = models.ForeignKey(
|
||||
'Explorer',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='%(class)ss'
|
||||
)
|
||||
|
||||
class Expireable(models.Model):
|
||||
"""
|
||||
Base class for things that can expire, i.e. Vouchers
|
||||
"""
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
created_when = models.DateTimeField(auto_now_add=True)
|
||||
expires_when = models.DateTimeField()
|
||||
|
||||
@property
|
||||
def is_expired(self):
|
||||
return timezone.now() > self.expires_when
|
21
django_lostplaces/lostplaces/models/external_links.py
Normal file
@@ -0,0 +1,21 @@
|
||||
from django.db import models
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from lostplaces.models.place import PlaceAsset
|
||||
|
||||
class ExternalLink(PlaceAsset):
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
url = models.URLField(
|
||||
max_length=200,
|
||||
verbose_name=_('URL')
|
||||
)
|
||||
label = models.CharField(
|
||||
max_length=100,
|
||||
verbose_name=_('link text')
|
||||
)
|
||||
|
||||
class PhotoAlbum(ExternalLink):
|
||||
pass
|
59
django_lostplaces/lostplaces/models/models.py
Normal file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
'''
|
||||
(Data)models which describe the structure of data to be saved into
|
||||
database.
|
||||
'''
|
||||
|
||||
import uuid
|
||||
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from lostplaces.models.abstract_models import Expireable
|
||||
|
||||
class Explorer(models.Model):
|
||||
"""
|
||||
Profile that is linked to the a User.
|
||||
Every user has a profile.
|
||||
"""
|
||||
|
||||
user = models.OneToOneField(
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='explorer'
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
return self.user.username
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def create_user_profile(sender, instance, created, **kwargs):
|
||||
if created:
|
||||
Explorer.objects.create(user=instance)
|
||||
|
||||
@receiver(post_save, sender=User)
|
||||
def save_user_profile(sender, instance, **kwargs):
|
||||
instance.explorer.save()
|
||||
|
||||
class Voucher(Expireable):
|
||||
"""
|
||||
Vouchers are authorization to created_when = models.DateTimeField(auto_now_add=True)
|
||||
expires_when = models.DateTimeField()kens to allow the registration of new users.
|
||||
A voucher has a code, a creation and a deletion date, which are all
|
||||
positional. Creation date is being set automatically during voucher
|
||||
creation.
|
||||
"""
|
||||
|
||||
code = models.CharField(unique=True, max_length=30)
|
||||
|
||||
@property
|
||||
def valid(self):
|
||||
return not self.is_expired
|
||||
|
||||
def __str__(self):
|
||||
return "Voucher " + str(self.code)
|
||||
|
141
django_lostplaces/lostplaces/models/place.py
Normal file
@@ -0,0 +1,141 @@
|
||||
import os
|
||||
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.dispatch import receiver
|
||||
from django.db.models.signals import post_delete, pre_save
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from lostplaces.models.abstract_models import Submittable, Taggable, Mapable
|
||||
|
||||
from easy_thumbnails.fields import ThumbnailerImageField
|
||||
from easy_thumbnails.files import get_thumbnailer
|
||||
|
||||
class Place(Submittable, Taggable, Mapable):
|
||||
"""
|
||||
Place defines a lost place (location, name, description etc.).
|
||||
"""
|
||||
|
||||
location = models.CharField(
|
||||
max_length=50,
|
||||
verbose_name=_('Location'),
|
||||
)
|
||||
description = models.TextField(
|
||||
help_text=_('Description of the place: e.g. how to get there, where to be careful, the place\'s history...'),
|
||||
verbose_name=_('Description'),
|
||||
)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('place_detail', kwargs={'pk': self.pk})
|
||||
|
||||
|
||||
@classmethod
|
||||
# Get center position of LP-geocoordinates.
|
||||
def average_latlon(cls, place_list):
|
||||
amount = len(place_list)
|
||||
# Init fill values to prevent None
|
||||
longitude = 0
|
||||
latitude = 0
|
||||
|
||||
if amount > 0:
|
||||
for place in place_list:
|
||||
longitude += place.longitude
|
||||
latitude += place.latitude
|
||||
return {'latitude':latitude / amount, 'longitude': longitude / amount}
|
||||
|
||||
return {'latitude': latitude, 'longitude': longitude}
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
|
||||
def generate_image_upload_path(instance, filename):
|
||||
"""
|
||||
Callback for generating path for uploaded images.
|
||||
Returns filename as: place_pk-placename{-rnd_string}.jpg
|
||||
"""
|
||||
|
||||
return 'places/' + str(instance.place.pk) + '-' + str(instance.place.name) + '.' + filename.split('.')[-1]
|
||||
|
||||
class PlaceAsset(Submittable):
|
||||
"""
|
||||
Assets to a place, i.e. images
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
place = models.ForeignKey(
|
||||
Place,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='%(class)ss',
|
||||
null=True
|
||||
)
|
||||
|
||||
class PlaceImage (Submittable):
|
||||
"""
|
||||
PlaceImage defines an image file object that points to a file in uploads/.
|
||||
Intermediate image sizes are generated as defined in THUMBNAIL_ALIASES.
|
||||
PlaceImage references a Place to which it belongs.
|
||||
"""
|
||||
|
||||
description = models.TextField(
|
||||
blank=True,
|
||||
verbose_name=_('Description'),
|
||||
)
|
||||
filename = ThumbnailerImageField(
|
||||
upload_to=generate_image_upload_path,
|
||||
resize_source=dict(size=(2560, 2560),
|
||||
sharpen=True),
|
||||
verbose_name=_('Filename(s)'),
|
||||
help_text=_('Optional: One or more images to upload')
|
||||
)
|
||||
place = models.ForeignKey(
|
||||
Place,
|
||||
on_delete=models.CASCADE,
|
||||
related_name='placeimages'
|
||||
)
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
Returning the name of the corresponding place + id
|
||||
of this image as textual representation of this instance
|
||||
"""
|
||||
|
||||
return 'Image ' + str(self.pk)
|
||||
|
||||
|
||||
# These two auto-delete files from filesystem when they are unneeded:
|
||||
|
||||
@receiver(post_delete, sender=PlaceImage)
|
||||
def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||
"""
|
||||
Deletes file (including thumbnails) from filesystem
|
||||
when corresponding `PlaceImage` object is deleted.
|
||||
"""
|
||||
if instance.filename:
|
||||
# Get and delete all files and thumbnails from instance
|
||||
thumbmanager = get_thumbnailer(instance.filename)
|
||||
thumbmanager.delete(save=False)
|
||||
|
||||
|
||||
@receiver(pre_save, sender=PlaceImage)
|
||||
def auto_delete_file_on_change(sender, instance, **kwargs):
|
||||
"""
|
||||
Deletes old file from filesystem
|
||||
when corresponding `PlaceImage` object is updated
|
||||
with new file.
|
||||
"""
|
||||
if not instance.pk:
|
||||
return False
|
||||
|
||||
try:
|
||||
old_file = PlaceImage.objects.get(pk=instance.pk).filename
|
||||
except PlaceImage.DoesNotExist:
|
||||
return False
|
||||
|
||||
# No need to delete thumbnails, as they will be overwritten on regeneration.
|
||||
new_file = instance.filename
|
||||
if not old_file == new_file:
|
||||
if os.path.isfile(old_file.path):
|
||||
os.remove(old_file.path)
|
Before Width: | Height: | Size: 264 KiB After Width: | Height: | Size: 264 KiB |
@@ -1,5 +1,4 @@
|
||||
Copyright (c) 2010, Sebastian Kosch (sebastian@aldusleaf.org),
|
||||
with Reserved Font Name "Crimson" and "Crimson Text".
|
||||
Copyright 2018 The Crimson Pro Project Authors (https://github.com/Fonthausen/CrimsonPro)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
93
django_lostplaces/lostplaces/static/fonts/Montserrat/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2011 The Montserrat Project Authors (https://github.com/JulietaUla/Montserrat)
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 816 B After Width: | Height: | Size: 816 B |
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
Before Width: | Height: | Size: 641 B After Width: | Height: | Size: 641 B |
Before Width: | Height: | Size: 850 B After Width: | Height: | Size: 850 B |
BIN
django_lostplaces/lostplaces/static/icons/map-marker-icon.png
Normal file
After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 914 B After Width: | Height: | Size: 914 B |
Before Width: | Height: | Size: 488 B After Width: | Height: | Size: 488 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 717 B |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
@@ -424,46 +424,46 @@
|
||||
object-position: center; }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Crimson Text';
|
||||
font-family: 'Crimson Pro';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local("Crimson Text Regular"), local("CrimsonText-Regular"), url(fonts/Crimson/CrimsonText-Regular.ttf) format("truetype"); }
|
||||
src: local("Crimson Pro Regular"), local("CrimsonPro-Regular"), url(fonts/Crimson/CrimsonPro-Regular.ttf) format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Crimson Text';
|
||||
font-family: 'Crimson Pro';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local("Crimson Text Italic"), local("CrimsonText-Italic"), url(fonts/Crimson/CrimsonText-Italic.ttf) format("truetype"); }
|
||||
src: local("Crimson Pro Italic"), local("CrimsonPro-Italic"), url(fonts/Crimson/CrimsonPro-Italic.ttf) format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Crimson Text';
|
||||
font-family: 'Crimson Pro';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: local("Crimson Text Bold"), local("CrimsonText-Bold"), url(fonts/Crimson/CrimsonText-Bold.ttf) format("truetype"); }
|
||||
src: local("Crimson Pro Bold"), local("CrimsonPro-Bold"), url(fonts/Crimson/CrimsonPro-Bold.ttf) format("truetype"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local("Montserrat Regular"), local("Montserrat-Regular"), url(fonts/Montserrat/Montserrat-Regular.ttf) format("truetype"); }
|
||||
src: local("Montserrat Regular"), local("Montserrat-Regular"), url(fonts/Montserrat/Montserrat-Regular.woff2) format("woff2"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: local("Montserrat Italic"), local("Montserrat-Italic"), url(fonts/Montserrat/Montserrat-Italic.ttf) format("truetype"); }
|
||||
src: local("Montserrat Italic"), local("Montserrat-Italic"), url(fonts/Montserrat/Montserrat-Italic.woff2) format("woff2"); }
|
||||
|
||||
@font-face {
|
||||
font-family: 'Montserrat';
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: local("Montserrat Bold"), local("Montserrat-Bold"), url(fonts/Montserrat/Montserrat-Bold.ttf) format("truetype"); }
|
||||
src: local("Montserrat Bold"), local("Montserrat-Bold"), url(fonts/Montserrat/Montserrat-Bold.woff2) format("woff2"); }
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
@@ -583,7 +583,7 @@ body {
|
||||
|
||||
.LP-Paragraph {
|
||||
color: black;
|
||||
font-family: "Crimson Text", Times, serif;
|
||||
font-family: "Crimson Pro", Times, serif;
|
||||
font-size: 1.4rem;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
@@ -856,7 +856,7 @@ body {
|
||||
padding: 15px; } }
|
||||
|
||||
.LP-TextSection__Text {
|
||||
font-family: "Crimson Text", Times, serif;
|
||||
font-family: "Crimson Pro", Times, serif;
|
||||
font-size: 1.4rem; }
|
||||
.LP-TextSection__Text .LP-Link {
|
||||
margin: 0 3px; }
|
||||
@@ -1588,23 +1588,78 @@ body {
|
||||
border: none; }
|
||||
.LP-ImageGrid__Container {
|
||||
gap: 10px; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item, .LP-ImageGrid .LP-ImageGrid__Item * {
|
||||
overflow: hidden;
|
||||
word-break: break-all; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item--left img {
|
||||
object-position: left; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item--center img {
|
||||
object-position: center; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item--top img {
|
||||
object-position: top; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item--bottom img {
|
||||
object-position: botom; }
|
||||
.LP-ImageGrid .LP-ImageGrid__Item--center img {
|
||||
object-position: center; }
|
||||
.LP-ImageGrid__Item {
|
||||
position: relative; }
|
||||
.LP-ImageGrid__Item, .LP-ImageGrid__Item * {
|
||||
overflow: hidden;
|
||||
word-break: break-all; }
|
||||
.LP-ImageGrid__Item img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover; }
|
||||
.LP-ImageGrid__Item--left img {
|
||||
object-position: left; }
|
||||
.LP-ImageGrid__Item--center img {
|
||||
object-position: center; }
|
||||
.LP-ImageGrid__Item--top img {
|
||||
object-position: top; }
|
||||
.LP-ImageGrid__Item--bottom img {
|
||||
object-position: botom; }
|
||||
.LP-ImageGrid__Item--center img {
|
||||
object-position: center; }
|
||||
.LP-ImageGrid__Item--add .LP-Link {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
display: block;
|
||||
background: #f9f9f9; }
|
||||
.LP-ImageGrid__Item--add .LP-Link .LP-Icon {
|
||||
width: 35px;
|
||||
height: 35px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%); }
|
||||
.LP-ImageGrid__Item--add:hover .LP-Link {
|
||||
background-color: #D7CEC7; }
|
||||
.LP-ImageGrid__DeleteItem {
|
||||
opacity: 0.7;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
background-color: #C09F80;
|
||||
border-radius: 50%;
|
||||
height: 35px;
|
||||
width: 35px; }
|
||||
.LP-ImageGrid__DeleteItem .LP-Link .LP-Icon {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
position: relative;
|
||||
left: 7.8125px;
|
||||
top: 7.8125px; }
|
||||
.LP-ImageGrid__Item > .LP-Link:hover + .LP-ImageGrid__DeleteItem, .LP-ImageGrid__DeleteItem:hover {
|
||||
visibility: visible; }
|
||||
|
||||
.LP-Map {
|
||||
margin-bottom: 25px; }
|
||||
.LP-Map .ol-attribution {
|
||||
font-family: "Montserrat", Helvetica, sans-serif;
|
||||
color: #565656; }
|
||||
.LP-Map .ol-attribution a {
|
||||
color: #C09F80; }
|
||||
.LP-Map .ol-attribution a:hover, .LP-Map .ol-attribution a:focus {
|
||||
color: #D7CEC7; }
|
||||
.LP-Map .ol-zoom-in, .LP-Map .ol-zoom-out {
|
||||
background-color: #C09F80; }
|
||||
.LP-Map .ol-zoom-in:hover, .LP-Map .ol-zoom-in:focus, .LP-Map .ol-zoom-out:hover, .LP-Map .ol-zoom-out:focus {
|
||||
background-color: #565656; }
|
||||
.LP-Map .LP-Map__Popup {
|
||||
font-family: "Montserrat", Helvetica, sans-serif;
|
||||
color: #565656;
|
||||
background-color: #f9f9f9;
|
||||
padding: .5em;
|
||||
border-radius: 2px; }
|
||||
|
||||
.LP-MainContainer {
|
||||
margin: 0 auto;
|
||||
@@ -1642,7 +1697,7 @@ body {
|
||||
margin-bottom: 25px; } }
|
||||
|
||||
.LP-TextSection .LP-UnorderedList {
|
||||
font-family: "Crimson Text", Times, serif;
|
||||
font-family: "Crimson Pro", Times, serif;
|
||||
font-size: 1.4rem; }
|
||||
.LP-TextSection .LP-UnorderedList li {
|
||||
margin-bottom: 0.75em;
|
2
django_lostplaces/lostplaces/static/maps/ol.css
Normal file
@@ -0,0 +1,2 @@
|
||||
.ol-box{box-sizing:border-box;border-radius:2px;border:2px solid #00f}.ol-mouse-position{top:8px;right:8px;position:absolute}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px;padding:2px;position:absolute}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width;transition:all .25s}.ol-scale-bar{position:absolute;bottom:8px;left:8px}.ol-scale-step-marker{width:1px;height:15px;background-color:#000;float:right;z-Index:10}.ol-scale-step-text{position:absolute;bottom:-5px;font-size:12px;z-Index:11;color:#000;text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff}.ol-scale-text{position:absolute;font-size:14px;text-align:center;bottom:25px;color:#000;text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff}.ol-scale-singlebar{position:relative;height:10px;z-Index:9;box-sizing:border-box;border:1px solid #000}.ol-unsupported{display:none}.ol-unselectable,.ol-viewport{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.ol-selectable{-webkit-touch-callout:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ol-grabbing{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.ol-grab{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.ol-control{position:absolute;background-color:rgba(255,255,255,.4);border-radius:4px;padding:2px}.ol-control:hover{background-color:rgba(255,255,255,.6)}.ol-zoom{top:.5em;left:.5em}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s}.ol-zoom-extent{top:4.643em;left:.5em}.ol-full-screen{right:.5em;top:.5em}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-size:1.14em;font-weight:700;text-decoration:none;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:rgba(0,60,136,.5);border:none;border-radius:2px}.ol-control button::-moz-focus-inner{border:none;padding:0}.ol-zoom-extent button{line-height:1.4em}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform}.ol-touch .ol-control button{font-size:1.5em}.ol-touch .ol-zoom-extent{top:5.5em}.ol-control button:focus,.ol-control button:hover{text-decoration:none;background-color:rgba(0,60,136,.7)}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em)}.ol-attribution ul{margin:0;padding:0 .5em;color:#000;text-shadow:0 0 2px #fff}.ol-attribution li{display:inline;list-style:none}.ol-attribution li:not(:last-child):after{content:" "}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle}.ol-attribution button,.ol-attribution ul{display:inline-block}.ol-attribution.ol-collapsed ul{display:none}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em}.ol-attribution.ol-uncollapsible button{display:none}.ol-zoomslider{top:4.5em;left:.5em;height:200px}.ol-zoomslider button{position:relative;height:10px}.ol-touch .ol-zoomslider{top:5.5em}.ol-overviewmap{left:.5em;bottom:.5em}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0}.ol-overviewmap .ol-overviewmap-map,.ol-overviewmap button{display:inline-block}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px}.ol-overviewmap:not(.ol-collapsed) button{bottom:1px;left:2px;position:absolute}.ol-overviewmap.ol-collapsed .ol-overviewmap-map,.ol-overviewmap.ol-uncollapsible button{display:none}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7)}.ol-overviewmap .ol-overviewmap-box:hover{cursor:move}
|
||||
/*# sourceMappingURL=ol.css.map */
|
1
django_lostplaces/lostplaces/static/maps/ol.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["src/ol/ol.css"],"names":[],"mappings":"AAAA,QACE,WAAY,WACZ,cAAe,IACf,OAAQ,IAAI,MAAM,KAGpB,mBACE,IAAK,IACL,MAAO,IACP,SAAU,SAGZ,eACE,WAAY,kBACZ,cAAe,IACf,OAAQ,IACR,KAAM,IACN,QAAS,IACT,SAAU,SAEZ,qBACE,OAAQ,IAAI,MAAM,KAClB,WAAY,KACZ,MAAO,KACP,UAAW,KACX,WAAY,OACZ,OAAQ,IACR,YAAa,QAAQ,CAAE,MACvB,WAAY,IAAI,KAElB,cACE,SAAU,SACV,OAAQ,IACR,KAAM,IAER,sBACE,MAAO,IACP,OAAQ,KACR,iBAAkB,KAClB,MAAO,MACP,QAAS,GAEX,oBACE,SAAU,SACV,OAAQ,KACR,UAAW,KACX,QAAS,GACT,MAAO,KACP,YAAa,KAAK,EAAE,IAAO,CAAE,EAAE,IAAI,IAAO,CAAE,IAAI,EAAE,IAAO,CAAE,EAAE,KAAK,KAEpE,eACE,SAAU,SACV,UAAW,KACX,WAAY,OACZ,OAAQ,KACR,MAAO,KACP,YAAa,KAAK,EAAE,IAAO,CAAE,EAAE,IAAI,IAAO,CAAE,IAAI,EAAE,IAAO,CAAE,EAAE,KAAK,KAEpE,oBACE,SAAU,SACV,OAAQ,KACR,QAAS,EACT,WAAY,WACZ,OAAQ,IAAI,MAAM,KAGpB,gBACE,QAAS,KAEG,iBAAd,aACE,sBAAuB,KACvB,oBAAqB,KACrB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KACb,4BAA6B,YAE/B,eACE,sBAAuB,QACvB,oBAAqB,KACrB,iBAAkB,KAClB,gBAAiB,KACjB,YAAa,KAEf,aACE,OAAQ,iBACR,OAAQ,cACR,OAAQ,SAEV,SACE,OAAQ,KACR,OAAQ,aACR,OAAQ,UACR,OAAQ,KAEV,YACE,SAAU,SACV,iBAAkB,qBAClB,cAAe,IACf,QAAS,IAEX,kBACE,iBAAkB,qBAEpB,SACE,IAAK,KACL,KAAM,KAER,WACE,IAAK,KACL,MAAO,KACP,WAAY,QAAQ,KAAK,MAAM,CAAE,WAAW,GAAG,OAEjD,qBACE,QAAS,EACT,WAAY,OACZ,WAAY,QAAQ,KAAK,MAAM,CAAE,WAAW,GAAG,OAAO,KAExD,gBACE,IAAK,QACL,KAAM,KAER,gBACE,MAAO,KACP,IAAK,KAGP,mBACE,QAAS,MACT,OAAQ,IACR,QAAS,EACT,MAAO,KACP,UAAW,OACX,YAAa,IACb,gBAAiB,KACjB,WAAY,OACZ,OAAQ,QACR,MAAO,QACP,YAAa,KACb,iBAAkB,kBAClB,OAAQ,KACR,cAAe,IAEjB,qCACE,OAAQ,KACR,QAAS,EAEX,uBACE,YAAa,MAEf,YACE,QAAS,MACT,YAAa,IACb,UAAW,MACX,YAAa,UAEf,6BACE,UAAW,MAEb,0BACE,IAAK,MAGP,yBADA,yBAEE,gBAAiB,KACjB,iBAAkB,kBAEpB,qBACE,cAAe,IAAI,IAAI,EAAE,EAE3B,sBACE,cAAe,EAAE,EAAE,IAAI,IAIzB,gBACE,WAAY,MACZ,OAAQ,KACR,MAAO,KACP,UAAW,mBAGb,mBACE,OAAQ,EACR,QAAS,EAAE,KACX,MAAO,KACP,YAAa,EAAE,EAAE,IAAI,KAEvB,mBACE,QAAS,OACT,WAAY,KAEd,0CACE,QAAS,IAEX,oBACE,WAAY,IACZ,UAAW,QACX,eAAgB,OAEE,uBAApB,mBACE,QAAS,aAEX,gCACE,QAAS,KAEX,mCACE,WAAY,qBAEd,iCACE,OAAQ,EACR,MAAO,EACP,cAAe,IAAI,EAAE,EAEvB,qCACE,WAAY,MACZ,WAAY,MAEd,wCACE,QAAS,KAGX,eACE,IAAK,MACL,KAAM,KACN,OAAQ,MAEV,sBACE,SAAU,SACV,OAAQ,KAGV,yBACE,IAAK,MAGP,gBACE,KAAM,KACN,OAAQ,KAEV,iCACE,OAAQ,EACR,KAAM,EACN,cAAe,EAAE,IAAI,EAAE,EAEzB,oCACA,uBACE,QAAS,aAEX,oCACE,OAAQ,IAAI,MAAM,QAClB,OAAQ,MACR,OAAQ,IACR,MAAO,MAET,0CACE,OAAQ,IACR,KAAM,IACN,SAAU,SAEZ,iDACA,wCACE,QAAS,KAEX,mCACE,WAAY,qBAEd,oBACE,OAAQ,IAAI,OAAO,kBAGrB,0CACE,OAAQ"}
|
9
django_lostplaces/lostplaces/static/maps/ol.js
Normal file
1
django_lostplaces/lostplaces/static/maps/ol.js.map
Normal file
@@ -1,6 +1,7 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}Forbidden{% endblock %}
|
||||
{% block title %}{% trans 'Forbidden' %}{% endblock %}
|
||||
|
||||
{% block additional_head %}
|
||||
{% if request.META.HTTP_REFERER %}
|
||||
@@ -10,6 +11,6 @@
|
||||
|
||||
{% block maincontent %}
|
||||
{% if request.META.HTTP_REFERER %}
|
||||
<p class="LP-Headline">You will be redirected in 5 seconds</p><p class="LP-Headline"><a href="{{ request.META.HTTP_REFERER }}" class="LP-Link">Go Back</a></p>
|
||||
<p class="LP-Headline">{% trans 'You will be redirected in 5 seconds' %}</p><p class="LP-Headline"><a href="{{ request.META.HTTP_REFERER }}" class="LP-Link">{% trans 'Go Back' %}</a></p>
|
||||
{% endif %}
|
||||
{% endblock maincontent %}
|
52
django_lostplaces/lostplaces/templates/flat/codex-de.html
Normal file
@@ -0,0 +1,52 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
# {% block title %}UrBex Codex{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<header class="LP-TextSection__Headline">
|
||||
<h1 class="LP-Headline">Nimm nichts mit - außer Deinen Bildern. Laß nichts da - außer Deinen Fußspuren!</h1>
|
||||
</header>
|
||||
|
||||
<article class="LP-TextSection LP-TextSection__Text">
|
||||
|
||||
<p>Das sollte doch eigentlich eindeutig sein, oder? Aber wie wir alle wissen, hat jedes Schild eine Geschichte. Wir haben zu viel sinnlose Zerstörung gesehen, sodass wir uns dazu entschieden haben, einen grundlegenden Urban Exploration Codex niederzuschreiben.</p>
|
||||
<ul class="LP-UnorderedList">
|
||||
<li>
|
||||
<b>Wir respektieren fremdes Eigentum</b>, so wie wir das von anderen auch verlangen. Deswegen öffnen wir keinen Zugang gewaltsam, oder beschädigen eine Verschlusseinrichtung. Wir betreten ein Grundstück oder ein Gebäude / eine Anlage / eine Ruine nur dann, wenn wir davon ausgehen können, nicht gegen den Willen des Eigentümers dort zu sein. Eine gut erhaltene Umzäunung, oder ein ständiger Wachschutz sprechen dafür, dass der Eigentümer sich noch mit seiner Anlage befasst. Längst umgesunkene Zäune, Ruinen im letzten Stadium eines Verfalls sprecher dafür, dass dem Eigentümer das eher Wurst ist.
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir nehmen von einer Location nichts mit</b>, auch keine "kleinen Andenken", und lassen nichts da - auch keine Kippen, keine Verpackungen - nichts.
|
||||
<b>Wir verändern am Ort nichts, nehmen nichts weg und fügen nichts hinzu.</b>
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir rauchen möglichst nicht.</b> Nicht nur, weil es stinkt und Müll verursacht. Es gibt immer die Chance, irgendwas durch Funkenflug anzuzünden. Lass es trockene Blätter an einem heißen Sommertag oder (potentielle) entflammbare Materialien in Industrieanlagen sein.
|
||||
</li>
|
||||
<li>
|
||||
<b>Sprayen ist ein absolutes "no-go"!</b>
|
||||
</li>
|
||||
<li>
|
||||
<b>In einer Location verhalten wir uns vorsichtig.</b> Wir werfen nichts in Löcher oder aus Fenstern und berühren auch keine elektrischen Anlagen. Nicht immer ist der Strom wirklich abgeschaltet. Deswegen öffnen wor auch keine Flaschen und andere Behälter. Wir gehen niemals ohne Licht in einen dunklen Raum, und nehmen immer eine Reservelampe mit.
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir sagen vor einer Tour mindestens einer Person unseres Vertrauens, wo wir sind</b> (Koordinaten!), wie lange wir uns dort aufhalten werden und was wir dort tun. Wir verabreden, daß wir uns bei einem längeren Aufenthalt dort regelmäßig melden, oder aber ein "okay" geben, wenn wir die Location wieder verlassen haben. Wenn wir uns verspäten, dann denken wir daran, eine entsprechende Nachricht abzusetzen. Unsere Kontaktperson soll nach einer gewissen Zeit, wenn sie nichts von mir hört, für Hilfe sorgen.
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir bereiten unsere Tour sorgfältig vor.</b> Es ist ärgerlich, wenn die Kamera-Akkus nicht geladen sind - aber gefährlich ist es keineswegs. Es ist aber lebensgefährlich, wenn ein verschmutzter Nagel durch eine Sohle getreten wird. Sicherheitsschuhe zu tragen ist eine gute Idee. Wenn wir unter Tage gehen, nehmen wir angemessenes Equipment mit um uns zu schützen — z. B. einen Gaswarner oder vllt. sogar einen Geigerzähler.
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir parken nicht so, daß Dritte auf unser Vorhaben aufmerksam werden.</b> Unser Hobby braucht keine öffentliche Aufmerksamkeit, die sich auf illegales Betreten von Grundstücken richtet (und illegal dürfte das Betreten ja meist sein ...).
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir verraten unsere Locations nicht</b> und veröffentlichen ausschließlich Fotos, bei denen Geodaten aus den Dateien (EXIF) entfernt worden sind. Deswegen posten wir unterwegs nur dann vom Smartphone, wenn wir absolut sicher sind, dass keine Koordinaten im Bild enthalten sind.
|
||||
</li>
|
||||
<li>
|
||||
<b>Vor allem halten wir die Klappe</b> und geben nicht mit einer tollen, noch unberührt aussehenden Location an. Deine "Freunde" in Facebook kennst Du oft nicht mal persönlich, schon gar nicht in einer Gruppe. Nichts verbreitet sich schneller als ein "Geheimnis", das unter dem Siegel des Vertrauens weitergegeben wurde. Willst Du daran schuld sein, daß hirnbefreite Sprayer auch diesen Ort demolieren?
|
||||
</li>
|
||||
<li>
|
||||
<b>Wir sorgen durch Argumente und Überzeugung dafür, daß unsere Begleiter sich ebenso verhalten!</b> In erster Linie versuchen wir durch unser eigenes Verhalten zu überzeugen.
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
{% endblock maincontent %}
|
@@ -29,22 +29,22 @@
|
||||
<b>In a location we are careful not to endanger ourselves or others.</b> We don't throw anything into holes or out of windows, and we don't touch electrical equipment. You can't tell from its look or sound if the power is really switched off. Therefore we do not open bottles and other containers. We never go into a dark room without light, and always have a spare lamp with us.
|
||||
</li>
|
||||
<li>
|
||||
<b>Before my tour we tell at least one person of my trust where we are</b> (coordinates!), how long we will be there and what we will do there. We arrange that we will contact him regularly if we stay there for a longer period of time, or give an "okay" when we have left the location again. If we am late, we will remember to send a message to that effect. Our contact person is supposed to provide help after a certain period of time if he does not hear from me.
|
||||
<b>Before our tour we tell at least one person of our trust where we are</b> (coordinates!), how long we will be there and what we will do there. We arrange that we will contact him regularly if we stay there for a longer period of time, or give an "okay" when we have left the location again. If we am late, we will remember to send a message to that effect. Our contact person is supposed to provide help after a certain period of time if he does not hear from me.
|
||||
</li>
|
||||
<li>
|
||||
<b>We prepare my tour carefully.</b> It is annoying when the camera batteries are not charged — but it is not dangerous at all. But it is life-threatening if you step unto a dirty nail that perforates your shoe. It is wise to wear sturdy shoes. When we go underground, we take appropiate equipment with us to protect ourselves — e. g. a gas warner or even a geiger counter.
|
||||
<b>We prepare out tour carefully.</b> It is annoying when the camera batteries are not charged — but it is not dangerous at all. But it is life-threatening if you step unto a dirty nail that perforates your shoe. It is wise to wear sturdy shoes. When we go underground, we take appropiate equipment with us to protect ourselves — e. g. a gas warner or even a geiger counter.
|
||||
</li>
|
||||
<li>
|
||||
<b>We do not park in such a way that third parties become aware of my intention.</b> Our hobby does not need public attention, which is directed to illegal entering of properties (and illegal entering is probably the most common way ...).
|
||||
<b>We do not park in such a way that third parties become aware of our intention.</b> Our hobby does not need public attention, which is directed to illegal entering of properties (and illegal entering is probably the most common way ...).
|
||||
</li>
|
||||
<li>
|
||||
<b>We do not disclose our locations</b> and only publish photos where geodata has been removed from the files (EXIF). Therefore we only post from my smartphone when we am absolutely sure that no coordinates are contained in the picture.
|
||||
<b>We do not disclose our locations</b> and only publish photos where geodata has been removed from the files (EXIF). Therefore we only post from our smartphone when we am absolutely sure that no coordinates are contained in the picture.
|
||||
</li>
|
||||
<li>
|
||||
<b>Above all, we keep my mouth shut</b> and don't brag about a great, still untouched looking location. You often don't even know your "friends" in Facebook personally, especially not in a group. Nothing spreads faster than a "secret" that has been passed on under the seal of trust. Do you want to be responsible for brainless sprayers destroying this place too?
|
||||
<b>Above all, we keep our mouth shut</b> and don't brag about a great, still untouched looking location. You often don't even know your "friends" in Facebook personally, especially not in a group. Nothing spreads faster than a "secret" that has been passed on under the seal of trust. Do you want to be responsible for brainless sprayers destroying this place too?
|
||||
</li>
|
||||
<li>
|
||||
<b>We make sure through argument and conviction that my companions behave the same way!</b> First and foremost we try to convince through our own behavior.
|
||||
<b>We make sure through argument and conviction that our companions behave the same way!</b> First and foremost we try to convince through our own behavior.
|
||||
</li>
|
||||
</ul>
|
||||
</article>
|
28
django_lostplaces/lostplaces/templates/flat/imprint-de.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
# {% block title %}Impressum{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<header class="LP-TextSection__Headline">
|
||||
<h1 class="LP-Headline">Impressum</h1>
|
||||
</header>
|
||||
|
||||
<article class="LP-TextSection LP-TextSection__Text">
|
||||
<h3>Angaben gemäß § 5 TMG</h3>
|
||||
<p>Urban Exploration Ltd.<br />
|
||||
John S. Smith<br />
|
||||
2563 College Avenue<br />
|
||||
Dayton, OH 45402</p>
|
||||
|
||||
<h3>Kontakt</h3>
|
||||
<p>Telefon: 937-387-6498<br />
|
||||
E-Mail: JohnSSmith@einrot.com</p>
|
||||
|
||||
<h3>Verantwortlich für den Inhalt nach § 55 Abs. 2 RStV</h3>
|
||||
<p>John S. Smith<br />
|
||||
2563 College Avenue<br />
|
||||
Dayton, OH 45402</p>
|
||||
</article>
|
||||
|
||||
{% endblock maincontent %}
|
28
django_lostplaces/lostplaces/templates/flat/imprint.html
Normal file
@@ -0,0 +1,28 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
# {% block title %}Imprint{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<header class="LP-TextSection__Headline">
|
||||
<h1 class="LP-Headline">Imprint</h1>
|
||||
</header>
|
||||
|
||||
<article class="LP-TextSection LP-TextSection__Text">
|
||||
<h3>Information according to § 5 TMG</h3>
|
||||
<p>Urban Exploration Ltd.<br />
|
||||
John S. Smith<br />
|
||||
2563 College Avenue<br />
|
||||
Dayton, OH 45402</p>
|
||||
|
||||
<h3>Contact</h3>
|
||||
<p>Phone: 937-387-6498<br />
|
||||
e-mail: JohnSSmith@einrot.com</p>
|
||||
|
||||
<h3>Responsible for the content according to § 55 Abs. 2 RStV</h3>
|
||||
<p>John S. Smith<br />
|
||||
2563 College Avenue<br />
|
||||
Dayton, OH 45402</p>
|
||||
</article>
|
||||
|
||||
{% endblock maincontent %}
|
@@ -0,0 +1,259 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
# {% block title %}Datenschutzerklärung{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<header class="LP-TextSection__Headline">
|
||||
<h1 class="LP-Headline">Datenschutzerklärung</h1>
|
||||
</header>
|
||||
|
||||
<article class="LP-TextSection LP-TextSection__Text">
|
||||
<h4>Datenschutzerklärung</h4>
|
||||
|
||||
<p>Wir freuen uns sehr über Ihr Interesse an unserem Unternehmen. Datenschutz hat einen besonders hohen Stellenwert für die Geschäftsleitung der Urban Exploration Ltd. Eine Nutzung der Internetseiten der Urban Exploration Ltd ist grundsätzlich ohne jede Angabe personenbezogener Daten möglich. Sofern eine betroffene Person besondere Services unseres Unternehmens über unsere Internetseite in Anspruch nehmen möchte, könnte jedoch eine Verarbeitung personenbezogener Daten erforderlich werden. Ist die Verarbeitung personenbezogener Daten erforderlich und besteht für eine solche Verarbeitung keine gesetzliche Grundlage, holen wir generell eine Einwilligung der betroffenen Person ein.</p>
|
||||
|
||||
<p>Die Verarbeitung personenbezogener Daten, beispielsweise des Namens, der Anschrift, E-Mail-Adresse oder Telefonnummer einer betroffenen Person, erfolgt stets im Einklang mit der Datenschutz-Grundverordnung und in Übereinstimmung mit den für die Urban Exploration Ltd geltenden landesspezifischen Datenschutzbestimmungen. Mittels dieser Datenschutzerklärung möchte unser Unternehmen die Öffentlichkeit über Art, Umfang und Zweck der von uns erhobenen, genutzten und verarbeiteten personenbezogenen Daten informieren. Ferner werden betroffene Personen mittels dieser Datenschutzerklärung über die ihnen zustehenden Rechte aufgeklärt.</p>
|
||||
|
||||
<p>Die Urban Exploration Ltd hat als für die Verarbeitung Verantwortlicher zahlreiche technische und organisatorische Maßnahmen umgesetzt, um einen möglichst lückenlosen Schutz der über diese Internetseite verarbeiteten personenbezogenen Daten sicherzustellen. Dennoch können Internetbasierte Datenübertragungen grundsätzlich Sicherheitslücken aufweisen, sodass ein absoluter Schutz nicht gewährleistet werden kann. Aus diesem Grund steht es jeder betroffenen Person frei, personenbezogene Daten auch auf alternativen Wegen, beispielsweise telefonisch, an uns zu übermitteln.</p>
|
||||
|
||||
<h4>1. Begriffsbestimmungen</h4>
|
||||
<p>Die Datenschutzerklärung der Urban Exploration Ltd beruht auf den Begrifflichkeiten, die durch den Europäischen Richtlinien- und Verordnungsgeber beim Erlass der Datenschutz-Grundverordnung (DS-GVO) verwendet wurden. Unsere Datenschutzerklärung soll sowohl für die Öffentlichkeit als auch für unsere Kunden und Geschäftspartner einfach lesbar und verständlich sein. Um dies zu gewährleisten, möchten wir vorab die verwendeten Begrifflichkeiten erläutern.</p>
|
||||
|
||||
<p>Wir verwenden in dieser Datenschutzerklärung unter anderem die folgenden Begriffe:</p>
|
||||
|
||||
<ul style="list-style: none">
|
||||
<li><h4>a) personenbezogene Daten</h4>
|
||||
<p>Personenbezogene Daten sind alle Informationen, die sich auf eine identifizierte oder identifizierbare natürliche Person (im Folgenden „betroffene Person“) beziehen. Als identifizierbar wird eine natürliche Person angesehen, die direkt oder indirekt, insbesondere mittels Zuordnung zu einer Kennung wie einem Namen, zu einer Kennnummer, zu Standortdaten, zu einer Online-Kennung oder zu einem oder mehreren besonderen Merkmalen, die Ausdruck der physischen, physiologischen, genetischen, psychischen, wirtschaftlichen, kulturellen oder sozialen Identität dieser natürlichen Person sind, identifiziert werden kann.</p>
|
||||
</li>
|
||||
<li><h4>b) betroffene Person</h4>
|
||||
<p>Betroffene Person ist jede identifizierte oder identifizierbare natürliche Person, deren personenbezogene Daten von dem für die Verarbeitung Verantwortlichen verarbeitet werden.</p>
|
||||
</li>
|
||||
<li><h4>c) Verarbeitung</h4>
|
||||
<p>Verarbeitung ist jeder mit oder ohne Hilfe automatisierter Verfahren ausgeführte Vorgang oder jede solche Vorgangsreihe im Zusammenhang mit personenbezogenen Daten wie das Erheben, das Erfassen, die Organisation, das Ordnen, die Speicherung, die Anpassung oder Veränderung, das Auslesen, das Abfragen, die Verwendung, die Offenlegung durch Übermittlung, Verbreitung oder eine andere Form der Bereitstellung, den Abgleich oder die Verknüpfung, die Einschränkung, das Löschen oder die Vernichtung.</p>
|
||||
</li>
|
||||
<li><h4>d) Einschränkung der Verarbeitung</h4>
|
||||
<p>Einschränkung der Verarbeitung ist die Markierung gespeicherter personenbezogener Daten mit dem Ziel, ihre künftige Verarbeitung einzuschränken.</p>
|
||||
</li>
|
||||
<li><h4>e) Profiling</h4>
|
||||
<p>Profiling ist jede Art der automatisierten Verarbeitung personenbezogener Daten, die darin besteht, dass diese personenbezogenen Daten verwendet werden, um bestimmte persönliche Aspekte, die sich auf eine natürliche Person beziehen, zu bewerten, insbesondere, um Aspekte bezüglich Arbeitsleistung, wirtschaftlicher Lage, Gesundheit, persönlicher Vorlieben, Interessen, Zuverlässigkeit, Verhalten, Aufenthaltsort oder Ortswechsel dieser natürlichen Person zu analysieren oder vorherzusagen.</p>
|
||||
</li>
|
||||
<li><h4>f) Pseudonymisierung</h4>
|
||||
<p>Pseudonymisierung ist die Verarbeitung personenbezogener Daten in einer Weise, auf welche die personenbezogenen Daten ohne Hinzuziehung zusätzlicher Informationen nicht mehr einer spezifischen betroffenen Person zugeordnet werden können, sofern diese zusätzlichen Informationen gesondert aufbewahrt werden und technischen und organisatorischen Maßnahmen unterliegen, die gewährleisten, dass die personenbezogenen Daten nicht einer identifizierten oder identifizierbaren natürlichen Person zugewiesen werden.</p>
|
||||
</li>
|
||||
<li><h4>g) Verantwortlicher oder für die Verarbeitung Verantwortlicher</h4>
|
||||
<p>Verantwortlicher oder für die Verarbeitung Verantwortlicher ist die natürliche oder juristische Person, Behörde, Einrichtung oder andere Stelle, die allein oder gemeinsam mit anderen über die Zwecke und Mittel der Verarbeitung von personenbezogenen Daten entscheidet. Sind die Zwecke und Mittel dieser Verarbeitung durch das Unionsrecht oder das Recht der Mitgliedstaaten vorgegeben, so kann der Verantwortliche beziehungsweise können die bestimmten Kriterien seiner Benennung nach dem Unionsrecht oder dem Recht der Mitgliedstaaten vorgesehen werden.</p>
|
||||
</li>
|
||||
<li><h4>h) Auftragsverarbeiter</h4>
|
||||
<p>Auftragsverarbeiter ist eine natürliche oder juristische Person, Behörde, Einrichtung oder andere Stelle, die personenbezogene Daten im Auftrag des Verantwortlichen verarbeitet.</p>
|
||||
</li>
|
||||
<li><h4>i) Empfänger</h4>
|
||||
<p>Empfänger ist eine natürliche oder juristische Person, Behörde, Einrichtung oder andere Stelle, der personenbezogene Daten offengelegt werden, unabhängig davon, ob es sich bei ihr um einen Dritten handelt oder nicht. Behörden, die im Rahmen eines bestimmten Untersuchungsauftrags nach dem Unionsrecht oder dem Recht der Mitgliedstaaten möglicherweise personenbezogene Daten erhalten, gelten jedoch nicht als Empfänger.</p>
|
||||
</li>
|
||||
<li><h4>j) Dritter</h4>
|
||||
<p>Dritter ist eine natürliche oder juristische Person, Behörde, Einrichtung oder andere Stelle außer der betroffenen Person, dem Verantwortlichen, dem Auftragsverarbeiter und den Personen, die unter der unmittelbaren Verantwortung des Verantwortlichen oder des Auftragsverarbeiters befugt sind, die personenbezogenen Daten zu verarbeiten.</p>
|
||||
</li>
|
||||
<li><h4>k) Einwilligung</h4>
|
||||
<p>Einwilligung ist jede von der betroffenen Person freiwillig für den bestimmten Fall in informierter Weise und unmissverständlich abgegebene Willensbekundung in Form einer Erklärung oder einer sonstigen eindeutigen bestätigenden Handlung, mit der die betroffene Person zu verstehen gibt, dass sie mit der Verarbeitung der sie betreffenden personenbezogenen Daten einverstanden ist.</p>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>2. Name und Anschrift des für die Verarbeitung Verantwortlichen</h4>
|
||||
<p>Verantwortlicher im Sinne der Datenschutz-Grundverordnung, sonstiger in den Mitgliedstaaten der Europäischen Union geltenden Datenschutzgesetze und anderer Bestimmungen mit datenschutzrechtlichem Charakter ist die:</p>
|
||||
|
||||
<p>Urban Exploration Ltd</p>
|
||||
<p>2563 College Avenue</p>
|
||||
<p>45402 Dayton</p>
|
||||
<p>OH</p>
|
||||
<p>Tel.: 937-387-6498</p>
|
||||
<p>E-Mail: JohnSSmith@einrot.com</p>
|
||||
<p>Website: https://www.urban-exploration.com</p>
|
||||
|
||||
<h4>3. Erfassung von allgemeinen Daten und Informationen</h4>
|
||||
<p>Die Internetseite der Urban Exploration Ltd erfasst mit jedem Aufruf der Internetseite durch eine betroffene Person oder ein automatisiertes System eine Reihe von allgemeinen Daten und Informationen. Diese allgemeinen Daten und Informationen werden in den Logfiles des Servers gespeichert. Erfasst werden können die (1) verwendeten Browsertypen und Versionen, (2) das vom zugreifenden System verwendete Betriebssystem, (3) die Internetseite, von welcher ein zugreifendes System auf unsere Internetseite gelangt (sogenannte Referrer), (4) die Unterwebseiten, welche über ein zugreifendes System auf unserer Internetseite angesteuert werden, (5) das Datum und die Uhrzeit eines Zugriffs auf die Internetseite, (6) eine Internet-Protokoll-Adresse (IP-Adresse), (7) der Internet-Service-Provider des zugreifenden Systems und (8) sonstige ähnliche Daten und Informationen, die der Gefahrenabwehr im Falle von Angriffen auf unsere informationstechnologischen Systeme dienen.</p>
|
||||
|
||||
<p>Bei der Nutzung dieser allgemeinen Daten und Informationen zieht die Urban Exploration Ltd keine Rückschlüsse auf die betroffene Person. Diese Informationen werden vielmehr benötigt, um (1) die Inhalte unserer Internetseite korrekt auszuliefern, (2) die Inhalte unserer Internetseite sowie die Werbung für diese zu optimieren, (3) die dauerhafte Funktionsfähigkeit unserer informationstechnologischen Systeme und der Technik unserer Internetseite zu gewährleisten sowie (4) um Strafverfolgungsbehörden im Falle eines Cyberangriffes die zur Strafverfolgung notwendigen Informationen bereitzustellen. Diese anonym erhobenen Daten und Informationen werden durch die Urban Exploration Ltd daher einerseits statistisch und ferner mit dem Ziel ausgewertet, den Datenschutz und die Datensicherheit in unserem Unternehmen zu erhöhen, um letztlich ein optimales Schutzniveau für die von uns verarbeiteten personenbezogenen Daten sicherzustellen. Die anonymen Daten der Server-Logfiles werden getrennt von allen durch eine betroffene Person angegebenen personenbezogenen Daten gespeichert.</p>
|
||||
|
||||
<h4>4. Registrierung auf unserer Internetseite</h4>
|
||||
<p>Die betroffene Person hat die Möglichkeit, sich auf der Internetseite des für die Verarbeitung Verantwortlichen unter Angabe von personenbezogenen Daten zu registrieren. Welche personenbezogenen Daten dabei an den für die Verarbeitung Verantwortlichen übermittelt werden, ergibt sich aus der jeweiligen Eingabemaske, die für die Registrierung verwendet wird. Die von der betroffenen Person eingegebenen personenbezogenen Daten werden ausschließlich für die interne Verwendung bei dem für die Verarbeitung Verantwortlichen und für eigene Zwecke erhoben und gespeichert. Der für die Verarbeitung Verantwortliche kann die Weitergabe an einen oder mehrere Auftragsverarbeiter, beispielsweise einen Paketdienstleister, veranlassen, der die personenbezogenen Daten ebenfalls ausschließlich für eine interne Verwendung, die dem für die Verarbeitung Verantwortlichen zuzurechnen ist, nutzt.</p>
|
||||
|
||||
<p>Durch eine Registrierung auf der Internetseite des für die Verarbeitung Verantwortlichen wird ferner die vom Internet-Service-Provider (ISP) der betroffenen Person vergebene IP-Adresse, das Datum sowie die Uhrzeit der Registrierung gespeichert. Die Speicherung dieser Daten erfolgt vor dem Hintergrund, dass nur so der Missbrauch unserer Dienste verhindert werden kann, und diese Daten im Bedarfsfall ermöglichen, begangene Straftaten aufzuklären. Insofern ist die Speicherung dieser Daten zur Absicherung des für die Verarbeitung Verantwortlichen erforderlich. Eine Weitergabe dieser Daten an Dritte erfolgt grundsätzlich nicht, sofern keine gesetzliche Pflicht zur Weitergabe besteht oder die Weitergabe der Strafverfolgung dient.</p>
|
||||
|
||||
<p>Die Registrierung der betroffenen Person unter freiwilliger Angabe personenbezogener Daten dient dem für die Verarbeitung Verantwortlichen dazu, der betroffenen Person Inhalte oder Leistungen anzubieten, die aufgrund der Natur der Sache nur registrierten Benutzern angeboten werden können. Registrierten Personen steht die Möglichkeit frei, die bei der Registrierung angegebenen personenbezogenen Daten jederzeit abzuändern oder vollständig aus dem Datenbestand des für die Verarbeitung Verantwortlichen löschen zu lassen.</p>
|
||||
|
||||
<p>Der für die Verarbeitung Verantwortliche erteilt jeder betroffenen Person jederzeit auf Anfrage Auskunft darüber, welche personenbezogenen Daten über die betroffene Person gespeichert sind. Ferner berichtigt oder löscht der für die Verarbeitung Verantwortliche personenbezogene Daten auf Wunsch oder Hinweis der betroffenen Person, soweit dem keine gesetzlichen Aufbewahrungspflichten entgegenstehen. Die Gesamtheit der Mitarbeiter des für die Verarbeitung Verantwortlichen stehen der betroffenen Person in diesem Zusammenhang als Ansprechpartner zur Verfügung.</p>
|
||||
|
||||
<h4>5. Routinemäßige Löschung und Sperrung von personenbezogenen Daten</h4>
|
||||
<p>Der für die Verarbeitung Verantwortliche verarbeitet und speichert personenbezogene Daten der betroffenen Person nur für den Zeitraum, der zur Erreichung des Speicherungszwecks erforderlich ist oder sofern dies durch den Europäischen Richtlinien- und Verordnungsgeber oder einen anderen Gesetzgeber in Gesetzen oder Vorschriften, welchen der für die Verarbeitung Verantwortliche unterliegt, vorgesehen wurde.</p>
|
||||
|
||||
<p>Entfällt der Speicherungszweck oder läuft eine vom Europäischen Richtlinien- und Verordnungsgeber oder einem anderen zuständigen Gesetzgeber vorgeschriebene Speicherfrist ab, werden die personenbezogenen Daten routinemäßig und entsprechend den gesetzlichen Vorschriften gesperrt oder gelöscht.</p>
|
||||
|
||||
<h4>6. Rechte der betroffenen Person</h4>
|
||||
<ul style="list-style: none;">
|
||||
<li><h4>a) Recht auf Bestätigung</h4>
|
||||
<p>Jede betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber eingeräumte Recht, von dem für die Verarbeitung Verantwortlichen eine Bestätigung darüber zu verlangen, ob sie betreffende personenbezogene Daten verarbeitet werden. Möchte eine betroffene Person dieses Bestätigungsrecht in Anspruch nehmen, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden.</p>
|
||||
</li>
|
||||
<li><h4>b) Recht auf Auskunft</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, jederzeit von dem für die Verarbeitung Verantwortlichen unentgeltliche Auskunft über die zu seiner Person gespeicherten personenbezogenen Daten und eine Kopie dieser Auskunft zu erhalten. Ferner hat der Europäische Richtlinien- und Verordnungsgeber der betroffenen Person Auskunft über folgende Informationen zugestanden:</p>
|
||||
|
||||
<ul style="list-style: none;">
|
||||
<li>die Verarbeitungszwecke</li>
|
||||
<li>die Kategorien personenbezogener Daten, die verarbeitet werden</li>
|
||||
<li>die Empfänger oder Kategorien von Empfängern, gegenüber denen die personenbezogenen Daten offengelegt worden sind oder noch offengelegt werden, insbesondere bei Empfängern in Drittländern oder bei internationalen Organisationen</li>
|
||||
<li>falls möglich die geplante Dauer, für die die personenbezogenen Daten gespeichert werden, oder, falls dies nicht möglich ist, die Kriterien für die Festlegung dieser Dauer</li>
|
||||
<li>das Bestehen eines Rechts auf Berichtigung oder Löschung der sie betreffenden personenbezogenen Daten oder auf Einschränkung der Verarbeitung durch den Verantwortlichen oder eines Widerspruchsrechts gegen diese Verarbeitung</li>
|
||||
<li>das Bestehen eines Beschwerderechts bei einer Aufsichtsbehörde</li>
|
||||
<li>wenn die personenbezogenen Daten nicht bei der betroffenen Person erhoben werden: Alle verfügbaren Informationen über die Herkunft der Daten</li>
|
||||
<li>das Bestehen einer automatisierten Entscheidungsfindung einschließlich Profiling gemäß Artikel 22 Abs.1 und 4 DS-GVO und — zumindest in diesen Fällen — aussagekräftige Informationen über die involvierte Logik sowie die Tragweite und die angestrebten Auswirkungen einer derartigen Verarbeitung für die betroffene Person</li>
|
||||
|
||||
</ul>
|
||||
<p>Ferner steht der betroffenen Person ein Auskunftsrecht darüber zu, ob personenbezogene Daten an ein Drittland oder an eine internationale Organisation übermittelt wurden. Sofern dies der Fall ist, so steht der betroffenen Person im Übrigen das Recht zu, Auskunft über die geeigneten Garantien im Zusammenhang mit der Übermittlung zu erhalten.</p>
|
||||
|
||||
<p>Möchte eine betroffene Person dieses Auskunftsrecht in Anspruch nehmen, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden.</p>
|
||||
</li>
|
||||
<li><h4>c) Recht auf Berichtigung</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, die unverzügliche Berichtigung sie betreffender unrichtiger personenbezogener Daten zu verlangen. Ferner steht der betroffenen Person das Recht zu, unter Berücksichtigung der Zwecke der Verarbeitung, die Vervollständigung unvollständiger personenbezogener Daten — auch mittels einer ergänzenden Erklärung — zu verlangen.</p>
|
||||
|
||||
<p>Möchte eine betroffene Person dieses Berichtigungsrecht in Anspruch nehmen, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden.</p></li>
|
||||
<li>
|
||||
<h4>d) Recht auf Löschung (Recht auf Vergessen werden)</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, von dem Verantwortlichen zu verlangen, dass die sie betreffenden personenbezogenen Daten unverzüglich gelöscht werden, sofern einer der folgenden Gründe zutrifft und soweit die Verarbeitung nicht erforderlich ist:</p>
|
||||
|
||||
<ul style="list-style: none;">
|
||||
<li>Die personenbezogenen Daten wurden für solche Zwecke erhoben oder auf sonstige Weise verarbeitet, für welche sie nicht mehr notwendig sind.</li>
|
||||
<li>Die betroffene Person widerruft ihre Einwilligung, auf die sich die Verarbeitung gemäß Art. 6 Abs. 1 Buchstabe a DS-GVO oder Art. 9 Abs. 2 Buchstabe a DS-GVO stützte, und es fehlt an einer anderweitigen Rechtsgrundlage für die Verarbeitung.</li>
|
||||
<li>Die betroffene Person legt gemäß Art. 21 Abs. 1 DS-GVO Widerspruch gegen die Verarbeitung ein, und es liegen keine vorrangigen berechtigten Gründe für die Verarbeitung vor, oder die betroffene Person legt gemäß Art. 21 Abs. 2 DS-GVO Widerspruch gegen die Verarbeitung ein.</li>
|
||||
<li>Die personenbezogenen Daten wurden unrechtmäßig verarbeitet.</li>
|
||||
<li>Die Löschung der personenbezogenen Daten ist zur Erfüllung einer rechtlichen Verpflichtung nach dem Unionsrecht oder dem Recht der Mitgliedstaaten erforderlich, dem der Verantwortliche unterliegt.</li>
|
||||
<li>Die personenbezogenen Daten wurden in Bezug auf angebotene Dienste der Informationsgesellschaft gemäß Art. 8 Abs. 1 DS-GVO erhoben.</li>
|
||||
|
||||
</ul>
|
||||
<p>Sofern einer der oben genannten Gründe zutrifft und eine betroffene Person die Löschung von personenbezogenen Daten, die bei der Urban Exploration Ltd gespeichert sind, veranlassen möchte, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden. Der Mitarbeiter der Urban Exploration Ltd wird veranlassen, dass dem Löschverlangen unverzüglich nachgekommen wird.</p>
|
||||
|
||||
<p>Wurden die personenbezogenen Daten von der Urban Exploration Ltd öffentlich gemacht und ist unser Unternehmen als Verantwortlicher gemäß Art. 17 Abs. 1 DS-GVO zur Löschung der personenbezogenen Daten verpflichtet, so trifft die Urban Exploration Ltd unter Berücksichtigung der verfügbaren Technologie und der Implementierungskosten angemessene Maßnahmen, auch technischer Art, um andere für die Datenverarbeitung Verantwortliche, welche die veröffentlichten personenbezogenen Daten verarbeiten, darüber in Kenntnis zu setzen, dass die betroffene Person von diesen anderen für die Datenverarbeitung Verantwortlichen die Löschung sämtlicher Links zu diesen personenbezogenen Daten oder von Kopien oder Replikationen dieser personenbezogenen Daten verlangt hat, soweit die Verarbeitung nicht erforderlich ist. Der Mitarbeiter der Urban Exploration Ltd wird im Einzelfall das Notwendige veranlassen.</p>
|
||||
</li>
|
||||
<li><h4>e) Recht auf Einschränkung der Verarbeitung</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, von dem Verantwortlichen die Einschränkung der Verarbeitung zu verlangen, wenn eine der folgenden Voraussetzungen gegeben ist:</p>
|
||||
|
||||
<ul style="list-style: none;">
|
||||
<li>Die Richtigkeit der personenbezogenen Daten wird von der betroffenen Person bestritten, und zwar für eine Dauer, die es dem Verantwortlichen ermöglicht, die Richtigkeit der personenbezogenen Daten zu überprüfen.</li>
|
||||
<li>Die Verarbeitung ist unrechtmäßig, die betroffene Person lehnt die Löschung der personenbezogenen Daten ab und verlangt stattdessen die Einschränkung der Nutzung der personenbezogenen Daten.</li>
|
||||
<li>Der Verantwortliche benötigt die personenbezogenen Daten für die Zwecke der Verarbeitung nicht länger, die betroffene Person benötigt sie jedoch zur Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen.</li>
|
||||
<li>Die betroffene Person hat Widerspruch gegen die Verarbeitung gem. Art. 21 Abs. 1 DS-GVO eingelegt und es steht noch nicht fest, ob die berechtigten Gründe des Verantwortlichen gegenüber denen der betroffenen Person überwiegen.</li>
|
||||
|
||||
</ul>
|
||||
<p>Sofern eine der oben genannten Voraussetzungen gegeben ist und eine betroffene Person die Einschränkung von personenbezogenen Daten, die bei der Urban Exploration Ltd gespeichert sind, verlangen möchte, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden. Der Mitarbeiter der Urban Exploration Ltd wird die Einschränkung der Verarbeitung veranlassen.</p>
|
||||
</li>
|
||||
<li><h4>f) Recht auf Datenübertragbarkeit</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, die sie betreffenden personenbezogenen Daten, welche durch die betroffene Person einem Verantwortlichen bereitgestellt wurden, in einem strukturierten, gängigen und maschinenlesbaren Format zu erhalten. Sie hat außerdem das Recht, diese Daten einem anderen Verantwortlichen ohne Behinderung durch den Verantwortlichen, dem die personenbezogenen Daten bereitgestellt wurden, zu übermitteln, sofern die Verarbeitung auf der Einwilligung gemäß Art. 6 Abs. 1 Buchstabe a DS-GVO oder Art. 9 Abs. 2 Buchstabe a DS-GVO oder auf einem Vertrag gemäß Art. 6 Abs. 1 Buchstabe b DS-GVO beruht und die Verarbeitung mithilfe automatisierter Verfahren erfolgt, sofern die Verarbeitung nicht für die Wahrnehmung einer Aufgabe erforderlich ist, die im öffentlichen Interesse liegt oder in Ausübung öffentlicher Gewalt erfolgt, welche dem Verantwortlichen übertragen wurde.</p>
|
||||
|
||||
<p>Ferner hat die betroffene Person bei der Ausübung ihres Rechts auf Datenübertragbarkeit gemäß Art. 20 Abs. 1 DS-GVO das Recht, zu erwirken, dass die personenbezogenen Daten direkt von einem Verantwortlichen an einen anderen Verantwortlichen übermittelt werden, soweit dies technisch machbar ist und sofern hiervon nicht die Rechte und Freiheiten anderer Personen beeinträchtigt werden.</p>
|
||||
|
||||
<p>Zur Geltendmachung des Rechts auf Datenübertragbarkeit kann sich die betroffene Person jederzeit an einen Mitarbeiter der Urban Exploration Ltd wenden.</p>
|
||||
|
||||
</li>
|
||||
<li>
|
||||
<h4>g) Recht auf Widerspruch</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, aus Gründen, die sich aus ihrer besonderen Situation ergeben, jederzeit gegen die Verarbeitung sie betreffender personenbezogener Daten, die aufgrund von Art. 6 Abs. 1 Buchstaben e oder f DS-GVO erfolgt, Widerspruch einzulegen. Dies gilt auch für ein auf diese Bestimmungen gestütztes Profiling.</p>
|
||||
|
||||
<p>Die Urban Exploration Ltd verarbeitet die personenbezogenen Daten im Falle des Widerspruchs nicht mehr, es sei denn, wir können zwingende schutzwürdige Gründe für die Verarbeitung nachweisen, die den Interessen, Rechten und Freiheiten der betroffenen Person überwiegen, oder die Verarbeitung dient der Geltendmachung, Ausübung oder Verteidigung von Rechtsansprüchen.</p>
|
||||
|
||||
<p>Verarbeitet die Urban Exploration Ltd personenbezogene Daten, um Direktwerbung zu betreiben, so hat die betroffene Person das Recht, jederzeit Widerspruch gegen die Verarbeitung der personenbezogenen Daten zum Zwecke derartiger Werbung einzulegen. Dies gilt auch für das Profiling, soweit es mit solcher Direktwerbung in Verbindung steht. Widerspricht die betroffene Person gegenüber der Urban Exploration Ltd der Verarbeitung für Zwecke der Direktwerbung, so wird die Urban Exploration Ltd die personenbezogenen Daten nicht mehr für diese Zwecke verarbeiten.</p>
|
||||
|
||||
<p>Zudem hat die betroffene Person das Recht, aus Gründen, die sich aus ihrer besonderen Situation ergeben, gegen die sie betreffende Verarbeitung personenbezogener Daten, die bei der Urban Exploration Ltd zu wissenschaftlichen oder historischen Forschungszwecken oder zu statistischen Zwecken gemäß Art. 89 Abs. 1 DS-GVO erfolgen, Widerspruch einzulegen, es sei denn, eine solche Verarbeitung ist zur Erfüllung einer im öffentlichen Interesse liegenden Aufgabe erforderlich.</p>
|
||||
|
||||
<p>Zur Ausübung des Rechts auf Widerspruch kann sich die betroffene Person direkt an jeden Mitarbeiter der Urban Exploration Ltd oder einen anderen Mitarbeiter wenden. Der betroffenen Person steht es ferner frei, im Zusammenhang mit der Nutzung von Diensten der Informationsgesellschaft, ungeachtet der Richtlinie 2002/58/EG, ihr Widerspruchsrecht mittels automatisierter Verfahren auszuüben, bei denen technische Spezifikationen verwendet werden.</p>
|
||||
</li>
|
||||
<li><h4>h) Automatisierte Entscheidungen im Einzelfall einschließlich Profiling</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, nicht einer ausschließlich auf einer automatisierten Verarbeitung — einschließlich Profiling — beruhenden Entscheidung unterworfen zu werden, die ihr gegenüber rechtliche Wirkung entfaltet oder sie in ähnlicher Weise erheblich beeinträchtigt, sofern die Entscheidung (1) nicht für den Abschluss oder die Erfüllung eines Vertrags zwischen der betroffenen Person und dem Verantwortlichen erforderlich ist, oder (2) aufgrund von Rechtsvorschriften der Union oder der Mitgliedstaaten, denen der Verantwortliche unterliegt, zulässig ist und diese Rechtsvorschriften angemessene Maßnahmen zur Wahrung der Rechte und Freiheiten sowie der berechtigten Interessen der betroffenen Person enthalten oder (3) mit ausdrücklicher Einwilligung der betroffenen Person erfolgt.</p>
|
||||
|
||||
<p>Ist die Entscheidung (1) für den Abschluss oder die Erfüllung eines Vertrags zwischen der betroffenen Person und dem Verantwortlichen erforderlich oder (2) erfolgt sie mit ausdrücklicher Einwilligung der betroffenen Person, trifft die Urban Exploration Ltd angemessene Maßnahmen, um die Rechte und Freiheiten sowie die berechtigten Interessen der betroffenen Person zu wahren, wozu mindestens das Recht auf Erwirkung des Eingreifens einer Person seitens des Verantwortlichen, auf Darlegung des eigenen Standpunkts und auf Anfechtung der Entscheidung gehört.</p>
|
||||
|
||||
<p>Möchte die betroffene Person Rechte mit Bezug auf automatisierte Entscheidungen geltend machen, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden.</p>
|
||||
|
||||
</li>
|
||||
<li><h4>i) Recht auf Widerruf einer datenschutzrechtlichen Einwilligung</h4>
|
||||
<p>Jede von der Verarbeitung personenbezogener Daten betroffene Person hat das vom Europäischen Richtlinien- und Verordnungsgeber gewährte Recht, eine Einwilligung zur Verarbeitung personenbezogener Daten jederzeit zu widerrufen.</p>
|
||||
|
||||
<p>Möchte die betroffene Person ihr Recht auf Widerruf einer Einwilligung geltend machen, kann sie sich hierzu jederzeit an einen Mitarbeiter des für die Verarbeitung Verantwortlichen wenden.</p>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
<h4>7. Datenschutzbestimmungen zu Einsatz und Verwendung von Facebook</h4>
|
||||
<p>Der für die Verarbeitung Verantwortliche hat auf dieser Internetseite Komponenten des Unternehmens Facebook integriert. Facebook ist ein soziales Netzwerk.</p>
|
||||
|
||||
<p>Ein soziales Netzwerk ist ein im Internet betriebener sozialer Treffpunkt, eine Online-Gemeinschaft, die es den Nutzern in der Regel ermöglicht, untereinander zu kommunizieren und im virtuellen Raum zu interagieren. Ein soziales Netzwerk kann als Plattform zum Austausch von Meinungen und Erfahrungen dienen oder ermöglicht es der Internetgemeinschaft, persönliche oder unternehmensbezogene Informationen bereitzustellen. Facebook ermöglicht den Nutzern des sozialen Netzwerkes unter anderem die Erstellung von privaten Profilen, den Upload von Fotos und eine Vernetzung über Freundschaftsanfragen.</p>
|
||||
|
||||
<p>Betreibergesellschaft von Facebook ist die Facebook, Inc., 1 Hacker Way, Menlo Park, CA 94025, USA. Für die Verarbeitung personenbezogener Daten Verantwortlicher ist, wenn eine betroffene Person außerhalb der USA oder Kanada lebt, die Facebook Ireland Ltd., 4 Grand Canal Square, Grand Canal Harbour, Dublin 2, Ireland.</p>
|
||||
|
||||
<p>Durch jeden Aufruf einer der Einzelseiten dieser Internetseite, die durch den für die Verarbeitung Verantwortlichen betrieben wird und auf welcher eine Facebook-Komponente (Facebook-Plug-In) integriert wurde, wird der Internetbrowser auf dem informationstechnologischen System der betroffenen Person automatisch durch die jeweilige Facebook-Komponente veranlasst, eine Darstellung der entsprechenden Facebook-Komponente von Facebook herunterzuladen. Eine Gesamtübersicht über alle Facebook-Plug-Ins kann unter https://developers.facebook.com/docs/plugins/?locale=de_DE abgerufen werden. Im Rahmen dieses technischen Verfahrens erhält Facebook Kenntnis darüber, welche konkrete Unterseite unserer Internetseite durch die betroffene Person besucht wird.</p>
|
||||
|
||||
<p>Sofern die betroffene Person gleichzeitig bei Facebook eingeloggt ist, erkennt Facebook mit jedem Aufruf unserer Internetseite durch die betroffene Person und während der gesamten Dauer des jeweiligen Aufenthaltes auf unserer Internetseite, welche konkrete Unterseite unserer Internetseite die betroffene Person besucht. Diese Informationen werden durch die Facebook-Komponente gesammelt und durch Facebook dem jeweiligen Facebook-Account der betroffenen Person zugeordnet. Betätigt die betroffene Person einen der auf unserer Internetseite integrierten Facebook-Buttons, beispielsweise den „Gefällt mir“-Button, oder gibt die betroffene Person einen Kommentar ab, ordnet Facebook diese Information dem persönlichen Facebook-Benutzerkonto der betroffenen Person zu und speichert diese personenbezogenen Daten.</p>
|
||||
|
||||
<p>Facebook erhält über die Facebook-Komponente immer dann eine Information darüber, dass die betroffene Person unsere Internetseite besucht hat, wenn die betroffene Person zum Zeitpunkt des Aufrufs unserer Internetseite gleichzeitig bei Facebook eingeloggt ist; dies findet unabhängig davon statt, ob die betroffene Person die Facebook-Komponente anklickt oder nicht. Ist eine derartige Übermittlung dieser Informationen an Facebook von der betroffenen Person nicht gewollt, kann diese die Übermittlung dadurch verhindern, dass sie sich vor einem Aufruf unserer Internetseite aus ihrem Facebook-Account ausloggt.</p>
|
||||
|
||||
<p>Die von Facebook veröffentlichte Datenrichtlinie, die unter https://de-de.facebook.com/about/privacy/ abrufbar ist, gibt Aufschluss über die Erhebung, Verarbeitung und Nutzung personenbezogener Daten durch Facebook. Ferner wird dort erläutert, welche Einstellungsmöglichkeiten Facebook zum Schutz der Privatsphäre der betroffenen Person bietet. Zudem sind unterschiedliche Applikationen erhältlich, die es ermöglichen, eine Datenübermittlung an Facebook zu unterdrücken. Solche Applikationen können durch die betroffene Person genutzt werden, um eine Datenübermittlung an Facebook zu unterdrücken.</p>
|
||||
|
||||
<h4>8. Datenschutzbestimmungen zu Einsatz und Verwendung von Instagram</h4>
|
||||
<p>Der für die Verarbeitung Verantwortliche hat auf dieser Internetseite Komponenten des Dienstes Instagram integriert. Instagram ist ein Dienst, der als audiovisuelle Plattform zu qualifizieren ist und den Nutzern das Teilen von Fotos und Videos und zudem eine Weiterverbreitung solcher Daten in anderen sozialen Netzwerken ermöglicht.</p>
|
||||
|
||||
<p>Betreibergesellschaft der Dienste von Instagram ist die Facebook Ireland Ltd., 4 Grand Canal Square, Grand Canal Harbour, Dublin 2 Ireland.</p>
|
||||
|
||||
<p>Durch jeden Aufruf einer der Einzelseiten dieser Internetseite, die durch den für die Verarbeitung Verantwortlichen betrieben wird und auf welcher eine Instagram-Komponente (Insta-Button) integriert wurde, wird der Internetbrowser auf dem informationstechnologischen System der betroffenen Person automatisch durch die jeweilige Instagram-Komponente veranlasst, eine Darstellung der entsprechenden Komponente von Instagram herunterzuladen. Im Rahmen dieses technischen Verfahrens erhält Instagram Kenntnis darüber, welche konkrete Unterseite unserer Internetseite durch die betroffene Person besucht wird.</p>
|
||||
|
||||
<p>Sofern die betroffene Person gleichzeitig bei Instagram eingeloggt ist, erkennt Instagram mit jedem Aufruf unserer Internetseite durch die betroffene Person und während der gesamten Dauer des jeweiligen Aufenthaltes auf unserer Internetseite, welche konkrete Unterseite die betroffene Person besucht. Diese Informationen werden durch die Instagram-Komponente gesammelt und durch Instagram dem jeweiligen Instagram-Account der betroffenen Person zugeordnet. Betätigt die betroffene Person einen der auf unserer Internetseite integrierten Instagram-Buttons, werden die damit übertragenen Daten und Informationen dem persönlichen Instagram-Benutzerkonto der betroffenen Person zugeordnet und von Instagram gespeichert und verarbeitet.</p>
|
||||
|
||||
<p>Instagram erhält über die Instagram-Komponente immer dann eine Information darüber, dass die betroffene Person unsere Internetseite besucht hat, wenn die betroffene Person zum Zeitpunkt des Aufrufs unserer Internetseite gleichzeitig bei Instagram eingeloggt ist; dies findet unabhängig davon statt, ob die betroffene Person die Instagram-Komponente anklickt oder nicht. Ist eine derartige Übermittlung dieser Informationen an Instagram von der betroffenen Person nicht gewollt, kann diese die Übermittlung dadurch verhindern, dass sie sich vor einem Aufruf unserer Internetseite aus ihrem Instagram-Account ausloggt.</p>
|
||||
|
||||
<p>Weitere Informationen und die geltenden Datenschutzbestimmungen von Instagram können unter https://help.instagram.com/155833707900388 und https://www.instagram.com/about/legal/privacy/ abgerufen werden.</p>
|
||||
|
||||
<h4>9. Datenschutzbestimmungen zu Einsatz und Verwendung von Twitter</h4>
|
||||
<p>Der für die Verarbeitung Verantwortliche hat auf dieser Internetseite Komponenten von Twitter integriert. Twitter ist ein multilingualer öffentlich zugänglicher Mikroblogging-Dienst, auf welchem die Nutzer sogenannte Tweets, also Kurznachrichten, die auf 280 Zeichen begrenzt sind, veröffentlichen und verbreiten können. Diese Kurznachrichten sind für jedermann, also auch für nicht bei Twitter angemeldete Personen abrufbar. Die Tweets werden aber auch den sogenannten Followern des jeweiligen Nutzers angezeigt. Follower sind andere Twitter-Nutzer, die den Tweets eines Nutzers folgen. Ferner ermöglicht Twitter über Hashtags, Verlinkungen oder Retweets die Ansprache eines breiten Publikums.</p>
|
||||
|
||||
<p>Betreibergesellschaft von Twitter International Company, One Cumberland Place, Fenian Street Dublin 2, D02 AX07, Ireland.</p>
|
||||
|
||||
<p>Durch jeden Aufruf einer der Einzelseiten dieser Internetseite, die durch den für die Verarbeitung Verantwortlichen betrieben wird und auf welcher eine Twitter-Komponente (Twitter-Button) integriert wurde, wird der Internetbrowser auf dem informationstechnologischen System der betroffenen Person automatisch durch die jeweilige Twitter-Komponente veranlasst, eine Darstellung der entsprechenden Twitter-Komponente von Twitter herunterzuladen. Weitere Informationen zu den Twitter-Buttons sind unter https://about.twitter.com/de/resources/buttons abrufbar. Im Rahmen dieses technischen Verfahrens erhält Twitter Kenntnis darüber, welche konkrete Unterseite unserer Internetseite durch die betroffene Person besucht wird. Zweck der Integration der Twitter-Komponente ist es, unseren Nutzern eine Weiterverbreitung der Inhalte diese Internetseite zu ermöglichen, diese Internetseite in der digitalen Welt bekannt zu machen und unsere Besucherzahlen zu erhöhen.</p>
|
||||
|
||||
<p>Sofern die betroffene Person gleichzeitig bei Twitter eingeloggt ist, erkennt Twitter mit jedem Aufruf unserer Internetseite durch die betroffene Person und während der gesamten Dauer des jeweiligen Aufenthaltes auf unserer Internetseite, welche konkrete Unterseite unserer Internetseite die betroffene Person besucht. Diese Informationen werden durch die Twitter-Komponente gesammelt und durch Twitter dem jeweiligen Twitter-Account der betroffenen Person zugeordnet. Betätigt die betroffene Person einen der auf unserer Internetseite integrierten Twitter-Buttons, werden die damit übertragenen Daten und Informationen dem persönlichen Twitter-Benutzerkonto der betroffenen Person zugeordnet und von Twitter gespeichert und verarbeitet.</p>
|
||||
|
||||
<p>Twitter erhält über die Twitter-Komponente immer dann eine Information darüber, dass die betroffene Person unsere Internetseite besucht hat, wenn die betroffene Person zum Zeitpunkt des Aufrufs unserer Internetseite gleichzeitig bei Twitter eingeloggt ist; dies findet unabhängig davon statt, ob die betroffene Person die Twitter-Komponente anklickt oder nicht. Ist eine derartige Übermittlung dieser Informationen an Twitter von der betroffenen Person nicht gewollt, kann diese die Übermittlung dadurch verhindern, dass sie sich vor einem Aufruf unserer Internetseite aus ihrem Twitter-Account ausloggt.</p>
|
||||
|
||||
<p>Die geltenden Datenschutzbestimmungen von Twitter sind unter https://twitter.com/privacy?lang=de abrufbar.</p>
|
||||
|
||||
<h4>10. Datenschutzbestimmungen zu Einsatz und Verwendung von YouTube</h4>
|
||||
<p>Der für die Verarbeitung Verantwortliche hat auf dieser Internetseite Komponenten von YouTube integriert. YouTube ist ein Internet-Videoportal, dass Video-Publishern das kostenlose Einstellen von Videoclips und anderen Nutzern die ebenfalls kostenfreie Betrachtung, Bewertung und Kommentierung dieser ermöglicht. YouTube gestattet die Publikation aller Arten von Videos, weshalb sowohl komplette Film- und Fernsehsendungen, aber auch Musikvideos, Trailer oder von Nutzern selbst angefertigte Videos über das Internetportal abrufbar sind.</p>
|
||||
|
||||
<p>Betreibergesellschaft von YouTube ist die Google Ireland Limited, Gordon House, Barrow Street, Dublin, D04 E5W5, Ireland.</p>
|
||||
|
||||
<p>Durch jeden Aufruf einer der Einzelseiten dieser Internetseite, die durch den für die Verarbeitung Verantwortlichen betrieben wird und auf welcher eine YouTube-Komponente (YouTube-Video) integriert wurde, wird der Internetbrowser auf dem informationstechnologischen System der betroffenen Person automatisch durch die jeweilige YouTube-Komponente veranlasst, eine Darstellung der entsprechenden YouTube-Komponente von YouTube herunterzuladen. Weitere Informationen zu YouTube können unter https://www.youtube.com/yt/about/de/ abgerufen werden. Im Rahmen dieses technischen Verfahrens erhalten YouTube und Google Kenntnis darüber, welche konkrete Unterseite unserer Internetseite durch die betroffene Person besucht wird.</p>
|
||||
|
||||
<p>Sofern die betroffene Person gleichzeitig bei YouTube eingeloggt ist, erkennt YouTube mit dem Aufruf einer Unterseite, die ein YouTube-Video enthält, welche konkrete Unterseite unserer Internetseite die betroffene Person besucht. Diese Informationen werden durch YouTube und Google gesammelt und dem jeweiligen YouTube-Account der betroffenen Person zugeordnet.</p>
|
||||
|
||||
<p>YouTube und Google erhalten über die YouTube-Komponente immer dann eine Information darüber, dass die betroffene Person unsere Internetseite besucht hat, wenn die betroffene Person zum Zeitpunkt des Aufrufs unserer Internetseite gleichzeitig bei YouTube eingeloggt ist; dies findet unabhängig davon statt, ob die betroffene Person ein YouTube-Video anklickt oder nicht. Ist eine derartige Übermittlung dieser Informationen an YouTube und Google von der betroffenen Person nicht gewollt, kann diese die Übermittlung dadurch verhindern, dass sie sich vor einem Aufruf unserer Internetseite aus ihrem YouTube-Account ausloggt.</p>
|
||||
|
||||
<p>Die von YouTube veröffentlichten Datenschutzbestimmungen, die unter https://www.google.de/intl/de/policies/privacy/ abrufbar sind, geben Aufschluss über die Erhebung, Verarbeitung und Nutzung personenbezogener Daten durch YouTube und Google.</p>
|
||||
|
||||
<h4>11. Rechtsgrundlage der Verarbeitung</h4>
|
||||
<p>Art. 6 I lit. a DS-GVO dient unserem Unternehmen als Rechtsgrundlage für Verarbeitungsvorgänge, bei denen wir eine Einwilligung für einen bestimmten Verarbeitungszweck einholen. Ist die Verarbeitung personenbezogener Daten zur Erfüllung eines Vertrags, dessen Vertragspartei die betroffene Person ist, erforderlich, wie dies beispielsweise bei Verarbeitungsvorgängen der Fall ist, die für eine Lieferung von Waren oder die Erbringung einer sonstigen Leistung oder Gegenleistung notwendig sind, so beruht die Verarbeitung auf Art. 6 I lit. b DS-GVO. Gleiches gilt für solche Verarbeitungsvorgänge die zur Durchführung vorvertraglicher Maßnahmen erforderlich sind, etwa in Fällen von Anfragen zur unseren Produkten oder Leistungen. Unterliegt unser Unternehmen einer rechtlichen Verpflichtung durch welche eine Verarbeitung von personenbezogenen Daten erforderlich wird, wie beispielsweise zur Erfüllung steuerlicher Pflichten, so basiert die Verarbeitung auf Art. 6 I lit. c DS-GVO. In seltenen Fällen könnte die Verarbeitung von personenbezogenen Daten erforderlich werden, um lebenswichtige Interessen der betroffenen Person oder einer anderen natürlichen Person zu schützen. Dies wäre beispielsweise der Fall, wenn ein Besucher in unserem Betrieb verletzt werden würde und daraufhin sein Name, sein Alter, seine Krankenkassendaten oder sonstige lebenswichtige Informationen an einen Arzt, ein Krankenhaus oder sonstige Dritte weitergegeben werden müssten. Dann würde die Verarbeitung auf Art. 6 I lit. d DS-GVO beruhen.
|
||||
Letztlich könnten Verarbeitungsvorgänge auf Art. 6 I lit. f DS-GVO beruhen. Auf dieser Rechtsgrundlage basieren Verarbeitungsvorgänge, die von keiner der vorgenannten Rechtsgrundlagen erfasst werden, wenn die Verarbeitung zur Wahrung eines berechtigten Interesses unseres Unternehmens oder eines Dritten erforderlich ist, sofern die Interessen, Grundrechte und Grundfreiheiten des Betroffenen nicht überwiegen. Solche Verarbeitungsvorgänge sind uns insbesondere deshalb gestattet, weil sie durch den Europäischen Gesetzgeber besonders erwähnt wurden. Er vertrat insoweit die Auffassung, dass ein berechtigtes Interesse anzunehmen sein könnte, wenn die betroffene Person ein Kunde des Verantwortlichen ist (Erwägungsgrund 47 Satz 2 DS-GVO).
|
||||
</p>
|
||||
|
||||
<h4>12. Berechtigte Interessen an der Verarbeitung, die von dem Verantwortlichen oder einem Dritten verfolgt werden</h4>
|
||||
<p>Basiert die Verarbeitung personenbezogener Daten auf Artikel 6 I lit. f DS-GVO ist unser berechtigtes Interesse die Durchführung unserer Geschäftstätigkeit zugunsten des Wohlergehens all unserer Mitarbeiter und unserer Anteilseigner.</p>
|
||||
|
||||
<h4>13. Dauer, für die die personenbezogenen Daten gespeichert werden</h4>
|
||||
<p>Das Kriterium für die Dauer der Speicherung von personenbezogenen Daten ist die jeweilige gesetzliche Aufbewahrungsfrist. Nach Ablauf der Frist werden die entsprechenden Daten routinemäßig gelöscht, sofern sie nicht mehr zur Vertragserfüllung oder Vertragsanbahnung erforderlich sind.</p>
|
||||
|
||||
<h4>14. Gesetzliche oder vertragliche Vorschriften zur Bereitstellung der personenbezogenen Daten; Erforderlichkeit für den Vertragsabschluss; Verpflichtung der betroffenen Person, die personenbezogenen Daten bereitzustellen; mögliche Folgen der Nichtbereitstellung</h4>
|
||||
<p>Wir klären Sie darüber auf, dass die Bereitstellung personenbezogener Daten zum Teil gesetzlich vorgeschrieben ist (z.B. Steuervorschriften) oder sich auch aus vertraglichen Regelungen (z.B. Angaben zum Vertragspartner) ergeben kann.
|
||||
Mitunter kann es zu einem Vertragsschluss erforderlich sein, dass eine betroffene Person uns personenbezogene Daten zur Verfügung stellt, die in der Folge durch uns verarbeitet werden müssen. Die betroffene Person ist beispielsweise verpflichtet uns personenbezogene Daten bereitzustellen, wenn unser Unternehmen mit ihr einen Vertrag abschließt. Eine Nichtbereitstellung der personenbezogenen Daten hätte zur Folge, dass der Vertrag mit dem Betroffenen nicht geschlossen werden könnte.
|
||||
Vor einer Bereitstellung personenbezogener Daten durch den Betroffenen muss sich der Betroffene an einen unserer Mitarbeiter wenden. Unser Mitarbeiter klärt den Betroffenen einzelfallbezogen darüber auf, ob die Bereitstellung der personenbezogenen Daten gesetzlich oder vertraglich vorgeschrieben oder für den Vertragsabschluss erforderlich ist, ob eine Verpflichtung besteht, die personenbezogenen Daten bereitzustellen, und welche Folgen die Nichtbereitstellung der personenbezogenen Daten hätte.
|
||||
</p>
|
||||
|
||||
<h4>15. Bestehen einer automatisierten Entscheidungsfindung</h4>
|
||||
<p>Als verantwortungsbewusstes Unternehmen verzichten wir auf eine automatische Entscheidungsfindung oder ein Profiling.</p>
|
||||
|
||||
<p>Diese Datenschutzerklärung wurde durch den <a href="https://dsgvo-muster-datenschutzerklaerung.dg-datenschutz.de/">Datenschutzerklärungs-Generator</a> der Deutschen Gesellschaft für Datenschutz, in Kooperation mit den <a href="https://www.wbs-law.de/taetigkeitsgebiete/medienrecht/">Medienrecht</a> Anwälten WILDE BEUGER SOLMECKE | Rechtsanwälte erstellt.
|
||||
</p>
|
||||
|
||||
{% endblock maincontent %}
|
94
django_lostplaces/lostplaces/templates/global.html
Normal file
@@ -0,0 +1,94 @@
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
{% block additional_head %}
|
||||
{% endblock additional_head %}
|
||||
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="{% static 'main.css' %}">
|
||||
<link rel="icon" type="image/png" href="{% static 'favicon.ico' %}">
|
||||
<title>
|
||||
{% block title %}Urban Exploration{% endblock %}
|
||||
</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="LP-Wrapper__Site">
|
||||
<header class="LP-Header">
|
||||
<div class="LP-Header__Logo">
|
||||
<a class="LP-Link" href="/">
|
||||
<img src="{% static 'logo.png' %}" class="LP-Image" />
|
||||
</a>
|
||||
</div>
|
||||
<div class="LP-Header__UserInformation">
|
||||
<span class="LP-Paragraph">
|
||||
{% if user.is_authenticated %}
|
||||
Hi {{ user.username }}!
|
||||
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">{% trans 'Logout' %}</span></a>
|
||||
{% if user.is_superuser %}
|
||||
<a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">{% trans 'Admin' %}</span></a>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
You are not logged in.
|
||||
<a class="LP-Link" href="{% url 'login' %}"><span class="LP-Link__Text">{% trans 'Login' %}</span></a> |
|
||||
<a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign Up' %}</span></a>
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
</header>
|
||||
<input id="toggle_sidebar" class="LP-Menu__Trigger" type="checkbox" />
|
||||
<label id="toggle_sidebar_label" for="toggle_sidebar" class="LP-Menu__TriggerLabel"></label>
|
||||
<aside class="LP-Main__Sidebar">
|
||||
<nav class="LP-Menu LP-Menu--sidebar">
|
||||
<ul class="LP-Menu__List">
|
||||
<li class="LP-Menu__Item"><a href="{% url 'lostplaces_home' %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Home' %}</span></a></li>
|
||||
<li class="LP-Menu__Item"><a href="{% url 'flatpage' slug='codex' %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'UrBex Codex' %}</span></a></li>
|
||||
|
||||
{% block additional_menu_items %}
|
||||
{% endblock additional_menu_items %}
|
||||
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_create'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Create Place' %}</span></a></li>
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_list'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'All Places' %}</span></a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</aside>
|
||||
<main class="LP-Main__Content">
|
||||
{% if messages %}
|
||||
<div class="LP-MessageList">
|
||||
<ul class="LP-MessageList__List">
|
||||
{% for message in messages %}
|
||||
<li class="LP-MessageList__Item">
|
||||
<div class="LP-Message {% if message.tags %}LP-Message--{{ message.tags }}{% endif %}">
|
||||
<div>
|
||||
<div class="LP-Message__Icon">
|
||||
</div>
|
||||
</div>
|
||||
<div class="LP-Message__Text">
|
||||
{{ message }}
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% block maincontent %}
|
||||
{% endblock maincontent %}
|
||||
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{% block footer %}
|
||||
{% include 'partials/nav/footer.html' %}
|
||||
{% endblock footer %}
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@@ -1,12 +1,13 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% block additional_head %}
|
||||
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
|
||||
<script src="{% static 'maps/ol.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
|
||||
<script src="{% static 'maps/ol.js' %}"></script>
|
||||
{% endblock additional_head %}
|
||||
|
||||
# {% block title %}Start{% endblock %}
|
||||
# {% block title %}{% trans 'Home' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
@@ -14,16 +15,16 @@
|
||||
<article class="LP-TextSection">
|
||||
</article>
|
||||
|
||||
{% include 'partials/osm_map.html' %}
|
||||
{% include 'partials/osm_map.html' with config=mapping_config %}
|
||||
<div class="LP-PlaceGrid">
|
||||
<h1 class="LP-Headline LP-Headline">Explore the latest locations</h1>
|
||||
<h1 class="LP-Headline LP-Headline">{% trans 'Explore the latest places' %}</h1>
|
||||
<ul class="LP-PlaceGrid__Grid">
|
||||
{% for place in place_list %}
|
||||
<li class="LP-PlaceGrid__Item">
|
||||
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
||||
<article class="LP-PlaceTeaser">
|
||||
<div class="LP-PlaceTeaser__Image">
|
||||
<img class="LP-Image" src="{{ place.images.first.filename.thumbnail.url}}" />
|
||||
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
|
||||
</div>
|
||||
<div class="LP-PlaceTeaser__Meta">
|
||||
<div class="LP-PlaceTeaser__Info">
|
43
django_lostplaces/lostplaces/templates/home_unauth.html
Normal file
@@ -0,0 +1,43 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load i18n %}
|
||||
|
||||
# {% block title %}Start{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
{% include 'partials/welcome.html' %}
|
||||
<article class="LP-TextSection">
|
||||
<p class="LP-Paragraph">
|
||||
{% blocktrans %}You can create, view and share your lost places with other members of this site. You can upload photos, place links to your web galleries and contribute your knowledge by tagging other places or commenting on them. You will find detailed information on where these locations are, how to get there and what to expect from them. This might even include detailed information on the surroundings or the history of a lost place.{% endblocktrans %}
|
||||
</p>
|
||||
{% url 'signup' as signup_url %}
|
||||
<p class="LP-Paragraph">
|
||||
{% blocktrans %}Since vandalism is a growing problem these days, no sensitive information is available to the public. You have to <a class="LP-Link" href="{{signup_url}}"><span class="LP-Link__Text">sign up</span></a> with a voucher code as an invitation to join this community. Only admins can create these codes. Usually you are given a code when we know you in real life in person and when we trust you. A request from an unknown person will most probably be denied.{% endblocktrans %}
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<div class="LP-PlaceGrid">
|
||||
<h1 class="LP-Headline LP-Headline">{% trans 'Explore the latest places' %}</h1>
|
||||
<ul class="LP-PlaceGrid__Grid">
|
||||
{% for place in place_list %}
|
||||
<li class="LP-PlaceGrid__Item">
|
||||
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
||||
<article class="LP-PlaceTeaser">
|
||||
<div class="LP-PlaceTeaser__Image">
|
||||
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
|
||||
</div>
|
||||
<div class="LP-PlaceTeaser__Meta">
|
||||
<div class="LP-PlaceTeaser__Info">
|
||||
<span class="LP-PlaceTeaser__Title">
|
||||
<h1 class="LP-Headline LP-Headline--teaser">{{place.name|truncatechars:19}}</h1>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% endblock maincontent %}
|
@@ -0,0 +1,9 @@
|
||||
{% load i18n %}
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<button class="LP-Button">{% if action %}{{ action }}{% else %}{% trans 'Submit' %}{% endif %}</button>
|
||||
</div>
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<a class="LP-Link" href="{% if referer %}{{ referer }}{% else %}{% url 'lostplaces_home' %}{% endif %}">
|
||||
<button type="button" class="LP-Button LP-Button--cancel">{% trans 'Cancel' %}</button>
|
||||
</a>
|
||||
</div>
|
@@ -1,3 +1,4 @@
|
||||
{% load i18n %}
|
||||
<footer class="LP-Footer">
|
||||
<div class="LP-FooterColumns__Container">
|
||||
|
||||
@@ -60,13 +61,13 @@
|
||||
<!-- Bottom section with last line of text and links. -->
|
||||
<section class="LP-Footer__BottomSection LP-Footer__Flex">
|
||||
<div class="LP-Footer__BottomWrapper">
|
||||
Proudly made by <a href="https://www.reverend.church" class="LP-Footer__GenericAnchor">Reverend</a>
|
||||
and <a href="https://www.commander1024.de" class="LP-Footer__GenericAnchor">Commander1024.</a></span>
|
||||
{% trans 'Made by' %} <a href="https://git.mowoe.com/reverend" class="LP-Footer__GenericAnchor">Reverend</a>
|
||||
{% trans 'and' %} <a href="https://www.commander1024.de" class="LP-Footer__GenericAnchor">Commander1024.</a></span>
|
||||
</div>
|
||||
<div class="LP-Footer__BottomWrapper">
|
||||
<a href="/flat/privacy-policy.html" class="LP-Footer__GenericAnchor">Privacy Policy</a>
|
||||
<a href="{% url 'flatpage' slug='privacy-policy' %}" class="LP-Footer__GenericAnchor">{% trans 'Privacy Policy' %}</a>
|
||||
|
|
||||
<a href="/flat/impress.html" class="LP-Footer__GenericAnchor">Impress</a>
|
||||
<a href="{% url 'flatpage' slug='imprint' %}" class="LP-Footer__GenericAnchor">{% trans 'Imprint' %}</a>
|
||||
</div>
|
||||
</section>
|
||||
</footer>
|
@@ -1,3 +1,4 @@
|
||||
{% load i18n %}
|
||||
{% load lostplaces %}
|
||||
|
||||
{% if is_paginated %}
|
||||
@@ -7,26 +8,26 @@
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--first">
|
||||
<a href="?page=1" class="LP-Link">
|
||||
<span class="LP-Icon">⟪</span>
|
||||
<span class="LP-Text">First</span>
|
||||
<span class="LP-Text">{% trans 'First' %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--previous">
|
||||
<a href="?page={{ page_obj.previous_page_number }}" class="LP-Link">
|
||||
<span class="LP-Icon">⟨</span>
|
||||
<span class="LP-Text">Previous</span>
|
||||
<span class="LP-Text">{% trans 'Previous' %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--first LP-Pagination__Item--disabled">
|
||||
<a href="#" class="LP-Link">
|
||||
<span class="LP-Icon">⟪</span>
|
||||
<span class="LP-Text">First</span>
|
||||
<span class="LP-Text">{% trans 'First' %}</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--previous LP-Pagination__Item--disabled">
|
||||
<a href="#" class="LP-Link">
|
||||
<span class="LP-Icon">⟨</span>
|
||||
<span class="LP-Text">Previous</span>
|
||||
<span class="LP-Text">{% trans 'Previous' %}</span>
|
||||
</a>
|
||||
</li>
|
||||
{% endif %}
|
||||
@@ -46,25 +47,25 @@
|
||||
{% if page_obj.has_next %}
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--next">
|
||||
<a href="?page={{ page_obj.next_page_number }}" class="LP-Link">
|
||||
<span class="LP-Text">Next</span>
|
||||
<span class="LP-Text">{% trans 'Next' %}</span>
|
||||
<span class="LP-Icon">⟩</span>
|
||||
</a>
|
||||
</li>
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--last">
|
||||
<a href="?page={{ page_obj.paginator.num_pages }}" class="LP-Link">
|
||||
<span class="LP-Text">Last</span>
|
||||
<span class="LP-Text">{% trans 'Last' %}</span>
|
||||
<span class="LP-Icon">⟫</span>
|
||||
</a>
|
||||
</li>
|
||||
{% else %}
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--next LP-Pagination__Item--disabled">
|
||||
<a href="#" class="LP-Link">
|
||||
<span class="LP-Text">Next</span>
|
||||
<span class="LP-Text">{% trans 'Next' %}</span>
|
||||
<span class="LP-Icon">⟩</span>
|
||||
</a>
|
||||
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--last LP-Pagination__Item--disabled">
|
||||
<a href="#" class="LP-Link">
|
||||
<span class="LP-Text">Last</span>
|
||||
<span class="LP-Text">{% trans 'Last' %}</span>
|
||||
<span class="LP-Icon">⟫</span>
|
||||
</a>
|
||||
</li>
|
@@ -1,6 +1,6 @@
|
||||
|
||||
<div id="map" class="map" style="height: 300px"></div>
|
||||
<div id="info" class="map-popup"></div>
|
||||
{% load static %}
|
||||
<div tabindex="1" id="map" class="LP-Map map" style="height: 300px"></div>
|
||||
<div id="info" class="map-popup LP-Map__Popup"></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var map = new ol.Map({
|
||||
@@ -11,20 +11,20 @@
|
||||
}),
|
||||
],
|
||||
view: new ol.View({
|
||||
center: ol.proj.fromLonLat([{{place_map_center|last}}, {{place_map_center|first}}]),
|
||||
center: ol.proj.fromLonLat([{{config.map_center.longitude|safe}}, {{config.map_center.latitude|safe}}]),
|
||||
zoom: 9
|
||||
})
|
||||
});
|
||||
|
||||
var vectorSource = new ol.source.Vector({
|
||||
features: [
|
||||
{% for place in place_list %}
|
||||
{% for point in config.all_points %}
|
||||
new ol.Feature({
|
||||
geometry: new ol.geom.Point(
|
||||
ol.proj.fromLonLat([{{place.longitude}},{{place.latitude}}])
|
||||
ol.proj.fromLonLat([{{point.longitude|safe}},{{point.latitude|safe}}])
|
||||
),
|
||||
url: '{% url 'place_detail' pk=place.pk %}',
|
||||
name: '{{place.name}}'
|
||||
url: '{{point.get_absolute_url}}',
|
||||
name: ' {{point.name}}'
|
||||
}),
|
||||
{% endfor %}
|
||||
]
|
||||
@@ -37,8 +37,8 @@
|
||||
anchor: [0.5, 46],
|
||||
anchorXUnits: 'fraction',
|
||||
anchorYUnits: 'pixels',
|
||||
scale: 0.3,
|
||||
src: 'http://icons.iconarchive.com/icons/paomedia/small-n-flat/128/map-marker-icon.png'
|
||||
scale: 0.02,
|
||||
src: '{% static "icons/map-marker-icon.png" %}'
|
||||
})
|
||||
})
|
||||
});
|
@@ -1,12 +1,14 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div class="LP-TagList">
|
||||
<ul class="LP-TagList__List">
|
||||
{% for tag in tag_list %}
|
||||
{% for tag in config.tagged_item.tags.all %}
|
||||
<li class="LP-TagList__Item">
|
||||
<div class="LP-Tag">
|
||||
<a href="#" class="LP-Link">
|
||||
<span class="LP-Link__Text">{{tag}}</span>
|
||||
</a>
|
||||
{% if request.user and request.user == config.tagged_item.submitted_by %}
|
||||
{% if request.user and request.user.explorer == config.tagged_item.submitted_by %}
|
||||
<a href="{% url config.delete_url_name tagged_id=config.tagged_item.id tag_id=tag.id %}" class="LP-Link">
|
||||
<span class="LP-Tag__Remove RV-Iconized__Container RV-Iconized__Container--extraSmall">
|
||||
<svg class="RV-Iconized__Icon" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -23,13 +25,13 @@
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form id="id_tag_submit_form" class="LP-Form LP-Form--inline LP-Form--tagging" method="POST" action="{{config.submit_url}}">
|
||||
<form id="id_tag_submit_form" class="LP-Form LP-Form--inline LP-Form--tagging" method="POST" action="{% url config.submit_url_name tagged_id=config.tagged_item.id%}">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">Tags hinzufügen</legend>
|
||||
<legend class="LP-Form__Legend">{% trans 'Add tags' %}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input LP-Input--tagging">
|
||||
<button id="id_tag_submit_button" class="LP-Button"> Tags hinzufügen</button>
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input LP-Input--tagging">
|
||||
<button id="id_tag_submit_button" class="LP-Button">{% trans 'Add tags' %}</button>
|
||||
</div>
|
||||
<div class="LP-Form__Field">
|
||||
{% include 'partials/form/inputField.html' with field=config.submit_form.tag_list classes="LP-Input--tagging" %}
|
||||
@@ -47,10 +49,10 @@
|
||||
|
||||
const tagify = new Tagify(input, {
|
||||
'whitelist': [
|
||||
{% for tag in all_tags %}
|
||||
'{{tag}}',
|
||||
{% endfor %}
|
||||
]
|
||||
{% for tag in config.all_tags %}
|
||||
'{{tag}}',
|
||||
{% endfor %}
|
||||
]
|
||||
})
|
||||
|
||||
const on_form_submit = function() {
|
21
django_lostplaces/lostplaces/templates/partials/welcome.html
Normal file
@@ -0,0 +1,21 @@
|
||||
{% load i18n %}
|
||||
|
||||
<header class="LP-TextSection__Headline">
|
||||
<h1 class="LP-Headline">{% trans 'Start' %}</h1>
|
||||
</header>
|
||||
|
||||
<div class="LP-TextSection__Text">
|
||||
<p class="LP-Paragraph">{% trans 'Welcome to our Urban Exploration community catalogue,' %}
|
||||
{% if user.is_authenticated %}
|
||||
{{ user.username }}
|
||||
{% else %}
|
||||
{% trans 'explorer' %}
|
||||
{% endif %}
|
||||
!
|
||||
</p>
|
||||
<p class="LP-Paragraph">
|
||||
{% trans 'We strictly follow our' %}
|
||||
<a class="LP-Link" href="{% url 'flatpage' slug='codex' %}"><span class="LP-Link__Text">{% trans 'UrBex codex' %}</span></a>
|
||||
{% trans 'and expect you to do so, too.' %}'
|
||||
</p>
|
||||
</div>
|
@@ -1,18 +1,19 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}Submit a photo album{% endblock %}
|
||||
{% block title %}{% trans 'Submit a photo album' %}{% endblock %}
|
||||
|
||||
{% block additional_menu_items %}
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_edit' pk=place.pk %}" class="LP-Link"><span
|
||||
class="LP-Link__Text">Edit place</span></a></li>
|
||||
class="LP-Link__Text">{% trans 'Edit place' %}</span></a></li>
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_delete' pk=place.pk %}" class="LP-Link"><span
|
||||
class="LP-Link__Text">Delete place</span></a></li>
|
||||
class="LP-Link__Text">{% trans 'Delete place' %}</span></a></li>
|
||||
{% endblock additional_menu_items %}
|
||||
|
||||
{% block maincontent %}
|
||||
<form class="LP-Form" method="POST">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">Submit a photo album for {{place.name}}</legend>
|
||||
<legend class="LP-Form__Legend">{% trans 'Submit a photo album for' %} {{place.name}}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition">
|
||||
<div class="LP-Form__Field">
|
||||
@@ -27,14 +28,7 @@
|
||||
</div>
|
||||
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<button class="LP-Button">Submit</button>
|
||||
</div>
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<a class="LP-Link" href="{% url 'place_detail' pk=place.id%}">
|
||||
<button type="button" class="LP-Button LP-Button--cancel">Cancel</button>
|
||||
</a>
|
||||
</div>
|
||||
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER %}
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
@@ -1,12 +1,13 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
# {% block title %}Place erstellen{% endblock %}
|
||||
# {% block title %}{% trans 'Create Place' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">Create Place</legend>
|
||||
<legend class="LP-Form__Legend">{% trans 'Create Place' %}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||
<div class="LP-Form__Field">
|
||||
@@ -38,15 +39,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% trans 'Create' as action %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<button class="LP-Button">Create</button>
|
||||
</div>
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<a class="LP-Link" href="{% url 'place_list' %}">
|
||||
<button type="button" class="LP-Button LP-Button--cancel">Cancel</button>
|
||||
</a>
|
||||
</div>
|
||||
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER action=action %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@@ -0,0 +1,25 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans 'Lost Place Deletion' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<form class="LP-Form" method="POST">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">{% trans 'Delete place' %}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition">
|
||||
<div class="LP-Form__Field LP-Form__InfoText">
|
||||
<p class="LP-Paragraph">{% trans 'Are you sure you want to delete' %} "{{place.name}}"?</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% trans 'Delete' as action %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
{% include 'partials/form/submit.html' with referer=request.META.HTTP_REFERER action=action %}
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
{% endblock maincontent %}
|
@@ -1,24 +1,23 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load thumbnail %}
|
||||
{% load svg_icon %}
|
||||
{% load lostplaces %}
|
||||
|
||||
{% block additional_head %}
|
||||
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
|
||||
|
||||
|
||||
<script src="{% static 'maps/ol.js' %}"></script>
|
||||
|
||||
<script src="{% static 'tagify.min.js' %}"></script>
|
||||
<link rel="stylesheet" href="{% static 'minimal.css' %}" type="text/css">
|
||||
{% endblock additional_head %}
|
||||
|
||||
{% block title %}{{place.name}}{% endblock %}
|
||||
|
||||
{% block additional_menu_items %}
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_edit' pk=place.pk %}" class="LP-Link"><span class="LP-Link__Text">Edit place</span></a></li>
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_delete' pk=place.pk %}" class="LP-Link"><span class="LP-Link__Text">Delete place</span></a></li>
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_edit' pk=place.pk %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Edit place' %}</span></a></li>
|
||||
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_delete' pk=place.pk %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Delete place' %}</span></a></li>
|
||||
{% endblock additional_menu_items %}
|
||||
|
||||
{% block maincontent %}
|
||||
@@ -26,9 +25,9 @@
|
||||
|
||||
<header class="LP-PlaceDetail__Header">
|
||||
<h1 class="LP-Headline">{{ place.name }}</h1>
|
||||
{% if place.images.first.filename.hero.url %}
|
||||
{% if place.placeimages.first.filename.hero.url %}
|
||||
<figure class="LP-PlaceDetail__Image">
|
||||
<img src="{{ place.images.first.filename.hero.url }}" class="LP-Image" />
|
||||
<img src="{{ place.placeimages.first.filename.hero.url }}" class="LP-Image" />
|
||||
</figure>
|
||||
{% endif %}
|
||||
</header>
|
||||
@@ -38,34 +37,33 @@
|
||||
</div>
|
||||
|
||||
<section class="LP-Section">
|
||||
|
||||
{% url 'place_tag_submit' place_id=place.id as tag_submit_url%}
|
||||
{% include 'partials/tagging.html' with tag_list=place.tags.all config=tagging_config all_tags=all_tags %}
|
||||
|
||||
{% include 'partials/tagging.html' with config=tagging_config %}
|
||||
</section>
|
||||
|
||||
<section class="LP-Section">
|
||||
<h1 class="LP-Headline">Map-Links</h1>
|
||||
{% include 'partials/osm_map.html' %}
|
||||
<h1 class="LP-Headline">{% trans 'Map links' %}</h1>
|
||||
{% include 'partials/osm_map.html' with config=mapping_config%}
|
||||
<div class="LP-LinkList">
|
||||
<ul class="LP-LinkList__Container">
|
||||
<li class="LP-LinkList__Item"><a target="_blank" href="https://www.google.com/maps?q={{place.latitude}},{{place.longitude}}" class="LP-Link"><span class="LP-Text">Google Maps</span></a></li>
|
||||
<li class="LP-LinkList__Item"><a target="_blank" href="https://www.tim-online.nrw.de/tim-online2/?center={{place.latitude}},{{place.longitude}}&icon=true&bg=dop" class="LP-Link"><span class="LP-Text">TIM Online</span></a></li>
|
||||
<li class="LP-LinkList__Item"><a target="_blank" href="http://www.openstreetmap.org/?mlat={{place.latitude}}&mlon={{place.longitude}}&zoom=16" class="LP-Link"><span class="LP-Text">OSM</span></a></li>
|
||||
<li class="LP-LinkList__Item"><a target="_blank" href="https://www.google.com/maps?q={{place.latitude|safe}},{{place.longitude|safe}}" class="LP-Link"><span class="LP-Text">Google Maps</span></a></li>
|
||||
<li class="LP-LinkList__Item"><a target="_blank" href="https://www.tim-online.nrw.de/tim-online2/?center={{place.latitude|safe}},{{place.longitude|safe}}&icon=true&bg=dop" class="LP-Link"><span class="LP-Text">TIM Online</span></a></li>
|
||||
<li class="LP-LinkList__Item"><a target="_blank" href="http://www.openstreetmap.org/?mlat={{place.latitude|safe}}&mlon={{place.longitude|safe}}&zoom=16" class="LP-Link"><span class="LP-Text">OSM</span></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class=" LP-Section">
|
||||
<h1 class="LP-Headline">Photoalben</h1>
|
||||
<h1 class="LP-Headline">{% trans 'Photo albums' %}</h1>
|
||||
<div class="LP-LinkList">
|
||||
<ul class="LP-LinkList__Container">
|
||||
{% for photo_album in place.photo_albums.all %}
|
||||
{% for photo_album in place.photoalbums.all %}
|
||||
<li class="LP-LinkList__Item">
|
||||
<a target="_blank" href="{{photo_album.url}}" class="LP-Link">
|
||||
<span class="LP-Text">{{photo_album.label}}</span>
|
||||
</a>
|
||||
{% if user == photo_album.submitted_by or user == place.submitted_by %}
|
||||
{% can_modify_place_asset photo_album request as authorized %}
|
||||
{% if authorized %}
|
||||
<a href="{% url 'photo_album_delete' pk=photo_album.pk%}" class="LP-Link LP-LinkList__ItemHover" title="Delete Photo Album">
|
||||
<div class="RV-Iconized__Container RV-Iconized__Container--small">
|
||||
{% icon 'trash' className="RV-Iconized__Icon" %}
|
||||
@@ -83,7 +81,7 @@
|
||||
v216c0,11.046,8.954,20,20,20s20-8.954,20-20V276h216c11.046,0,20-8.954,20-20C512,244.954,503.046,236,492,236z" />
|
||||
</g>
|
||||
</svg>
|
||||
<span class="RV-Iconized__Text">Fotoalbum hinzufügen</span>
|
||||
<span class="RV-Iconized__Text">{% trans 'Add photo album' %}</span>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
@@ -92,14 +90,29 @@
|
||||
</section>
|
||||
|
||||
<section class="LP-Section">
|
||||
<h1 class="LP-Headline">Bilder</h1>
|
||||
<h1 class="LP-Headline">{% trans 'Images' %}</h1>
|
||||
<div class="LP-ImageGrid">
|
||||
<ul class="LP-ImageGrid__Container">
|
||||
{% for place_image in place.images.all %}
|
||||
{% for place_image in place.placeimages.all %}
|
||||
<li class="LP-ImageGrid__Item">
|
||||
<a href="{{ place_image.filename.large.url }}" class="LP-Link"><img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}"></a>
|
||||
<a href="{{ place_image.filename.large.url }}" class="LP-Link">
|
||||
<img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}">
|
||||
</a>
|
||||
{% can_modify_place_asset place_image request as authorized %}
|
||||
{% if authorized %}
|
||||
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
|
||||
<a href="{% url 'place_image_delete' pk=place_image.id %}" class="LP-Link">
|
||||
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}" />
|
||||
</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
<li class="LP-ImageGrid__Item LP-ImageGrid__Item--add" title="Bild hinzufügen">
|
||||
<a class="LP-Link" href="{% url 'place_image_create' place_id=place.id%}">
|
||||
<img class="LP-Icon" src="{% static 'icons/plus.svg' %}" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
60
django_lostplaces/lostplaces/templates/place/place_list.html
Normal file
@@ -0,0 +1,60 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block additional_head %}
|
||||
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
|
||||
<script src="{% static 'maps/ol.js' %}"></script>
|
||||
{% endblock additional_head %}
|
||||
|
||||
{% block title %}{% trans 'Lost Places' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
{% include 'partials/osm_map.html' with config=mapping_config %}
|
||||
<div class="LP-PlaceList">
|
||||
<h1 class="LP-Headline">{% trans 'Listing our places' %}</h1>
|
||||
<ul class="LP-PlaceList__List">
|
||||
{% for place in place_list %}
|
||||
<li class="LP-PlaceList__Item">
|
||||
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
||||
<article class="LP-PlaceTeaser LP-PlaceTeaser--extended">
|
||||
<div class="LP-PlaceTeaser__Image">
|
||||
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url }}" />
|
||||
</div>
|
||||
<div class="LP-PlaceTeaser__Meta">
|
||||
<div class="LP-PlaceTeaser__Info">
|
||||
<span class="LP-PlaceTeaser__Title">
|
||||
<h2 class="LP-Headline LP-Headline--teaser">{{place.name}}</h2>
|
||||
</span>
|
||||
<span class="LP-PlaceTeaser__Detail">
|
||||
<p class="LP-Paragraph">{{place.location}}</p>
|
||||
</span>
|
||||
</div>
|
||||
<div class="LP-PlaceTeaser__Description">
|
||||
<p class="LP-Paragraph">
|
||||
{% if place.description|length > 210 %}
|
||||
{{place.description|truncatechars:210|truncatewords:-1}}
|
||||
{% else %}
|
||||
{{place.description}}
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
<div class="LP-PlaceTeaser__Icons">
|
||||
<ul class="LP-Icon__List">
|
||||
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/favourite.svg' %}" /></li>
|
||||
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/location.svg' %}" /></li>
|
||||
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% include 'partials/nav/pagination.html' %}
|
||||
|
||||
</div>
|
||||
{% endblock maincontent %}
|
@@ -1,12 +1,13 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
# {% block title %}Update place{% endblock %}
|
||||
# {% block title %}{% trans 'Update place' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">Update place</legend>
|
||||
<legend class="LP-Form__Legend">{% trans 'Update place' %}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||
<div class="LP-Form__Field">
|
||||
@@ -38,15 +39,9 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% trans 'Update' as action %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<button class="LP-Button">Update</button>
|
||||
</div>
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<a class="LP-Link" href="{% url 'place_detail' pk=place.pk %}">
|
||||
<button type="button" class="LP-Button LP-Button--cancel">Cancel</button>
|
||||
</a>
|
||||
</div>
|
||||
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER action=action %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
@@ -0,0 +1,22 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load i18n %}
|
||||
|
||||
{% block maincontent %}
|
||||
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">{% trans 'Submit images to a place' %}</legend>
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="LP-Form__Composition">
|
||||
<div class="LP-Form__Field">
|
||||
{% include 'partials/form/inputField.html' with field=form.filename %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER %}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
</form>
|
||||
{% endblock maincontent %}
|
@@ -1,13 +1,13 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
|
||||
# {% block title %}Login{% endblock %}
|
||||
{% load i18n %}
|
||||
# {% block title %}{% trans 'Login' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">Login</legend>
|
||||
<legend class="LP-Form__Legend">{% trans 'Login' %}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||
<div class="LP-Form__Field">
|
||||
@@ -20,12 +20,12 @@
|
||||
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<button class="LP-Button">Login</button>
|
||||
<button class="LP-Button">{% trans 'Login' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<p class="LP-Headline">No account? <a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">Sign up here</span></a></p>
|
||||
<p class="LP-Headline">{% trans 'Have No Account Yet?' %} <a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign Up' %}</span></a></p>
|
||||
|
||||
{% endblock maincontent %}
|
@@ -1,14 +1,15 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
# {% block title %}Registrierung{% endblock %}
|
||||
# {% block title %}{% trans 'Sign up' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<form class="LP-Form" method="POST">
|
||||
<fieldset class="LP-Form__Fieldset">
|
||||
<legend class="LP-Form__Legend">Registration</legend>
|
||||
<legend class="LP-Form__Legend">{% trans 'Sign Up' %}</legend>
|
||||
{% csrf_token %}
|
||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||
<div class="LP-Form__Field">
|
||||
@@ -37,7 +38,7 @@
|
||||
|
||||
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||
<button class="LP-Button">Sign up</button>
|
||||
<button class="LP-Button">{% trans 'Sign Up' %}</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
Before Width: | Height: | Size: 209 B After Width: | Height: | Size: 209 B |
@@ -1,2 +1,3 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
@@ -1,4 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django import template
|
||||
from django.http import request
|
||||
|
||||
register = template.Library()
|
||||
|
||||
@@ -19,4 +23,14 @@ def proper_paginate(paginator, current_page, neighbors=2):
|
||||
end_index = paginator.num_pages
|
||||
page_list = [f for f in range(start_index, end_index+1)]
|
||||
return page_list[:(2*neighbors + 1)]
|
||||
return paginator.page_range
|
||||
return paginator.page_range
|
||||
|
||||
@register.simple_tag
|
||||
def can_modify_place_asset(place_asset, request, *args, **kwargs):
|
||||
print(place_asset.place.submitted_by, place_asset.submitted_by, request.user)
|
||||
if request.user.is_superuser:
|
||||
return True
|
||||
if request.user.explorer == place_asset.place.submitted_by or request.user.explorer == place_asset.submitted_by:
|
||||
return True
|
||||
else:
|
||||
return False
|
@@ -1,3 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json, os
|
||||
from importlib import import_module
|
||||
|
||||
@@ -6,7 +9,7 @@ from django.conf import settings
|
||||
from django.template import Library, TemplateSyntaxError
|
||||
|
||||
#icons_json_path = getattr(settings, 'SVG_ICONS_SOURCE_FILE')
|
||||
icons_json_path = os.path.join(settings.BASE_DIR, 'lostplaces_app', 'static', 'icons', 'icons.icomoon.json')
|
||||
icons_json_path = os.path.join(settings.BASE_DIR, 'lostplaces', 'static', 'icons', 'icons.icomoon.json')
|
||||
icons_json = json.load(open(icons_json_path))
|
||||
|
||||
register = Library()
|
5
django_lostplaces/lostplaces/tests/__init__.py
Normal file
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from django.test import TestCase
|
||||
from django.contrib.auth.models import User
|
76
django_lostplaces/lostplaces/tests/forms/__init__.py
Normal file
@@ -0,0 +1,76 @@
|
||||
from django.test import TestCase
|
||||
from django.core.exceptions import FieldDoesNotExist
|
||||
|
||||
class FormTestCase(TestCase):
|
||||
'''
|
||||
Base class for FormTests.
|
||||
Parameters:
|
||||
- form : Form to test
|
||||
'''
|
||||
form = None
|
||||
|
||||
def assertField(self, field_name, field_class, must_have={}, must_not_have={}):
|
||||
'''
|
||||
Tests if a field exists under the given name and
|
||||
if the field is of the right type.
|
||||
Also checks if the field has the given must_have attributes
|
||||
and does not have any of the must_not_have attributes. If you
|
||||
dont care about the value of the attribute you can just set it to
|
||||
something that fullfills value == False (i.e. '' or 0)
|
||||
'''
|
||||
try:
|
||||
field = self.form.base_fields[field_name]
|
||||
except FieldDoesNotExist:
|
||||
self.fail(
|
||||
'Expecting %s to have a field named \'%s\'' % (
|
||||
self.form.__name__,
|
||||
field_name
|
||||
)
|
||||
)
|
||||
self.assertEqual(
|
||||
type(field), field_class,
|
||||
msg='Expecting type of %s to be %s' % (
|
||||
str(field),
|
||||
field_class.__name__
|
||||
)
|
||||
)
|
||||
|
||||
for key, value in must_have.items():
|
||||
if value:
|
||||
self.assertEqual(
|
||||
getattr(field, key), value,
|
||||
msg='Expeting the value of %s %s to be \'%s\'' % (
|
||||
str(field),
|
||||
key,
|
||||
value
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.assertTrue(
|
||||
hasattr(field, key),
|
||||
msg='Expeting %s to have \'%s\'' % (
|
||||
str(field),
|
||||
key
|
||||
)
|
||||
)
|
||||
|
||||
for key, value in must_not_have.items():
|
||||
if value:
|
||||
self.assertTrue(
|
||||
getattr(field, key) != value,
|
||||
msg='Expeting the value of %s %s to not be \'%s\'' % (
|
||||
str(field),
|
||||
key,
|
||||
value
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.assertFalse(
|
||||
hasattr(field, value),
|
||||
msg='Expeting %s to not have \'%s\'' % (
|
||||
str(field),
|
||||
key
|
||||
)
|
||||
)
|
||||
|
||||
return field
|
@@ -0,0 +1,59 @@
|
||||
import datetime
|
||||
|
||||
from django import forms
|
||||
from django.utils import timezone
|
||||
|
||||
from lostplaces.tests.forms import FormTestCase
|
||||
from lostplaces.forms import ExplorerCreationForm
|
||||
from lostplaces.models.models import Voucher
|
||||
|
||||
class ExplorerCreationFormTestCase(FormTestCase):
|
||||
"""
|
||||
This test case only tests for the voucher since all other aspects don't realy matter
|
||||
to this project and are already tested by django
|
||||
"""
|
||||
form = ExplorerCreationForm
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
Voucher.objects.create(
|
||||
code='Imacode123',
|
||||
expires_when=timezone.now() + datetime.timedelta(minutes=1)
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
self.post_data = {
|
||||
'voucher': 'Imacode123',
|
||||
'username': 'testpeter',
|
||||
'email': 'testpeter@example.org',
|
||||
'password1': 'Develop123',
|
||||
'password2': 'Develop123'
|
||||
}
|
||||
|
||||
def test_voucher_field(self):
|
||||
self.assertField(
|
||||
field_name='voucher',
|
||||
field_class=forms.CharField
|
||||
)
|
||||
|
||||
def test_validation_valid(self):
|
||||
form = ExplorerCreationForm(self.post_data)
|
||||
self.assertTrue(
|
||||
form.is_valid(),
|
||||
msg='Expecting the %s to validate' % (
|
||||
self.form.__name__
|
||||
)
|
||||
)
|
||||
|
||||
def test_validation_invalid(self):
|
||||
self.post_data = {
|
||||
'voucher': 'Imanotacode123'
|
||||
}
|
||||
form = ExplorerCreationForm(self.post_data)
|
||||
self.assertFalse(
|
||||
form.is_valid(),
|
||||
msg='Expecting the %s to not validate' % (
|
||||
self.form.__name__
|
||||
)
|
||||
)
|
||||
|