Compare commits
210 Commits
Author | SHA1 | Date | |
---|---|---|---|
196fb02436 | |||
9be993d9ba | |||
20dd880a11 | |||
946c3091c0 | |||
4bacd1a28d | |||
086789aa88 | |||
3c5b447d4c | |||
cfbb876d2c | |||
4e0bfef483 | |||
ccdb49c8ea | |||
90dd281f7c | |||
d9df6e67a8 | |||
cd20e730ba | |||
c613d15e89 | |||
2380398fa9 | |||
4c5b9c7648 | |||
91a3f3171d | |||
01f7dad37c | |||
2bfdf5c172 | |||
15f6a30cd6 | |||
812c921a42 | |||
dafe7eee34 | |||
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 | |||
4e366d94c9 | |||
da60d81e90 | |||
2e73cb92d4 | |||
773390b09f | |||
ac0121d96e | |||
a0c4f2cad3 | |||
86fbee4116 | |||
ab3ecae54b | |||
ae915681ac | |||
cfbe54a4e5 | |||
a976b59732 | |||
d6006b17d9 | |||
c911f7958a | |||
f592aba75d | |||
190eb5eef7 | |||
979900ab07 | |||
66bd9f648b | |||
76b514e1e6 | |||
b758d53a63 | |||
dabec5185f | |||
c189183e72 | |||
60ad323e7a | |||
2d2e356f1c | |||
710663b490 | |||
24c2ac8347 | |||
e0a0fa29d2 | |||
53817e9dc4 | |||
556931d2b1 | |||
485eb7b886 | |||
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 |
10
.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
|
||||
|
||||
@@ -97,4 +91,4 @@ venv.bak/
|
||||
.vscode
|
||||
|
||||
# twine / pypi
|
||||
.pypirc
|
||||
.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.
|
||||
|
@@ -1,5 +0,0 @@
|
||||
include LICENSE
|
||||
include Readme.rst
|
||||
include Pipfile
|
||||
recursive-include lostplaces_app/static *
|
||||
recursive-include lostplaces_app/templates *
|
12
Pipfile
@@ -10,7 +10,8 @@ autopep8 = "*"
|
||||
pipenv = "*"
|
||||
wheel = "*"
|
||||
twine = "*"
|
||||
pandoc ="*"
|
||||
pandoc = "*"
|
||||
pylint-django = "*"
|
||||
|
||||
[packages]
|
||||
django = "*"
|
||||
@@ -18,6 +19,9 @@ easy-thumbnails = "*"
|
||||
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"
|
||||
|
69
Readme.md
@@ -2,14 +2,14 @@
|
||||
|
||||
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 ressources the frontend requires will be shipped with lostplace's distribution. We also try to minimze the use of JavaScript as far as we can and try to offer JS-less alternatives where we can.
|
||||
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 usefull information.
|
||||
- Manage lost places with lots of useful information.
|
||||
- OSM-Maps
|
||||
- Sensitive information is not accesiable for anonymous (not logged in) users.
|
||||
- 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.
|
||||
|
||||
@@ -21,6 +21,13 @@ Right now it depends on the following non-core Python 3 libraries. These can be
|
||||
* [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.
|
||||
|
||||
|
||||
# Installing a development instance
|
||||
@@ -34,10 +41,10 @@ After having obtained the repository contents (either via .zip download or git c
|
||||
$ 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
|
||||
@@ -45,9 +52,9 @@ $ pipenv 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
|
||||
@@ -63,25 +70,27 @@ Currently there are two ways to deploy the lostplaces project:
|
||||
|
||||
## Cloning the repository
|
||||
|
||||
Essentially, this is the same as installing a development instance, but without the development server (manage.py runserver) and something powerfull (Apache, NGINX) instead. You have to configure the webserve to work with the *SGI Api respectivly, reference [django's guide for deployment](https://docs.djangoproject.com/en/3.1/howto/deployment/) for further information.
|
||||
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 recommened for production use. Reference [django's guide for databases](https://docs.djangoproject.com/en/3.1/ref/databases/) 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 `lostplaces/managy.py collectstatic` and you should be ready to go.
|
||||
Run `django_lostplaces/managy.py collectstatic` and you should be ready to go.
|
||||
|
||||
|
||||
## Installing the lostplaces_app to an existing django instance
|
||||
## Installing lostplaces to an existing django instance
|
||||
|
||||
### Installing django and the lostplaces app
|
||||
### 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 realeases page](https://git.mowoe.com/reverend/lostplaces-backend/releases) and install it using `pip install --user name-of-the-file.tar.gz`
|
||||
Afterwards, either
|
||||
- download the desired release [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`
|
||||
- or install the latest release using `pip install django-lostplaces`
|
||||
|
||||
*Note: You can run pip install without the --user flag, which will require root privileges and introduces potential security issues.*
|
||||
|
||||
@@ -93,7 +102,7 @@ Now configure your `settings.py` as follows:
|
||||
```python
|
||||
INSTALLED_APPS = [
|
||||
...
|
||||
'lostplaces_app',
|
||||
'django_lostplaces',
|
||||
'easy_thumbnails',
|
||||
'widget_tweaks',
|
||||
'django_taggit'
|
||||
@@ -110,28 +119,22 @@ MEDIA_URL = '/uploads/'
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
|
||||
```
|
||||
|
||||
3. Set the user model (this will be changed in the next release):
|
||||
|
||||
```python
|
||||
AUTH_USER_MODEL = 'lostplaces_app.Explorer'
|
||||
```
|
||||
|
||||
4. Set the URL's for login, for example:
|
||||
3. Set the URL's for login, for example:
|
||||
|
||||
```python
|
||||
LOGIN_URL = reverse_lazy('login')
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('lostplaces_home')
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy('lostplaces_home')
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('django_lostplaces_home')
|
||||
LOGOUT_REDIRECT_URL = reverse_lazy('django_lostplaces_home')
|
||||
```
|
||||
|
||||
### Configuring the URL's
|
||||
In the `urls.py` configure the `urlpatter` like this:
|
||||
In the `urls.py` configure the `urlpatterns` like this:
|
||||
```python
|
||||
urlpatterns = [
|
||||
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('lostplaces_app.urls')), # In this configuration lostplaces will be at the top level of you website, change '' to 'lostplaces/', if you don't want this.
|
||||
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.
|
||||
```
|
||||
|
||||
@@ -139,5 +142,11 @@ Before making the django instance public, you should tweak the config `settings.
|
||||
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`
|
||||
|
||||
Run `lostplaces/managy.py collectstatic` you should be ready to go.
|
||||
|
||||
Run `django_lostplaces/manage.py collectstatic` you should be ready to go.
|
||||
|
||||
|
||||
### Contact
|
||||
If you run into any issues, have any questions or If you are interested in this project in general, feel free to get in touch with us via [reverend@reverend2048.de](mailto:reverend@reverend2048.de), we do speak English and German.
|
6
django_lostplaces/MANIFEST.in
Normal file
@@ -0,0 +1,6 @@
|
||||
exclude
|
||||
include LICENSE
|
||||
include Readme.rst
|
||||
include Pipfile
|
||||
recursive-include lostplaces/static *
|
||||
recursive-include lostplaces/templates *
|
@@ -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()
|
@@ -18,6 +18,8 @@ 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__)))
|
||||
@@ -38,7 +40,7 @@ ALLOWED_HOSTS = ['localhost']
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'lostplaces_app',
|
||||
'lostplaces',
|
||||
'easy_thumbnails',
|
||||
'widget_tweaks',
|
||||
'taggit',
|
||||
@@ -58,9 +60,10 @@ 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 = [
|
||||
{
|
||||
@@ -78,7 +81,7 @@ TEMPLATES = [
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = 'lostplaces.wsgi.application'
|
||||
WSGI_APPLICATION = 'django_lostplaces.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
@@ -124,6 +127,11 @@ USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
|
||||
LANGUAGES = [
|
||||
('de', _('German')),
|
||||
('en', _('English')),
|
||||
]
|
||||
|
||||
|
||||
# Static files (CSS, JavaScript, Images)
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
@@ -131,9 +139,15 @@ USE_TZ = True
|
||||
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')
|
||||
|
||||
# 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_URL = reverse_lazy('login')
|
||||
LOGIN_REDIRECT_URL = reverse_lazy('lostplaces_home')
|
@@ -23,11 +23,11 @@ from django.conf.urls.static import static
|
||||
from django.urls import path, include
|
||||
from django.views.generic.base import TemplateView
|
||||
|
||||
from lostplaces_app.views import SignUpView
|
||||
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'
|
11
django_lostplaces/lostplaces/common.py
Normal file
@@ -0,0 +1,11 @@
|
||||
def get_all_subclasses(cls):
|
||||
'''
|
||||
Gets all subclasses recursively, does not contain
|
||||
abstract classes
|
||||
'''
|
||||
subclass_list = []
|
||||
for subclass in cls.__subclasses__():
|
||||
if not subclass._meta.abstract:
|
||||
subclass_list.append(subclass)
|
||||
subclass_list += get_all_subclasses(subclass)
|
||||
return subclass_list
|
@@ -4,9 +4,11 @@
|
||||
''' (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 django.contrib.auth.models import User
|
||||
from lostplaces_app.models import Place, PlaceImage, Voucher
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from lostplaces.models import Place, PlaceImage, Voucher
|
||||
|
||||
class ExplorerCreationForm(UserCreationForm):
|
||||
class Meta:
|
||||
@@ -14,16 +16,20 @@ class ExplorerCreationForm(UserCreationForm):
|
||||
fields = ('username', 'email')
|
||||
voucher = forms.CharField(
|
||||
max_length=30,
|
||||
help_text='The Voucher you got from an administrator'
|
||||
)
|
||||
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()
|
||||
@@ -40,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']
|
387
django_lostplaces/lostplaces/locale/de/LC_MESSAGES/django.po
Normal file
@@ -0,0 +1,387 @@
|
||||
# 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 21:53+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/abstract_models.py:59
|
||||
msgid "Submission date"
|
||||
msgstr "Einreichungsdatum"
|
||||
|
||||
#: models/abstract_models.py:67
|
||||
msgid "Submitter"
|
||||
msgstr "Einreicher"
|
||||
|
||||
#: models/abstract_models.py:79
|
||||
msgid "Creation date"
|
||||
msgstr "Erstellungsdatum"
|
||||
|
||||
#: models/abstract_models.py:82
|
||||
msgid "Expiration date"
|
||||
msgstr "Ablaufdatum"
|
||||
|
||||
#: 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 "Ausloggen"
|
||||
|
||||
#: 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:6 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 templates/place/place_update.html:5
|
||||
#: templates/place/place_update.html:10
|
||||
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 "Delete lost place"
|
||||
msgstr "Lost Place löschen"
|
||||
|
||||
#: templates/place/place_delete.html:15
|
||||
#, python-format
|
||||
msgid "Are you sure you want to delete %(place_name)s?"
|
||||
msgstr "Bist Du sicher, dass Du %(place_name)s löschen möchtest?"
|
||||
|
||||
#: 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 "All Places"
|
||||
msgstr "Alle Places"
|
||||
|
||||
#: templates/place/place_list.html:16
|
||||
msgid "Our lost places"
|
||||
msgstr "Unsere Lost Places"
|
||||
|
||||
#: 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 "No account, yet?"
|
||||
msgstr "Noch kein Konto?"
|
||||
|
||||
#: 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 deleted successfully"
|
||||
msgstr "Bild 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
|
||||
msgid "Successfully updated place"
|
||||
msgstr "Place erfolgreich aktualisiert"
|
||||
|
||||
#: views/place_views.py:63
|
||||
msgid "You are not allowed to edit this place"
|
||||
msgstr "Du darfst diesen Place nicht bearbeiten"
|
||||
|
||||
#: views/place_views.py:97
|
||||
msgid "Successfully created place"
|
||||
msgstr "Place erfolgreich erstellt"
|
||||
|
||||
#: views/place_views.py:105
|
||||
msgid "Please fill in all required fields."
|
||||
msgstr "Bitte füll alle benötigten Felder aus."
|
||||
|
||||
#: views/place_views.py:112
|
||||
msgid "Successfully deleted place"
|
||||
msgstr "Place erfolgreich gelöscht"
|
||||
|
||||
#: views/place_views.py:114
|
||||
msgid "You are not allowed to delete this place"
|
||||
msgstr "Du darfst diesen Place nicht löschen"
|
||||
|
||||
#: views/views.py:29
|
||||
msgid "User created"
|
||||
msgstr "Benutzer erstellt"
|
||||
|
||||
#: views/views.py:54
|
||||
msgid "Photo album link submitted"
|
||||
msgstr "Fotoalbum-Link hinzugefügt"
|
||||
|
||||
#: views/views.py:59
|
||||
msgid "Photo album link deleted"
|
||||
msgstr "Fotoalbum-Link gelöscht"
|
||||
|
||||
#: views/views.py:60
|
||||
msgid "You are not allowed to edit this photo album link"
|
||||
msgstr "Du darfst diesen Fotoalbum-Link nicht 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_reomve_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,
|
||||
},
|
||||
),
|
||||
]
|
102
django_lostplaces/lostplaces/migrations/0004_release_0_1_3.py
Normal file
@@ -0,0 +1,102 @@
|
||||
# Generated by Django 3.1.1 on 2020-12-19 13:53
|
||||
|
||||
import django.core.validators
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import easy_thumbnails.fields
|
||||
import lostplaces.models.place
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('lostplaces', '0003_voucher'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='photoalbum',
|
||||
name='label',
|
||||
field=models.CharField(max_length=100, verbose_name='link text'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photoalbum',
|
||||
name='submitted_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='photoalbums', to='lostplaces.explorer', verbose_name='Submitter'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photoalbum',
|
||||
name='submitted_when',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='photoalbum',
|
||||
name='url',
|
||||
field=models.URLField(verbose_name='URL'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='description',
|
||||
field=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'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='latitude',
|
||||
field=models.FloatField(help_text='Latitude in decimal format: e. g. 41.40338', validators=[django.core.validators.MinValueValidator(-90), django.core.validators.MaxValueValidator(90)], verbose_name='Latitude'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='location',
|
||||
field=models.CharField(max_length=50, verbose_name='Location'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='longitude',
|
||||
field=models.FloatField(help_text='Longitude in decimal format: e. g. 2.17403', validators=[django.core.validators.MinValueValidator(-180), django.core.validators.MaxValueValidator(180)], verbose_name='Longitude'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='name',
|
||||
field=models.CharField(max_length=50, verbose_name='Name'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='submitted_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='places', to='lostplaces.explorer', verbose_name='Submitter'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='place',
|
||||
name='submitted_when',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='placeimage',
|
||||
name='description',
|
||||
field=models.TextField(blank=True, verbose_name='Description'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='placeimage',
|
||||
name='filename',
|
||||
field=easy_thumbnails.fields.ThumbnailerImageField(help_text='Optional: One or more images to upload', upload_to=lostplaces.models.place.generate_image_upload_path, verbose_name='Filename(s)'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='placeimage',
|
||||
name='submitted_by',
|
||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer', verbose_name='Submitter'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='placeimage',
|
||||
name='submitted_when',
|
||||
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='voucher',
|
||||
name='created_when',
|
||||
field=models.DateTimeField(auto_now_add=True, verbose_name='Creation date'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='voucher',
|
||||
name='expires_when',
|
||||
field=models.DateTimeField(verbose_name='Expiration date'),
|
||||
),
|
||||
]
|
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 *
|
87
django_lostplaces/lostplaces/models/abstract_models.py
Normal file
@@ -0,0 +1,87 @@
|
||||
|
||||
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,
|
||||
verbose_name=_('Submission date')
|
||||
)
|
||||
submitted_by = models.ForeignKey(
|
||||
'Explorer',
|
||||
on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
blank=True,
|
||||
related_name='%(class)ss',
|
||||
verbose_name=_('Submitter')
|
||||
)
|
||||
|
||||
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,
|
||||
verbose_name=_('Creation date')
|
||||
)
|
||||
expires_when = models.DateTimeField(
|
||||
verbose_name=_('Expiration date')
|
||||
)
|
||||
|
||||
@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 (PlaceAsset):
|
||||
"""
|
||||
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 |
BIN
django_lostplaces/lostplaces/static/images/missing_image.png
Normal file
After Width: | Height: | Size: 24 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,16 +856,15 @@ 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; }
|
||||
|
||||
.LP-PlaceTeaser {
|
||||
width: 280px; }
|
||||
width: 100%; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Image {
|
||||
height: 165px;
|
||||
width: 280px;
|
||||
width: 100%;
|
||||
overflow: hidden; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Image .LP-Image {
|
||||
max-width: unset;
|
||||
@@ -873,6 +872,8 @@ body {
|
||||
object-fit: cover; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 5px;
|
||||
@@ -883,19 +884,30 @@ body {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-top: 5px;
|
||||
font-size: 0.9rem; }
|
||||
font-size: 1.3rem; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Headline {
|
||||
font-family: "Montserrat", Helvetica, sans-serif;
|
||||
color: #565656;
|
||||
font-size: 1rem;
|
||||
font-size: 2rem;
|
||||
padding: 0px;
|
||||
margin: 0px; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Icon {
|
||||
height: 2em;
|
||||
width: 2em; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Description {
|
||||
font-family: "Montserrat", Helvetica, sans-serif;
|
||||
color: #565656;
|
||||
display: none; }
|
||||
order: 3;
|
||||
flex-basis: 100%; }
|
||||
.LP-PlaceTeaser .LP-PlaceTeaser__Description .LP-Paragraph {
|
||||
font-size: 22px; }
|
||||
|
||||
@media (min-width: 650px) {
|
||||
.LP-PlaceTeaser {
|
||||
width: 280px; }
|
||||
.LP-PlaceTeaser__Image {
|
||||
width: 280px;
|
||||
height: 165px; }
|
||||
.LP-PlaceTeaser--extended {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -904,12 +916,15 @@ body {
|
||||
height: 165px; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta {
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
padding-left: 25px;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start; }
|
||||
align-items: flex-start;
|
||||
gap: unset; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Headline, .LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Paragraph {
|
||||
font-size: unset; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Info .LP-Headline {
|
||||
font-size: 28px; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons {
|
||||
@@ -917,10 +932,16 @@ body {
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons ul {
|
||||
padding: 0;
|
||||
margin: 0; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Icon {
|
||||
height: 20px;
|
||||
width: 20px; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description {
|
||||
display: block;
|
||||
max-height: 55px;
|
||||
overflow: hidden; }
|
||||
overflow: hidden;
|
||||
order: unset; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description .LP-Paragraph {
|
||||
font-size: unset; }
|
||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Image {
|
||||
height: 165px;
|
||||
width: 280px;
|
||||
@@ -1006,6 +1027,31 @@ body {
|
||||
.LP-MessageList .LP-MessageList__Item {
|
||||
margin: 5px 0; }
|
||||
|
||||
.LP-UserInfo {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: #D7CEC7;
|
||||
max-width: 400px;
|
||||
width: 100%;
|
||||
min-width: 300px; }
|
||||
.LP-UserInfo__UserName {
|
||||
background-color: #C09F80; }
|
||||
.LP-UserInfo__UserName .LP-Headline {
|
||||
color: black;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
padding: 5px;
|
||||
font-size: 25px; }
|
||||
.LP-UserInfo__Meta {
|
||||
padding: 5px; }
|
||||
.LP-UserInfo__Meta * {
|
||||
font-family: "Montserrat", Helvetica, sans-serif;
|
||||
font-size: 18px; }
|
||||
.LP-UserInfo__Meta .LP-UserInfo__Key {
|
||||
padding-right: 25px;
|
||||
font-weight: bold; }
|
||||
|
||||
.LP-Header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -1069,7 +1115,9 @@ body {
|
||||
box-shadow: 0 0 2px #565656; }
|
||||
|
||||
.LP-PlaceList .LP-PlaceList__List {
|
||||
list-style-type: none; }
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0; }
|
||||
.LP-PlaceList .LP-PlaceList__List .LP-Link .LP-Place:hover {
|
||||
color: #565656;
|
||||
background-color: #f9f9f9;
|
||||
@@ -1080,6 +1128,10 @@ body {
|
||||
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
||||
max-width: 900px;
|
||||
margin: 18px 0; }
|
||||
@media (max-width: 750px) {
|
||||
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
||||
width: 100%;
|
||||
margin-bottom: 35px; } }
|
||||
|
||||
.LP-PlaceList .LP-Pagination {
|
||||
margin-top: 50px; }
|
||||
@@ -1588,23 +1640,90 @@ 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-UserProfile {
|
||||
display: flex;
|
||||
flex-direction: row; }
|
||||
.LP-UserProfile__Bio {
|
||||
flex-grow: 5;
|
||||
flex-shrink: 10;
|
||||
padding-right: 35px; }
|
||||
.LP-UserProfile__Info {
|
||||
flex-grow: 10;
|
||||
flex-shrink: 1;
|
||||
flex-basis: max-content; }
|
||||
|
||||
.LP-MainContainer {
|
||||
margin: 0 auto;
|
||||
@@ -1618,8 +1737,9 @@ body {
|
||||
width: 100%; } }
|
||||
|
||||
.LP-PlaceDetail .LP-PlaceDetail__Image {
|
||||
width: 700px;
|
||||
max-width: 700px;
|
||||
max-height: 500px;
|
||||
width: 50%;
|
||||
box-shadow: 0 0 10px #565656;
|
||||
box-shadow: 0 0 10px #565656;
|
||||
object-fit: cover;
|
||||
@@ -1627,22 +1747,23 @@ body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
float: right;
|
||||
margin-left: 35px;
|
||||
margin-bottom: 35px;
|
||||
margin-right: 35px;
|
||||
margin-left: 25px;
|
||||
margin-bottom: 25px;
|
||||
margin-right: 25px;
|
||||
overflow: hidden; }
|
||||
|
||||
@media (max-width: 1000px) {
|
||||
@media (max-width: 750px) {
|
||||
.LP-PlaceDetail .LP-PlaceDetail__Header .LP-PlaceDetail__Image {
|
||||
float: none;
|
||||
width: 100%;
|
||||
max-width: unset;
|
||||
height: auto;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
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 %}
|
109
django_lostplaces/lostplaces/templates/explorer/profile.html
Normal file
@@ -0,0 +1,109 @@
|
||||
{% extends 'global.html'%}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load svg_icon %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
<div class="LP-UserProfile">
|
||||
<div class="LP-UserProfile__Info">
|
||||
<div class="LP-UserInfo">
|
||||
<div class="LP-UserInfo__UserName">
|
||||
<h1 class="LP-Headline">{{explorer.user.username}}</h1>
|
||||
</div>
|
||||
<div class="LP-UserInfo__Meta">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="LP-UserInfo__Key">
|
||||
<span class="LP-Paragraph">{% trans 'Joined' %}</span>
|
||||
</td>
|
||||
<td class="LP-UserInfo__Value">
|
||||
<span class="LP-Paragraph">{{explorer.user.date_joined|date:'d.m.Y'}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="LP-UserInfo__Key">
|
||||
<span class="LP-Paragraph">{% trans 'Places'%}</span>
|
||||
</td>
|
||||
<td class="LP-UserInfo__Value">
|
||||
<span class="LP-Paragraph">{{place_count}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="LP-UserInfo__Key">
|
||||
<span class="LP-Paragraph">{% trans 'Place Assets'%}</span>
|
||||
</td>
|
||||
<td class="LP-UserInfo__Value">
|
||||
<span class="LP-Paragraph">{{asset_count}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<section class="LP-Section">
|
||||
<div class="LP-PlaceList">
|
||||
<h1 class="LP-Headline">{% trans 'Places submitted by' %} {{explorer.user.username}}</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">
|
||||
{% include 'partials/place_teaser.html' with place=place extended=True %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
{% include 'partials/nav/pagination.html' %}
|
||||
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="LP-Section">
|
||||
<h1 class="LP-Headline">{% trans 'Images submitted by' %} {{explorer.user.username}}</h1>
|
||||
<div class="LP-ImageGrid">
|
||||
<ul class="LP-ImageGrid__Container">
|
||||
{% for place_image in assets.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>
|
||||
{% if user.explorer == place_image.submitted_by%}
|
||||
<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 %}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class=" LP-Section">
|
||||
<h1 class="LP-Headline">{% trans 'Photo albums submitted by' %} {{explorer.user.username}}</h1>
|
||||
<div class="LP-LinkList">
|
||||
<ul class="LP-LinkList__Container">
|
||||
{% for photo_album in assets.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.explorer == photo_album.submitted_by%}
|
||||
<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" %}
|
||||
</div>
|
||||
</a>
|
||||
{% endif %}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% 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>
|
@@ -1,4 +1,5 @@
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
@@ -28,15 +29,16 @@
|
||||
<span class="LP-Paragraph">
|
||||
{% if user.is_authenticated %}
|
||||
Hi {{ user.username }}!
|
||||
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">logout</span></a>
|
||||
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">{% trans 'Logout' %}</span></a> |
|
||||
<a class="LP-Link" href="{% url 'explorer_profile' explorer_id=user.pk%}"><span class="LP-Link__Text">{% trans 'Profile' %}</span></a>
|
||||
{% if user.is_superuser %}
|
||||
<a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">admin</span></a>
|
||||
| <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">login</span></a> |
|
||||
<a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">signup</span></a>
|
||||
<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>
|
||||
@@ -46,14 +48,14 @@
|
||||
<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">Home</span></a></li>
|
||||
<li class="LP-Menu__Item"><a href="{% url 'flatpage' slug='codex' %}" class="LP-Link"><span class="LP-Link__Text">UrBex codex</span></a></li>
|
||||
<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">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">See all places</span></a></li>
|
||||
<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>
|
32
django_lostplaces/lostplaces/templates/home.html
Normal file
@@ -0,0 +1,32 @@
|
||||
{% 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 'Home' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
{% include 'partials/welcome.html' %}
|
||||
<article class="LP-TextSection">
|
||||
</article>
|
||||
|
||||
{% include 'partials/osm_map.html' with config=mapping_config %}
|
||||
<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">
|
||||
{% include 'partials/place_teaser.html' with place=place%}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{% endblock maincontent %}
|
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://git.mowoe.com/reverend" 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="{% url 'flatpage' slug='privacy-policy' %}" class="LP-Footer__GenericAnchor">Privacy Policy</a>
|
||||
<a href="{% url 'flatpage' slug='privacy-policy' %}" class="LP-Footer__GenericAnchor">{% trans 'Privacy Policy' %}</a>
|
||||
|
|
||||
<a href="{% url 'flatpage' slug='imprint' %}" class="LP-Footer__GenericAnchor">Imprint</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" %}'
|
||||
})
|
||||
})
|
||||
});
|
@@ -0,0 +1,37 @@
|
||||
{%load static %}
|
||||
|
||||
<article class="LP-PlaceTeaser {% if extended %} LP-PlaceTeaser--extended{% endif %}">
|
||||
<div class="LP-PlaceTeaser__Image">
|
||||
{% if place.placeimages.all|length > 0 %}
|
||||
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
|
||||
{% else %}
|
||||
<img class="LP-Image" src="{% static 'images/missing_image.png' %}" />
|
||||
{% endif %}
|
||||
</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>
|
||||
<span class="LP-PlaceTeaser__Detail">
|
||||
<p class="LP-Paragraph">{{place.location|truncatechars:25}}</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>
|
@@ -1,6 +1,8 @@
|
||||
{% 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">
|
||||
@@ -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>
|
||||
<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" %}
|
||||
@@ -46,14 +48,10 @@
|
||||
submit_form.onsubmit = () => false
|
||||
|
||||
const tagify = new Tagify(input, {
|
||||
'whitelist': [{
|
||||
%
|
||||
for tag in all_tags %
|
||||
}
|
||||
'whitelist': [
|
||||
{% for tag in config.all_tags %}
|
||||
'{{tag}}',
|
||||
{
|
||||
% endfor %
|
||||
}
|
||||
{% endfor %}
|
||||
]
|
||||
})
|
||||
|
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 'Delete lost place' %}{% 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">{% blocktrans with place_name=place.name%}Are you sure you want to delete {{place_name}}?{% endblocktrans %}</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,6 +1,7 @@
|
||||
{% extends 'global.html'%}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% load thumbnail %}
|
||||
{% load svg_icon %}
|
||||
|
||||
@@ -14,8 +15,8 @@
|
||||
{% 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 %}
|
||||
@@ -23,9 +24,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>
|
||||
@@ -37,32 +38,32 @@
|
||||
<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.explorer == photo_album.submitted_by or user.explorer == place.submitted_by %}
|
||||
{% if user.explorer == photo_album.submitted_by or user.explorer == place.submitted_by %}
|
||||
<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" %}
|
||||
@@ -80,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>
|
||||
@@ -89,14 +90,28 @@
|
||||
</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>
|
||||
{% if user.explorer == place_image.submitted_by or user.explorer == place.submitted_by %}
|
||||
<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>
|
30
django_lostplaces/lostplaces/templates/place/place_list.html
Normal file
@@ -0,0 +1,30 @@
|
||||
{% 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 'All Places' %}{% endblock %}
|
||||
|
||||
{% block maincontent %}
|
||||
|
||||
{% include 'partials/osm_map.html' with config=mapping_config %}
|
||||
<div class="LP-PlaceList">
|
||||
<h1 class="LP-Headline">{% trans 'Our lost 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">
|
||||
{% include 'partials/place_teaser.html' with place=place extended=True %}
|
||||
</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 'Edit 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 'Edit 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 '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 |