Compare commits
117 Commits
fc7a847f6d
...
0.1
Author | SHA1 | Date | |
---|---|---|---|
6b90ca39eb | |||
c1007fb7bc | |||
aa4c77e675 | |||
7a378c26d0 | |||
d58d118953 | |||
4ea8d16253 | |||
9f29ea603f | |||
60a9f61358 | |||
c2b9b494cc | |||
99fbe827c9 | |||
6f1598e978 | |||
7a432921d1 | |||
97a5052ad8 | |||
42d1137dfb | |||
e2152662cf | |||
9f33b994dd | |||
70f2137af5 | |||
b5147ee59b | |||
df2aaf646a | |||
62a53c98e6 | |||
9fad8e8baa | |||
01ab8a304d | |||
86087c2b8d | |||
f616b713d4 | |||
6482d622b2 | |||
faa4ed52ef | |||
9f788ab44c | |||
f27fc71a01 | |||
2f1f356eb0 | |||
adc0fd4d5e | |||
8889314d9e | |||
1a70c1437e | |||
c148cc5f10 | |||
aa48af7c91 | |||
564d20c73e | |||
0b3aff1d1d | |||
0cf482dc5c | |||
275bec6560 | |||
852def01d2 | |||
1eed5a8283 | |||
4ebc8f93f7 | |||
1130ee70d9 | |||
759c42279d | |||
87efccf6c9 | |||
a82ddaa44e | |||
78f087fb3c | |||
1d62b20a3c | |||
9f3ed46b35 | |||
b6b17f4caf | |||
c0191fc6c4 | |||
10d96c7c8f | |||
0074c73562 | |||
1e082dcb25 | |||
d554355f9c | |||
5c9a52b01c | |||
7bcb08a4ae | |||
5009b778f7 | |||
f9fd9d68a7 | |||
cbcfda3726 | |||
0620ac2325 | |||
c39bbef47c | |||
bc49b305ff | |||
764d0f32be | |||
9dfd389a5d | |||
22e2657367 | |||
aff5babb20 | |||
5bc92a5841 | |||
d5de4e0440 | |||
8f340f6567 | |||
118c48cd66 | |||
70ee70b50f | |||
bc484b9ff9 | |||
313748f5ac | |||
8b01bbb2ce | |||
147c0e8dfe | |||
86d7212060 | |||
30e6c6fda6 | |||
98a3c9f22c | |||
675cdc5721 | |||
121b99730d | |||
fb8e7a357b | |||
f9cb21dc8e | |||
06b7686264 | |||
34df74e42a | |||
f77650b54d | |||
68db5fbc7a | |||
89060f4ce0 | |||
602a8bb1e6 | |||
fe97e02e41 | |||
15a74f1f31 | |||
19847d0e1f | |||
5a9e86d3c0 | |||
172e462d1d | |||
565c58019b | |||
e63601955e | |||
c2d08f637f | |||
805363eac5 | |||
f9851071ed | |||
985ab2ed75 | |||
2b3fa6f216 | |||
5d500100e5 | |||
b7fd19e5ef | |||
85632e85fb | |||
7ee5b359d1 | |||
9a2ff27810 | |||
05b770f56d | |||
d1e1eaf2ae | |||
e2f4fca8ca | |||
8f9e1b5877 | |||
28d09c968a | |||
d138c57b22 | |||
f3a7676bfa | |||
284302e3dc | |||
74032b7460 | |||
9e2a54b8e5 | |||
c20e9c866d | |||
66404eea87 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -66,6 +66,10 @@ coverage.xml
|
|||||||
*.mo
|
*.mo
|
||||||
|
|
||||||
# Django stuff:
|
# 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
|
# pyenv
|
||||||
.python-version
|
.python-version
|
||||||
|
3
Pipfile
3
Pipfile
@@ -11,6 +11,7 @@ django = "*"
|
|||||||
easy-thumbnails = "*"
|
easy-thumbnails = "*"
|
||||||
image = "*"
|
image = "*"
|
||||||
django-widget-tweaks = "*"
|
django-widget-tweaks = "*"
|
||||||
# Commented out to not explicitly specify Python3 subversion.
|
|
||||||
|
# Commented out to not explicitly specify Python 3 subversion.
|
||||||
# [requires]
|
# [requires]
|
||||||
# python_version = "3.8"
|
# python_version = "3.8"
|
||||||
|
@@ -1,14 +1,14 @@
|
|||||||
# lostplaces-backend
|
# lostplaces-backend
|
||||||
|
|
||||||
lostplaces-backend is a django 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.
|
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 ist currently in early development status, neither scope, datalmodel(s) nor features are finalized yet.
|
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.
|
||||||
|
|
||||||
## Dependencies
|
## Dependencies
|
||||||
Right now it depends on the following non-core Python 3 libraries. These can be installed using the package manager of your distribution or into the venv locally.
|
Right now it depends on the following non-core Python 3 libraries. These can be installed using the package manager of your distribution or into the venv locally.
|
||||||
|
|
||||||
* [django](https://www.djangoproject.com/) django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
|
* [django](https://www.djangoproject.com/) django is a high-level Python Web framework that encourages rapid development and clean, pragmatic design.
|
||||||
* [django-thumbs-v2](https://github.com/rrmerugu/django-thumbs-v2) Create thumbnails for your images with django.
|
* [easy-thumbnails](https://github.com/SmileyChris/easy-thumbnails) A powerful, yet easy to implement thumbnailing application for Django 1.11+
|
||||||
|
|
||||||
### Setting up a (pipenv) virtual environment for development
|
### Setting up a (pipenv) virtual environment for development
|
||||||
|
|
||||||
|
@@ -14,6 +14,7 @@ https://docs.djangoproject.com/en/3.0/ref/settings/
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
from django.urls import reverse_lazy
|
||||||
|
|
||||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||||
@@ -42,7 +43,7 @@ INSTALLED_APPS = [
|
|||||||
'django.contrib.messages',
|
'django.contrib.messages',
|
||||||
'django.contrib.staticfiles',
|
'django.contrib.staticfiles',
|
||||||
'easy_thumbnails',
|
'easy_thumbnails',
|
||||||
'widget_tweaks',
|
'widget_tweaks',
|
||||||
]
|
]
|
||||||
|
|
||||||
MIDDLEWARE = [
|
MIDDLEWARE = [
|
||||||
@@ -138,10 +139,12 @@ AUTH_USER_MODEL = 'lostplaces_app.Explorer'
|
|||||||
LOGIN_REDIRECT_URL = 'home'
|
LOGIN_REDIRECT_URL = 'home'
|
||||||
LOGOUT_REDIRECT_URL = 'home'
|
LOGOUT_REDIRECT_URL = 'home'
|
||||||
|
|
||||||
|
LOGIN_URL = reverse_lazy('login')
|
||||||
|
|
||||||
THUMBNAIL_ALIASES = {
|
THUMBNAIL_ALIASES = {
|
||||||
'': {
|
'': {
|
||||||
'thumbnail': {'size': (300, 300), 'crop': False},
|
'thumbnail': {'size': (300, 300), 'crop': False},
|
||||||
'hero': {'size': (700, 700), 'crop': False},
|
'hero': {'size': (700, 700), 'crop': False},
|
||||||
'large': {'size': (1920, 1920), 'crop': False},
|
'large': {'size': (1920, 1920), 'crop': False},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@@ -19,6 +19,7 @@ class ExplorerCreationForm(UserCreationForm):
|
|||||||
try:
|
try:
|
||||||
fetched_voucher = Voucher.objects.get(code=sumitted_voucher)
|
fetched_voucher = Voucher.objects.get(code=sumitted_voucher)
|
||||||
except Voucher.DoesNotExist:
|
except Voucher.DoesNotExist:
|
||||||
|
self.add_error('voucher', 'Invalid voucher')
|
||||||
return False
|
return False
|
||||||
|
|
||||||
fetched_voucher.delete()
|
fetched_voucher.delete()
|
||||||
|
@@ -1,67 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-07-28 19:00
|
|
||||||
|
|
||||||
import django.contrib.auth.models
|
|
||||||
import django.contrib.auth.validators
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
import django.utils.timezone
|
|
||||||
import django_thumbs.fields
|
|
||||||
import lostplaces_app.models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
initial = True
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('auth', '0011_update_proxy_permissions'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
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)),
|
|
||||||
('location', models.CharField(max_length=50)),
|
|
||||||
('latitude', models.FloatField()),
|
|
||||||
('longitude', models.FloatField()),
|
|
||||||
('description', models.TextField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='PlaceImage',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('filename', django_thumbs.fields.ImageThumbsField(max_length=50, sizes=({'code': 'thumbnail', 'wxh': '390x390'}, {'code': 'hero', 'wxh': '700x700'}, {'code': 'large', 'wxh': '1920x1920'}), upload_to=lostplaces_app.models.generate_image_upload_path)),
|
|
||||||
('description', models.TextField(blank=True)),
|
|
||||||
('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='images', to='lostplaces_app.Place')),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Explorer',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('password', models.CharField(max_length=128, verbose_name='password')),
|
|
||||||
('last_login', models.DateTimeField(blank=True, null=True, verbose_name='last login')),
|
|
||||||
('is_superuser', models.BooleanField(default=False, help_text='Designates that this user has all permissions without explicitly assigning them.', verbose_name='superuser status')),
|
|
||||||
('username', models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username')),
|
|
||||||
('first_name', models.CharField(blank=True, max_length=30, verbose_name='first name')),
|
|
||||||
('last_name', models.CharField(blank=True, max_length=150, verbose_name='last name')),
|
|
||||||
('email', models.EmailField(blank=True, max_length=254, verbose_name='email address')),
|
|
||||||
('is_staff', models.BooleanField(default=False, help_text='Designates whether the user can log into this admin site.', verbose_name='staff status')),
|
|
||||||
('is_active', models.BooleanField(default=True, help_text='Designates whether this user should be treated as active. Unselect this instead of deleting accounts.', verbose_name='active')),
|
|
||||||
('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')),
|
|
||||||
('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')),
|
|
||||||
('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')),
|
|
||||||
],
|
|
||||||
options={
|
|
||||||
'verbose_name': 'user',
|
|
||||||
'verbose_name_plural': 'users',
|
|
||||||
'abstract': False,
|
|
||||||
},
|
|
||||||
managers=[
|
|
||||||
('objects', django.contrib.auth.models.UserManager()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-07-29 16:29
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0001_initial'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='place',
|
|
||||||
name='submitted_by',
|
|
||||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-07-29 18:22
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0002_place_submitted_by'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
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=settings.AUTH_USER_MODEL),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-07-30 09:18
|
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django.db import migrations, models
|
|
||||||
import django.db.models.deletion
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0003_auto_20200729_1822'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='placeimage',
|
|
||||||
name='submitted_by',
|
|
||||||
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='images', to=settings.AUTH_USER_MODEL),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-08-01 10:29
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0004_placeimage_submitted_by'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.CreateModel(
|
|
||||||
name='Voucher',
|
|
||||||
fields=[
|
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
|
||||||
('code', models.CharField(max_length=10)),
|
|
||||||
('created', models.DateField(auto_now_add=True)),
|
|
||||||
('expires', models.DateField()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,22 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-08-01 10:37
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0005_voucher'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.RemoveField(
|
|
||||||
model_name='voucher',
|
|
||||||
name='id',
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='voucher',
|
|
||||||
name='code',
|
|
||||||
field=models.CharField(max_length=10, primary_key=True, serialize=False, unique=True),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-08-01 10:39
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0006_auto_20200801_1037'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='voucher',
|
|
||||||
name='created',
|
|
||||||
field=models.DateTimeField(auto_now_add=True),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,24 +0,0 @@
|
|||||||
# Generated by Django 3.0.8 on 2020-08-01 10:44
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0007_auto_20200801_1039'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='voucher',
|
|
||||||
name='id',
|
|
||||||
field=models.AutoField(auto_created=True, default=0, primary_key=True, serialize=False, verbose_name='ID'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='voucher',
|
|
||||||
name='code',
|
|
||||||
field=models.CharField(max_length=10, unique=True),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,18 +0,0 @@
|
|||||||
# Generated by Django 3.0.9 on 2020-08-03 16:36
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0008_auto_20200801_1044'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='place',
|
|
||||||
name='submitted_when',
|
|
||||||
field=models.DateTimeField(auto_now_add=True, null=True),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -1,20 +0,0 @@
|
|||||||
# Generated by Django 3.0.9 on 2020-08-03 17:07
|
|
||||||
|
|
||||||
from django.db import migrations
|
|
||||||
import easy_thumbnails.fields
|
|
||||||
import lostplaces_app.models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('lostplaces_app', '0009_place_submitted_when'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AlterField(
|
|
||||||
model_name='placeimage',
|
|
||||||
name='filename',
|
|
||||||
field=easy_thumbnails.fields.ThumbnailerImageField(upload_to=lostplaces_app.models.generate_image_upload_path),
|
|
||||||
),
|
|
||||||
]
|
|
@@ -14,115 +14,115 @@ from easy_thumbnails.fields import ThumbnailerImageField
|
|||||||
# Create your models here.
|
# Create your models here.
|
||||||
|
|
||||||
class Explorer(AbstractUser):
|
class Explorer(AbstractUser):
|
||||||
"""
|
"""
|
||||||
Custom user model
|
Custom user model
|
||||||
Addtional fields wbd
|
Addtional fields wbd
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.username
|
return self.username
|
||||||
|
|
||||||
class Voucher(models.Model):
|
class Voucher(models.Model):
|
||||||
"""
|
"""
|
||||||
Vouchers are authorization tokens to allow the registration of new users.
|
Vouchers are authorization tokens to allow the registration of new users.
|
||||||
A voucher has a code, a creation and a deletion date, which are all positional.
|
A voucher has a code, a creation and a deletion date, which are all positional.
|
||||||
Creation date is being set automatically during voucher creation.
|
Creation date is being set automatically during voucher creation.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
code = models.CharField(unique=True, max_length=10)
|
code = models.CharField(unique=True, max_length=10)
|
||||||
created = models.DateTimeField(auto_now_add=True)
|
created = models.DateTimeField(auto_now_add=True)
|
||||||
expires = models.DateField()
|
expires = models.DateField()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "Voucher " + str(self.pk)
|
return "Voucher " + str(self.pk)
|
||||||
|
|
||||||
class Place (models.Model):
|
class Place (models.Model):
|
||||||
"""
|
"""
|
||||||
Place defines a lost place (location, name, description etc.).
|
Place defines a lost place (location, name, description etc.).
|
||||||
"""
|
"""
|
||||||
|
|
||||||
name = models.CharField(max_length=50)
|
name = models.CharField(max_length=50)
|
||||||
submitted_when = models.DateTimeField(auto_now_add=True, null=True)
|
submitted_when = models.DateTimeField(auto_now_add=True, null=True)
|
||||||
submitted_by = models.ForeignKey(
|
submitted_by = models.ForeignKey(
|
||||||
Explorer,
|
Explorer,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
related_name='places'
|
related_name='places'
|
||||||
)
|
)
|
||||||
location = models.CharField(max_length=50)
|
location = models.CharField(max_length=50)
|
||||||
latitude = models.FloatField()
|
latitude = models.FloatField()
|
||||||
longitude = models.FloatField()
|
longitude = models.FloatField()
|
||||||
description = models.TextField()
|
description = models.TextField()
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
def generate_image_upload_path(instance, filename):
|
def generate_image_upload_path(instance, filename):
|
||||||
"""
|
"""
|
||||||
Callback for generating path for uploaded images.
|
Callback for generating path for uploaded images.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return 'places/' + str(uuid.uuid4())+'.'+filename.split('.')[-1]
|
return 'places/' + str(uuid.uuid4())+'.'+filename.split('.')[-1]
|
||||||
|
|
||||||
class PlaceImage (models.Model):
|
class PlaceImage (models.Model):
|
||||||
"""
|
"""
|
||||||
PlaceImage defines an image file object that points to a file in uploads/.
|
PlaceImage defines an image file object that points to a file in uploads/.
|
||||||
Intermediate image sizes are generated as defined in SIZES.
|
Intermediate image sizes are generated as defined in SIZES.
|
||||||
PlaceImage references a Place to which it belongs.
|
PlaceImage references a Place to which it belongs.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
description = models.TextField(blank=True)
|
description = models.TextField(blank=True)
|
||||||
filename = ThumbnailerImageField(upload_to=generate_image_upload_path)
|
filename = ThumbnailerImageField(upload_to=generate_image_upload_path)
|
||||||
place = models.ForeignKey(
|
place = models.ForeignKey(
|
||||||
Place,
|
Place,
|
||||||
on_delete=models.CASCADE,
|
on_delete=models.CASCADE,
|
||||||
related_name='images'
|
related_name='images'
|
||||||
)
|
)
|
||||||
submitted_by = models.ForeignKey(
|
submitted_by = models.ForeignKey(
|
||||||
Explorer,
|
Explorer,
|
||||||
on_delete=models.SET_NULL,
|
on_delete=models.SET_NULL,
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
related_name='images'
|
related_name='images'
|
||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
"""
|
"""
|
||||||
Returning the name of the corresponding place + id
|
Returning the name of the corresponding place + id
|
||||||
of this image as textual represntation of this instance
|
of this image as textual represntation of this instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return ' '.join([self.place.name, str(self.pk)])
|
return ' '.join([self.place.name, str(self.pk)])
|
||||||
|
|
||||||
# These two auto-delete files from filesystem when they are unneeded:
|
# These two auto-delete files from filesystem when they are unneeded:
|
||||||
|
|
||||||
@receiver(models.signals.post_delete, sender=PlaceImage)
|
@receiver(models.signals.post_delete, sender=PlaceImage)
|
||||||
def auto_delete_file_on_delete(sender, instance, **kwargs):
|
def auto_delete_file_on_delete(sender, instance, **kwargs):
|
||||||
"""
|
"""
|
||||||
Deletes file from filesystem
|
Deletes file from filesystem
|
||||||
when corresponding `PlaceImage` object is deleted.
|
when corresponding `PlaceImage` object is deleted.
|
||||||
"""
|
"""
|
||||||
if instance.filename:
|
if instance.filename:
|
||||||
if os.path.isfile(instance.filename.path):
|
if os.path.isfile(instance.filename.path):
|
||||||
os.remove(instance.filename.path)
|
os.remove(instance.filename.path)
|
||||||
|
|
||||||
@receiver(models.signals.pre_save, sender=PlaceImage)
|
@receiver(models.signals.pre_save, sender=PlaceImage)
|
||||||
def auto_delete_file_on_change(sender, instance, **kwargs):
|
def auto_delete_file_on_change(sender, instance, **kwargs):
|
||||||
"""
|
"""
|
||||||
Deletes old file from filesystem
|
Deletes old file from filesystem
|
||||||
when corresponding `PlaceImage` object is updated
|
when corresponding `PlaceImage` object is updated
|
||||||
with new file.
|
with new file.
|
||||||
"""
|
"""
|
||||||
if not instance.pk:
|
if not instance.pk:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
try:
|
try:
|
||||||
old_file = PlaceImage.objects.get(pk=instance.pk).filename
|
old_file = PlaceImage.objects.get(pk=instance.pk).filename
|
||||||
except PlaceImage.DoesNotExist:
|
except PlaceImage.DoesNotExist:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
new_file = instance.filename
|
new_file = instance.filename
|
||||||
if not old_file == new_file:
|
if not old_file == new_file:
|
||||||
if os.path.isfile(old_file.path):
|
if os.path.isfile(old_file.path):
|
||||||
os.remove(old_file.path)
|
os.remove(old_file.path)
|
||||||
|
@@ -1,173 +0,0 @@
|
|||||||
@font-face {
|
|
||||||
font-family: 'Crimson Text';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Crimson Text Italic'), local('CrimsonText-Italic'), url(static/fonts/CrimsonText-Italic.ttf) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Crimson Text';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Crimson Text SemiBold Italic'), local('CrimsonText-SemiBoldItalic'), url(static/fonts/CrimsonText-SemiBoldItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Crimson Text';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Crimson Text Bold Italic'), local('CrimsonText-BoldItalic'), url(static/fonts/CrimsonText-BoldItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Crimson Text';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Crimson Text Regular'), local('CrimsonText-Regular'), url(static/fonts/CrimsonText-Regular) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Crimson Text';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Crimson Text SemiBold'), local('CrimsonText-SemiBold'), url(static/fonts/CrimsonText-SemiBold) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Crimson Text';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Crimson Text Bold'), local('CrimsonText-Bold'), url(static/fonts/CrimsonText-Bold) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Thin Italic'), local('Montserrat-ThinItalic'), url(static/fonts/Montserrat-ThinItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat ExtraLight Italic'), local('Montserrat-ExtraLightItalic'), url(static/fonts/Montserrat-ExtraLightItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Light Italic'), local('Montserrat-LightItalic'), url(static/fonts/Montserrat-LightItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Italic'), local('Montserrat-Italic'), url(static/fonts/Montserrat-Italic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Medium Italic'), local('Montserrat-MediumItalic'), url(static/fonts/Montserrat-MediumItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat SemiBold Italic'), local('Montserrat-SemiBoldItalic'), url(static/fonts/Montserrat-SemiBoldItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Bold Italic'), local('Montserrat-BoldItalic'), url(static/fonts/Montserrat-BoldItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat ExtraBold Italic'), local('Montserrat-ExtraBoldItalic'), url(static/fonts/Montserrat-ExtraBoldItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: italic;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Black Italic'), local('Montserrat-BlackItalic'), url(static/fonts/Montserrat-BlackItalic) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 100;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Thin'), local('Montserrat-Thin'), url(static/fonts/Montserrat-Thin) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 200;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat ExtraLight'), local('Montserrat-ExtraLight'), url(static/fonts/Montserrat-ExtraLight) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 300;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Light'), local('Montserrat-Light'), url(static/fonts/Montserrat-Light) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 400;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Regular'), local('Montserrat-Regular'), url(static/fonts/Montserrat-Regular) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 500;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Medium'), local('Montserrat-Medium'), url(static/fonts/Montserrat-Medium) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 600;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat SemiBold'), local('Montserrat-SemiBold'), url(static/fonts/Montserrat-SemiBold) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 700;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Bold'), local('Montserrat-Bold'), url(static/fonts/Montserrat-Bold) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 800;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat ExtraBold'), local('Montserrat-ExtraBold'), url(static/fonts/Montserrat-ExtraBold) format('truetype');
|
|
||||||
}
|
|
||||||
@font-face {
|
|
||||||
font-family: 'Montserrat';
|
|
||||||
font-style: normal;
|
|
||||||
font-weight: 900;
|
|
||||||
font-display: swap;
|
|
||||||
src: local('Montserrat Black'), local('Montserrat-Black'), url(static/fonts/Montserrat-Black) format('truetype');
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
font-family: 'Crimson Text', serif;
|
|
||||||
font-family: 'Montserrat', sans-serif;
|
|
||||||
*/
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
lostplaces/lostplaces_app/static/icons/debug.png
Normal file
BIN
lostplaces/lostplaces_app/static/icons/debug.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
BIN
lostplaces/lostplaces_app/static/icons/error.png
Normal file
BIN
lostplaces/lostplaces_app/static/icons/error.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 30" width="30px" height="30px"><path d="M 3 7 A 1.0001 1.0001 0 1 0 3 9 L 27 9 A 1.0001 1.0001 0 1 0 27 7 L 3 7 z M 3 14 A 1.0001 1.0001 0 1 0 3 16 L 27 16 A 1.0001 1.0001 0 1 0 27 14 L 3 14 z M 3 21 A 1.0001 1.0001 0 1 0 3 23 L 27 23 A 1.0001 1.0001 0 1 0 27 21 L 3 21 z"/></svg>
|
After Width: | Height: | Size: 351 B |
1
lostplaces/lostplaces_app/static/icons/information.svg
Normal file
1
lostplaces/lostplaces_app/static/icons/information.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="50px" height="50px"><path d="M 25 2 C 12.309295 2 2 12.309295 2 25 C 2 37.690705 12.309295 48 25 48 C 37.690705 48 48 37.690705 48 25 C 48 12.309295 37.690705 2 25 2 z M 25 4 C 36.609824 4 46 13.390176 46 25 C 46 36.609824 36.609824 46 25 46 C 13.390176 46 4 36.609824 4 25 C 4 13.390176 13.390176 4 25 4 z M 25 11 A 3 3 0 0 0 22 14 A 3 3 0 0 0 25 17 A 3 3 0 0 0 28 14 A 3 3 0 0 0 25 11 z M 21 21 L 21 23 L 22 23 L 23 23 L 23 36 L 22 36 L 21 36 L 21 38 L 22 38 L 23 38 L 27 38 L 28 38 L 29 38 L 29 36 L 28 36 L 27 36 L 27 21 L 26 21 L 22 21 L 21 21 z"/></svg>
|
After Width: | Height: | Size: 641 B |
1
lostplaces/lostplaces_app/static/icons/message.svg
Normal file
1
lostplaces/lostplaces_app/static/icons/message.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200"><defs><style>.cls-1{fill:#231f20;}</style></defs><title>Wondicon - UI (Free)</title><path class="cls-1" d="M125,177.86a5,5,0,0,1-4.74-3.42L96,101.76,27.64,77.57a5,5,0,0,1,.2-9.49L169.22,24.53a5,5,0,0,1,6.23,6.3L129.76,174.37a5,5,0,0,1-4.73,3.49ZM45.23,73.19l56.44,20a5,5,0,0,1,3.07,3.13l20.15,60.44L163,36.9Z"/><path class="cls-1" d="M100,102.84a4.94,4.94,0,0,1-3.59-1.52,5,5,0,0,1,.11-7.07L131.86,60a5,5,0,0,1,7,7.18l-35.35,34.26A5,5,0,0,1,100,102.84Z"/><path class="cls-1" d="M75,175.69a5,5,0,0,1-3.19-8.85l25-20.69a5,5,0,0,1,6.38,7.7l-25,20.69A5,5,0,0,1,75,175.69Z"/><path class="cls-1" d="M29.31,175.69a5,5,0,0,1-3.53-8.54l45.68-45.69a5,5,0,0,1,7.08,7.08L32.85,174.22A5,5,0,0,1,29.31,175.69Z"/><path class="cls-1" d="M29.31,130a5,5,0,0,1-3.85-8.19l20.69-25a5,5,0,0,1,7.7,6.38l-20.69,25A5,5,0,0,1,29.31,130Z"/></svg>
|
After Width: | Height: | Size: 914 B |
3
lostplaces/lostplaces_app/static/icons/success.svg
Normal file
3
lostplaces/lostplaces_app/static/icons/success.svg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?xml version="1.0" ?><svg style="enable-background:new 0 0 24 24;" version="1.1" viewBox="0 0 24 24" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><style type="text/css">
|
||||||
|
.st0{display:none;}
|
||||||
|
</style><g class="st0" id="grid"/><g id="icon"><path d="M12,0C5.383,0,0,5.383,0,12s5.383,12,12,12s12-5.383,12-12S18.617,0,12,0z M12,23C5.935,23,1,18.065,1,12S5.935,1,12,1 s11,4.935,11,11S18.065,23,12,23z"/><path d="M16.801,8.403l-6.132,6.133L7.753,11.62c-0.195-0.195-0.512-0.195-0.707,0s-0.195,0.512,0,0.707l3.27,3.27 c0.094,0.094,0.221,0.146,0.354,0.146s0.26-0.053,0.354-0.146l6.485-6.486c0.195-0.195,0.195-0.512,0-0.707 S16.997,8.208,16.801,8.403z"/></g></svg>
|
After Width: | Height: | Size: 714 B |
@@ -4,7 +4,94 @@
|
|||||||
|
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: Montserrat;
|
font-family: Montserrat;
|
||||||
src: url("fonts/Montserrat/Montserrat-Regular.otf"), url("fonts/Montserrat/Montserrat-Bold.otf"), url("fonts/Montserrat/Montserrat-Italic.otf"); }
|
src: url("fonts/Montserrat/Montserrat-Regular.ttf"), url("fonts/Montserrat/Montserrat-Bold.ttf"), url("fonts/Montserrat/Montserrat-Italic.ttf"); }
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0; }
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 100%;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0; }
|
||||||
|
|
||||||
|
.LP-Wrapper__Site {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 250px 1fr;
|
||||||
|
grid-template-rows: auto 1fr;
|
||||||
|
grid-template-areas: "header header" "sidebar content";
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
min-height: 100vh; }
|
||||||
|
|
||||||
|
.LP-Main__Content {
|
||||||
|
min-height: 1px;
|
||||||
|
padding: 25px;
|
||||||
|
grid-area: content; }
|
||||||
|
|
||||||
|
.LP-Main__Sidebar {
|
||||||
|
grid-area: sidebar;
|
||||||
|
background-color: #f9f9f9; }
|
||||||
|
|
||||||
|
.LP-Section {
|
||||||
|
clear: both;
|
||||||
|
padding: 25px 0px;
|
||||||
|
padding-left: 25px; }
|
||||||
|
.LP-Section .LP-Headline {
|
||||||
|
margin-left: -25px; }
|
||||||
|
|
||||||
|
.LP-Menu__Trigger {
|
||||||
|
display: none; }
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.LP-Wrapper__Site {
|
||||||
|
grid-template-columns: 187.5px 1fr; } }
|
||||||
|
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.LP-Section {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0; }
|
||||||
|
.LP-Section .LP-Headline {
|
||||||
|
margin: 0; } }
|
||||||
|
|
||||||
|
@media (max-width: 450px) {
|
||||||
|
.LP-Main__Sidebar {
|
||||||
|
max-width: 100vw; } }
|
||||||
|
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.LP-Wrapper__Site {
|
||||||
|
grid-template-columns: 0 1fr; }
|
||||||
|
.LP-Main__Sidebar {
|
||||||
|
grid-area: unset;
|
||||||
|
width: 250px;
|
||||||
|
z-index: 15;
|
||||||
|
position: fixed;
|
||||||
|
left: -251px;
|
||||||
|
height: 100vh;
|
||||||
|
top: 60px;
|
||||||
|
border-right: 1px solid #C09F80;
|
||||||
|
transition: left 0.3s; }
|
||||||
|
.LP-Main__Sidebar--hidden {
|
||||||
|
visibility: hidden; }
|
||||||
|
#toggle_sidebar:checked ~ .LP-Main__Sidebar {
|
||||||
|
left: 0; }
|
||||||
|
#toggle_sidebar ~ .LP-Main__Sidebar {
|
||||||
|
left: -251px; }
|
||||||
|
.LP-Menu__TriggerLabel {
|
||||||
|
z-index: 20;
|
||||||
|
height: 60px;
|
||||||
|
width: 60px;
|
||||||
|
background-image: url("icons/hamburger_menu.svg");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-clip: content-box;
|
||||||
|
background-position: center;
|
||||||
|
position: fixed; }
|
||||||
|
.LP-Menu__Trigger:checked ~ .LP-Menu__TriggerLabel {
|
||||||
|
background-color: darkgray;
|
||||||
|
filter: invert(1); }
|
||||||
|
.LP-Main__Content {
|
||||||
|
margin-top: 60px; } }
|
||||||
|
|
||||||
.LP-Link {
|
.LP-Link {
|
||||||
color: #565656;
|
color: #565656;
|
||||||
@@ -27,7 +114,7 @@
|
|||||||
padding-top: 0px;
|
padding-top: 0px;
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
margin-bottom: 0px; }
|
margin-bottom: 25px; }
|
||||||
.LP-Headline--main {
|
.LP-Headline--main {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 2rem;
|
top: 2rem;
|
||||||
@@ -38,7 +125,9 @@
|
|||||||
.LP-Paragraph {
|
.LP-Paragraph {
|
||||||
color: black;
|
color: black;
|
||||||
font-family: Crimson, Times, serif;
|
font-family: Crimson, Times, serif;
|
||||||
font-size: 1.2rem; }
|
font-size: 1.2rem;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0; }
|
||||||
|
|
||||||
.LP-Icon {
|
.LP-Icon {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
@@ -59,12 +148,17 @@
|
|||||||
border: none;
|
border: none;
|
||||||
padding: 8px 14px;
|
padding: 8px 14px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
font-weight: bold; }
|
font-weight: bold;
|
||||||
|
cursor: pointer; }
|
||||||
.LP-Button:active {
|
.LP-Button:active {
|
||||||
background-color: #76323F;
|
background-color: #76323F;
|
||||||
color: #f9f9f9; }
|
color: #f9f9f9; }
|
||||||
.LP-Button--cancel {
|
.LP-Button--cancel {
|
||||||
background-color: #f9f9f9; }
|
background-color: #565656;
|
||||||
|
color: #f9f9f9; }
|
||||||
|
.LP-Button--cancel:active {
|
||||||
|
color: #565656;
|
||||||
|
background-color: #f9f9f9; }
|
||||||
|
|
||||||
.LP-Form .LP-Form__Checkbox {
|
.LP-Form .LP-Form__Checkbox {
|
||||||
display: none; }
|
display: none; }
|
||||||
@@ -92,6 +186,17 @@
|
|||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
border-radius: 3px 3px 0 0;
|
border-radius: 3px 3px 0 0;
|
||||||
box-shadow: none; }
|
box-shadow: none; }
|
||||||
|
.LP-Input .LP-Input__Field[type=submit] {
|
||||||
|
background-color: #C09F80;
|
||||||
|
color: #565656;
|
||||||
|
border: none;
|
||||||
|
padding: 8px 14px;
|
||||||
|
border-radius: 2px;
|
||||||
|
font-weight: bold;
|
||||||
|
cursor: pointer; }
|
||||||
|
.LP-Input .LP-Input__Field[type=submit]:active {
|
||||||
|
background-color: #76323F;
|
||||||
|
color: #f9f9f9; }
|
||||||
.LP-Input .LP-Input__Label {
|
.LP-Input .LP-Input__Label {
|
||||||
font-family: Montserrat, Helvetica, sans-serif;
|
font-family: Montserrat, Helvetica, sans-serif;
|
||||||
font-size: 16px; }
|
font-size: 16px; }
|
||||||
@@ -126,7 +231,9 @@
|
|||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
vertical-align: top; }
|
vertical-align: top;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0; }
|
||||||
|
|
||||||
.LP-Logo {
|
.LP-Logo {
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -146,6 +253,103 @@
|
|||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
display: inline; }
|
display: inline; }
|
||||||
|
|
||||||
|
.LP-Message {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: stretch;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
font-family: Montserrat, Helvetica, sans-serif;
|
||||||
|
border-radius: 3px;
|
||||||
|
font-weight: bold;
|
||||||
|
box-shadow: 0 0 2px #565656;
|
||||||
|
overflow: hidden; }
|
||||||
|
.LP-Message--error .LP-Message__Icon {
|
||||||
|
background-color: #02979e;
|
||||||
|
background-image: url("icons/error.png"); }
|
||||||
|
.LP-Message--warning .LP-Message__Icon {
|
||||||
|
background-color: #0047e7;
|
||||||
|
background-image: url("icons/error.png"); }
|
||||||
|
.LP-Message--info .LP-Message__Icon {
|
||||||
|
background-color: #522719;
|
||||||
|
background-image: url("icons/information.svg"); }
|
||||||
|
.LP-Message--success .LP-Message__Icon {
|
||||||
|
background-color: #6937ff;
|
||||||
|
background-image: url("icons/success.svg"); }
|
||||||
|
.LP-Message--debug .LP-Message__Icon {
|
||||||
|
background-color: #046a2f;
|
||||||
|
background-image: url("icons/debug.png"); }
|
||||||
|
.LP-Message .LP-Message__Icon {
|
||||||
|
background-size: 40px 40px;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center;
|
||||||
|
height: 100%;
|
||||||
|
min-height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
filter: invert(1);
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 0; }
|
||||||
|
.LP-Message .LP-Message__Text {
|
||||||
|
padding: 0 15px;
|
||||||
|
flex-grow: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 8px; }
|
||||||
|
|
||||||
|
.LP-Pagination {
|
||||||
|
font-family: Montserrat, Helvetica, sans-serif;
|
||||||
|
font-weight: bold;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: center; }
|
||||||
|
.LP-Pagination .LP-Pagination__List {
|
||||||
|
list-style-type: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item {
|
||||||
|
margin: 0 4px; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item--disabled {
|
||||||
|
color: #b6b6b6; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item--disabled .LP-Link {
|
||||||
|
color: #b6b6b6;
|
||||||
|
cursor: default; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item--disabled .LP-Link:hover {
|
||||||
|
background-color: unset;
|
||||||
|
color: unset; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item--current .LP-Link {
|
||||||
|
background-color: #D7CEC7; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item--current .LP-Link:hover {
|
||||||
|
background-color: #D7CEC7;
|
||||||
|
color: #565656; }
|
||||||
|
.LP-Pagination .LP-Link {
|
||||||
|
padding: 15px 20px;
|
||||||
|
vertical-align: sub;
|
||||||
|
border-radius: 2px; }
|
||||||
|
.LP-Pagination .LP-Link:active, .LP-Pagination .LP-Link:hover {
|
||||||
|
background-color: #D7CEC7;
|
||||||
|
color: #565656; }
|
||||||
|
.LP-Pagination .LP-Icon {
|
||||||
|
font-size: larger; }
|
||||||
|
|
||||||
|
@media (max-width: 1000px) {
|
||||||
|
.LP-Pagination .LP-Link {
|
||||||
|
padding: 10px 15px; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item--other .LP-Text {
|
||||||
|
display: none; } }
|
||||||
|
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.LP-Pagination .LP-Pagination__Item {
|
||||||
|
margin: 0 1px; }
|
||||||
|
.LP-Pagination .LP-Pagination__Item .LP-Link {
|
||||||
|
padding: 13px 16px; } }
|
||||||
|
|
||||||
|
@media (max-width: 450px) {
|
||||||
|
.LP-Pagination .LP-Pagination__Item .LP-Link {
|
||||||
|
padding: 8px 11px; } }
|
||||||
|
|
||||||
.LP-Content {
|
.LP-Content {
|
||||||
padding: 35px; }
|
padding: 35px; }
|
||||||
|
|
||||||
@@ -170,7 +374,9 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding-bottom: 10px; }
|
padding: 5px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
padding-top: 10px; }
|
||||||
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Paragraph {
|
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Paragraph {
|
||||||
font-family: Montserrat, Helvetica, sans-serif;
|
font-family: Montserrat, Helvetica, sans-serif;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -252,18 +458,28 @@
|
|||||||
.LP-Menu .LP-Link__Text:hover {
|
.LP-Menu .LP-Link__Text:hover {
|
||||||
color: #76323F; }
|
color: #76323F; }
|
||||||
.LP-Menu--sidebar {
|
.LP-Menu--sidebar {
|
||||||
border: none;
|
border-top: 1px solid #C09F80;
|
||||||
min-width: 80px; }
|
border-left: none;
|
||||||
|
min-width: 60px;
|
||||||
|
background-color: #f9f9f9;
|
||||||
|
padding-top: 25px; }
|
||||||
.LP-Menu--sidebar .LP-Menu__List {
|
.LP-Menu--sidebar .LP-Menu__List {
|
||||||
flex-direction: column; }
|
flex-direction: column; }
|
||||||
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item {
|
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-left: 1px solid #C09F80;
|
margin-bottom: 10px;
|
||||||
margin-bottom: 10px; }
|
padding-left: 25px; }
|
||||||
|
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item--additional {
|
||||||
|
background-color: #ccc; }
|
||||||
|
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item .LP-Link {
|
||||||
|
line-height: 1em; }
|
||||||
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item:last-child {
|
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item:last-child {
|
||||||
margin-bottom: 0; }
|
margin-bottom: 0; }
|
||||||
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item .LP-Link:hover {
|
.LP-Menu--sidebar .LP-Menu__List .LP-Menu__Item:hover {
|
||||||
background-color: #f9f9f9; }
|
border-right: 2px solid #C09F80;
|
||||||
|
position: relative;
|
||||||
|
background-color: #D7CEC7;
|
||||||
|
color: #76323F; }
|
||||||
|
|
||||||
@media (max-width: 750px) {
|
@media (max-width: 750px) {
|
||||||
.LP-Menu:not(.LP-Menu--sidebar) .LP-Menu__List {
|
.LP-Menu:not(.LP-Menu--sidebar) .LP-Menu__List {
|
||||||
@@ -277,23 +493,38 @@
|
|||||||
.LP-Menu .LP-Menu__List {
|
.LP-Menu .LP-Menu__List {
|
||||||
justify-content: space-between; } }
|
justify-content: space-between; } }
|
||||||
|
|
||||||
|
.LP-MessageList {
|
||||||
|
padding: 25px; }
|
||||||
|
.LP-MessageList .LP-MessageList__List {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between; }
|
||||||
|
.LP-MessageList .LP-MessageList__Item {
|
||||||
|
margin: 5px 0; }
|
||||||
|
|
||||||
.LP-Header {
|
.LP-Header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
margin-bottom: 70px;
|
height: 60px;
|
||||||
height: 60px; }
|
box-shadow: 0 0 2px #C09F80;
|
||||||
|
grid-area: header;
|
||||||
|
background-color: white;
|
||||||
|
padding-left: 25px; }
|
||||||
.LP-Header__Navigation {
|
.LP-Header__Navigation {
|
||||||
flex-grow: 2; }
|
flex-grow: 2; }
|
||||||
.LP-Header__Logo {
|
.LP-Header__Logo {
|
||||||
height: 60px;
|
height: 45px;
|
||||||
margin: 25px;
|
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
max-height: 100%;
|
max-height: 100%;
|
||||||
|
width: 225px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
flex-shrink: 0; }
|
flex-shrink: 0; }
|
||||||
.LP-Header__Logo .LP-Image {
|
.LP-Header__Logo .LP-Image {
|
||||||
height: 60px; }
|
height: 100%; }
|
||||||
|
|
||||||
.LP-Header__UserInformation {
|
.LP-Header__UserInformation {
|
||||||
margin-right: 3%; }
|
margin-right: 3%; }
|
||||||
@@ -306,7 +537,7 @@
|
|||||||
|
|
||||||
@media (max-width: 750px) {
|
@media (max-width: 750px) {
|
||||||
.LP-Header__Logo {
|
.LP-Header__Logo {
|
||||||
width: 60px; }
|
width: 45px; }
|
||||||
.LP-Header__Logo .LP-Image {
|
.LP-Header__Logo .LP-Image {
|
||||||
object-position: 0 0;
|
object-position: 0 0;
|
||||||
object-fit: cover; } }
|
object-fit: cover; } }
|
||||||
@@ -317,6 +548,13 @@
|
|||||||
.LP-Header__Navigation {
|
.LP-Header__Navigation {
|
||||||
width: 100%; } }
|
width: 100%; } }
|
||||||
|
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.LP-Header {
|
||||||
|
padding-left: 60px;
|
||||||
|
width: calc(100% - 60px);
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10; } }
|
||||||
|
|
||||||
.LP-PlaceGrid .LP-PlaceGrid__Grid {
|
.LP-PlaceGrid .LP-PlaceGrid__Grid {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
@@ -340,9 +578,11 @@
|
|||||||
border-left: 2px #565656 solid; }
|
border-left: 2px #565656 solid; }
|
||||||
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
min-width: 450px;
|
|
||||||
margin: 18px 0; }
|
margin: 18px 0; }
|
||||||
|
|
||||||
|
.LP-PlaceList .LP-Pagination {
|
||||||
|
margin-top: 50px; }
|
||||||
|
|
||||||
.LP-LinkList__List {
|
.LP-LinkList__List {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
display: grid;
|
display: grid;
|
||||||
@@ -351,11 +591,11 @@
|
|||||||
padding: 0; }
|
padding: 0; }
|
||||||
.LP-LinkList__List .LP-LinkList__Item {
|
.LP-LinkList__List .LP-LinkList__Item {
|
||||||
border-left: 1px solid #C09F80;
|
border-left: 1px solid #C09F80;
|
||||||
width: 100%;
|
width: calc(100% - 1px);
|
||||||
margin-top: 12px; }
|
margin-top: 12px; }
|
||||||
.LP-LinkList__List .LP-LinkList__Item .LP-Link {
|
.LP-LinkList__List .LP-LinkList__Item .LP-Link {
|
||||||
padding: 1em 0 1em 1em;
|
padding: 1em 0 1em 1em;
|
||||||
width: calc(100% - $-link-padding);
|
width: calc(100% - 1em);
|
||||||
display: block;
|
display: block;
|
||||||
color: #565656; }
|
color: #565656; }
|
||||||
.LP-LinkList__List .LP-LinkList__Item .LP-Link--iconized {
|
.LP-LinkList__List .LP-LinkList__Item .LP-Link--iconized {
|
||||||
@@ -403,28 +643,49 @@
|
|||||||
.LP-Footer .LP-LinkList__List .LP-LinkList__Item .LP-Link:hover {
|
.LP-Footer .LP-LinkList__List .LP-LinkList__Item .LP-Link:hover {
|
||||||
background-color: inherit; }
|
background-color: inherit; }
|
||||||
|
|
||||||
.LP-Form .LP-Form__Fieldset {
|
.LP-Form {
|
||||||
border: none; }
|
display: flex;
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Legend {
|
flex-direction: column;
|
||||||
margin: 0;
|
align-items: center; }
|
||||||
padding: 0;
|
.LP-Form .LP-Form__Fieldset {
|
||||||
font-family: Montserrat, Helvetica, sans-serif;
|
border: none;
|
||||||
font-size: 21px; }
|
max-width: 1200px;
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition {
|
min-width: 750px; }
|
||||||
display: flex;
|
.LP-Form .LP-Form__Fieldset .LP-Form__Legend {
|
||||||
flex-direction: row;
|
margin: 0;
|
||||||
justify-content: space-between; }
|
padding: 0;
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field {
|
font-family: Montserrat, Helvetica, sans-serif;
|
||||||
flex: 3 1 100px;
|
font-size: 21px; }
|
||||||
padding: 6px 15px; }
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition {
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--wider {
|
display: flex;
|
||||||
flex: 5 1; }
|
flex-direction: row;
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--wide {
|
justify-content: space-between; }
|
||||||
flex: 4 1; }
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field {
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--narrow {
|
flex: 3 2 100px;
|
||||||
flex: 2 0; }
|
padding: 6px 15px; }
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--narrower {
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--wider {
|
||||||
flex: 1 0; }
|
flex: 5 2; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--wide {
|
||||||
|
flex: 4 2; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--narrow {
|
||||||
|
flex: 2 1; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field--narrower {
|
||||||
|
flex: 1 2; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition--buttons {
|
||||||
|
justify-content: flex-end; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Button {
|
||||||
|
flex-grow: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
min-width: 130px; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Button .LP-Link {
|
||||||
|
display: contents; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__InfoText .LP-Paragraph {
|
||||||
|
font-family: Montserrat, Helvetica, sans-serif;
|
||||||
|
color: #565656; }
|
||||||
|
|
||||||
|
@media (max-width: 750px) {
|
||||||
|
.LP-Form .LP-Form__Fieldset {
|
||||||
|
min-width: unset; } }
|
||||||
|
|
||||||
@media (max-width: 650px) {
|
@media (max-width: 650px) {
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition--breakable {
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition--breakable {
|
||||||
@@ -437,9 +698,43 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between; }
|
justify-content: space-between; }
|
||||||
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field {
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Field:not(.LP-Form__Button) {
|
||||||
flex: 3 1 100px;
|
flex: 3 1 100px;
|
||||||
padding: 12px 15px; } }
|
padding: 12px 15px; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition .LP-Form__Button {
|
||||||
|
padding: 0 15px; }
|
||||||
|
.LP-Form .LP-Form__Fieldset .LP-Form__Composition--buttons {
|
||||||
|
justify-content: flex-end; } }
|
||||||
|
|
||||||
|
.LP-ImageGrid .LP-ImageGrid__List {
|
||||||
|
list-style-type: none;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, 300px);
|
||||||
|
align-content: space-around;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0px;
|
||||||
|
padding: 0px; }
|
||||||
|
|
||||||
|
.LP-ImageGrid .LP-ImageGrid__Item {
|
||||||
|
margin-top: 10px; }
|
||||||
|
|
||||||
|
.LP-ImageGrid .LP-Link {
|
||||||
|
overflow: hidden; }
|
||||||
|
|
||||||
|
.LP-ImageGrid .LP-Image {
|
||||||
|
box-shadow: 0 0 5px #565656;
|
||||||
|
height: 200px;
|
||||||
|
width: 290px;
|
||||||
|
object-fit: cover; }
|
||||||
|
|
||||||
|
@media (max-width: 650px) {
|
||||||
|
.LP-ImageGrid .LP-ImageGrid__List {
|
||||||
|
grid-template-columns: 1fr; }
|
||||||
|
.LP-ImageGrid .LP-ImageGrid__List .LP-Image {
|
||||||
|
box-shadow: 0 0 5px #565656;
|
||||||
|
height: auto;
|
||||||
|
width: 100%;
|
||||||
|
object-fit: cover; } }
|
||||||
|
|
||||||
.LP-MainContainer {
|
.LP-MainContainer {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
@@ -452,47 +747,25 @@
|
|||||||
.LP-MainContainer {
|
.LP-MainContainer {
|
||||||
width: 100%; } }
|
width: 100%; } }
|
||||||
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverview__Info .LP-PlaceOveriew__Image {
|
.LP-PlaceDetail .LP-PlaceDetail__Image {
|
||||||
width: 700px;
|
width: 700px;
|
||||||
|
max-height: 500px;
|
||||||
box-shadow: 0 0 10px #565656;
|
box-shadow: 0 0 10px #565656;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
object-position: 0 0;
|
object-position: 0 0;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
float: right;
|
float: right;
|
||||||
margin-left: 35px;
|
margin-left: 35px;
|
||||||
margin-bottom: 35px;
|
margin-bottom: 35px;
|
||||||
|
margin-right: 35px;
|
||||||
overflow: hidden; }
|
overflow: hidden; }
|
||||||
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverview__Info .LP-PlaceOverView__Description {
|
|
||||||
padding: 0px;
|
|
||||||
position: relative;
|
|
||||||
top: -15px; }
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverview__Info .LP-PlaceOverView__Description .LP-Headline {
|
|
||||||
position: relative;
|
|
||||||
top: 15px;
|
|
||||||
margin-bottom: 30px; }
|
|
||||||
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverView__ImageList {
|
|
||||||
list-style-type: none;
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
||||||
margin: 0px;
|
|
||||||
padding: 0px; }
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverView__ImageList .LP-PlaceOverView__ImageItem {
|
|
||||||
margin-top: 10px; }
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverView__ImageList .LP-PlaceOverView__ImageItem .LP-Link {
|
|
||||||
overflow: hidden; }
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverView__ImageList .LP-PlaceOverView__ImageItem .LP-Image {
|
|
||||||
box-shadow: 0 0 5px #565656;
|
|
||||||
height: 200px;
|
|
||||||
width: 290px;
|
|
||||||
object-fit: cover; }
|
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 1000px) {
|
||||||
.LP-PlaceOverview .LP-PlaceOverview__Info .LP-TextSection {
|
.LP-PlaceDetail .LP-PlaceDetail__Header .LP-PlaceDetail__Image {
|
||||||
margin-top: 30px; }
|
|
||||||
.LP-PlaceOverview .LP-PlaceOverview__Info .LP-PlaceOveriew__Image {
|
|
||||||
float: none;
|
float: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0; } }
|
padding: 0;
|
||||||
|
margin-bottom: 25px; } }
|
||||||
|
@@ -1,48 +0,0 @@
|
|||||||
{% extends 'global.html'%}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
# {% block title %}Place erstellen{% endblock %}
|
|
||||||
|
|
||||||
{% block maincontent %}
|
|
||||||
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
|
||||||
<fieldset class="LP-Form__Fieldset">
|
|
||||||
<legend class="LP-Form__Legend">Place erstellen</legend>
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=place_form.name %}
|
|
||||||
</div>
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=place_form.location %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=place_form.latitude %}
|
|
||||||
</div>
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=place_form.longitude %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="LP-Form__Composition">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=place_form.description %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="LP-Form__Composition">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=place_image_form.filename %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="LP-Form__Composition">
|
|
||||||
<input type="submit" class="LP-Button" value="Abschicken"/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% endblock maincontent %}
|
|
@@ -9,28 +9,88 @@
|
|||||||
<title>
|
<title>
|
||||||
{% block title %}Urban Exploration{% endblock %}
|
{% block title %}Urban Exploration{% endblock %}
|
||||||
</title>
|
</title>
|
||||||
|
|
||||||
|
{% block additional_head %}
|
||||||
|
{% endblock additional_head %}
|
||||||
|
|
||||||
|
<script>
|
||||||
|
document.addEventListener("DOMContentLoaded", function(){
|
||||||
|
Array.from(document.getElementsByClassName('LP-Main__Sidebar')).forEach(function(element){
|
||||||
|
element.classList.add('LP-Main__Sidebar--hidden')
|
||||||
|
})
|
||||||
|
setTimeout(function(){
|
||||||
|
Array.from(document.getElementsByClassName('LP-Main__Sidebar')).forEach(function(element){
|
||||||
|
element.classList.remove('LP-Main__Sidebar--hidden')
|
||||||
|
})
|
||||||
|
}, 500)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<header class="LP-Header">
|
<div class="LP-Wrapper__Site">
|
||||||
<div class="LP-Header__Logo">
|
<header class="LP-Header">
|
||||||
<a class="LP-Link" href="#">
|
<div class="LP-Header__Logo">
|
||||||
<img class="LP-Logo" src="{% static 'logo.png' %}" />
|
<a class="LP-Link" href="/">
|
||||||
</a>
|
<img src="{% static 'logo.png' %}" class="LP-Image" />
|
||||||
</div>
|
</a>
|
||||||
<div class="LP-Header__Navigation">
|
</div>
|
||||||
<nav class="LP-Menu">
|
<div class="LP-Header__UserInformation">
|
||||||
|
<span class="LP-Paragraph">
|
||||||
|
{% if user.is_authenticated %}
|
||||||
|
Hi {{ user.username }}!
|
||||||
|
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">logout</span></a>
|
||||||
|
{% if user.is_superuser %}
|
||||||
|
| <a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">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>
|
||||||
|
{% endif %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
<input id="toggle_sidebar" class="LP-Menu__Trigger" type="checkbox"/>
|
||||||
|
<label id="toggle_sidebar_label" for="toggle_sidebar" class="LP-Menu__TriggerLabel"></label>
|
||||||
|
<aside class="LP-Main__Sidebar">
|
||||||
|
<nav class="LP-Menu LP-Menu--sidebar">
|
||||||
<ul class="LP-Menu__List">
|
<ul class="LP-Menu__List">
|
||||||
<li class="LP-Menu__Item"><a href="" class="LP-Link"><span class="LP-Link__Text">Home</span></a></li>
|
<li class="LP-Menu__Item"><a href="/" class="LP-Link"><span class="LP-Link__Text">Home</span></a></li>
|
||||||
<li class="LP-Menu__Item"><a href="" class="LP-Link"><span class="LP-Link__Text">About</span></a></li>
|
<li class="LP-Menu__Item"><a href="" class="LP-Link"><span class="LP-Link__Text">About</span></a></li>
|
||||||
<li class="LP-Menu__Item"><a href="" class="LP-Link"><span class="LP-Link__Text">Contact</span></a></li>
|
<li class="LP-Menu__Item"><a href="" class="LP-Link"><span class="LP-Link__Text">Contact</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>
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</aside>
|
||||||
</header>
|
<main class="LP-Main__Content">
|
||||||
<article class="LP-MainContainer">
|
{% if messages %}
|
||||||
{% block maincontent %}
|
<div class="LP-MessageList">
|
||||||
|
<ul class="LP-MessageList__List">
|
||||||
{% endblock maincontent %}
|
{% for message in messages %}
|
||||||
</article>
|
<li class="LP-MessageList__Item">
|
||||||
|
<div class="LP-Message {% if message.tags %}LP-Message--{{ message.tags }}{% endif %}">
|
||||||
|
<div>
|
||||||
|
<div class="LP-Message__Icon">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="LP-Message__Text">
|
||||||
|
{{ message }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
|
{% block maincontent %}
|
||||||
|
{% endblock maincontent %}
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@@ -5,19 +5,10 @@
|
|||||||
|
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
|
|
||||||
{% if user.is_authenticated %}
|
|
||||||
Hi {{ user.username }}!
|
|
||||||
<p><a href="{% url 'logout' %}">logout</a></p>
|
|
||||||
{% else %}
|
|
||||||
<p>Du bist nicht eingeloggt.</p>
|
|
||||||
<a href="{% url 'login' %}">login</a> |
|
|
||||||
<a href="{% url 'signup' %}">signup</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="LP-PlaceGrid">
|
<div class="LP-PlaceGrid">
|
||||||
<h1 class="LP-Headline LP-Headline">Explore the latest locations</h1>
|
<h1 class="LP-Headline LP-Headline">Explore the latest locations</h1>
|
||||||
<ul class="LP-PlaceGrid__Grid">
|
<ul class="LP-PlaceGrid__Grid">
|
||||||
{% for place in place_list %}
|
{% for place in place_list %}
|
||||||
<li class="LP-PlaceGrid__Item">
|
<li class="LP-PlaceGrid__Item">
|
||||||
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
||||||
<article class="LP-PlaceTeaser">
|
<article class="LP-PlaceTeaser">
|
||||||
@@ -27,15 +18,12 @@
|
|||||||
<div class="LP-PlaceTeaser__Meta">
|
<div class="LP-PlaceTeaser__Meta">
|
||||||
<div class="LP-PlaceTeaser__Info">
|
<div class="LP-PlaceTeaser__Info">
|
||||||
<span class="LP-PlaceTeaser__Title">
|
<span class="LP-PlaceTeaser__Title">
|
||||||
<h1 class="LP-Headline LP-Headline--teaser">{{place.name}}</h1>
|
<h1 class="LP-Headline LP-Headline--teaser">{{place.name|truncatechars:19}}</h1>
|
||||||
</span>
|
</span>
|
||||||
<span class="LP-PlaceTeaser__Detail">
|
<span class="LP-PlaceTeaser__Detail">
|
||||||
<p class="LP-Paragraph">{{place.location}}</p>
|
<p class="LP-Paragraph">{{place.location|truncatechars:25}}</p>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="LP-PlaceTeaser__Description">
|
|
||||||
<p class="LP-Paragraph">{{place.description}}</p>
|
|
||||||
</div>
|
|
||||||
<div class="LP-PlaceTeaser__Icons">
|
<div class="LP-PlaceTeaser__Icons">
|
||||||
<ul class="LP-Icon__List">
|
<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/favourite.svg' %}" /></li>
|
||||||
@@ -44,10 +32,10 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@@ -1,16 +1,16 @@
|
|||||||
{% load widget_tweaks %}
|
{% load widget_tweaks %}
|
||||||
|
|
||||||
<div class="LP-Input {% if field.errors %} LP-Input--error {% endif %}">
|
<div class="LP-Input {% if field.errors %} LP-Input--error {% endif %}">
|
||||||
<label for="{{field.id_for_label}}" class="LP-Input__Label">{{field.label}}</label>
|
<label for="{{field.id_for_label}}" class="LP-Input__Label">{{field.label}}</label>
|
||||||
{% render_field field class="LP-Input__Field"%}
|
{% render_field field class="LP-Input__Field"%}
|
||||||
|
|
||||||
<span class="LP-Input__Message">
|
<span class="LP-Input__Message">
|
||||||
{% if field.errors %}
|
{% if field.errors %}
|
||||||
{% for error in field.errors%}
|
{% for error in field.errors%}
|
||||||
{{error}}
|
{{error}}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% elif field.help_text%}
|
{% elif field.help_text%}
|
||||||
{{ field.help_text }}
|
{{ field.help_text }}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
@@ -0,0 +1,74 @@
|
|||||||
|
{% load lostplaces %}
|
||||||
|
|
||||||
|
{% if is_paginated %}
|
||||||
|
<div class="LP-Pagination">
|
||||||
|
<ul class="LP-Pagination__List">
|
||||||
|
{% if page_obj.has_previous %}
|
||||||
|
<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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</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>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% for i in page_obj.paginator|proper_paginate:page_obj.number %}
|
||||||
|
{% if i == page_obj.number %}
|
||||||
|
<li class="LP-Pagination__Item LP-Pagination__Item--current">
|
||||||
|
{% else %}
|
||||||
|
<li class="LP-Pagination__Item LP-Pagination__Item--neighbor">
|
||||||
|
{% endif %}
|
||||||
|
<a href="?page={{i}}" class="LP-Link">
|
||||||
|
<span class="LP-Text">{{i}}</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% 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-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-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-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-Icon">⟫</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endif %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
55
lostplaces/lostplaces_app/templates/place/place_create.html
Normal file
55
lostplaces/lostplaces_app/templates/place/place_create.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{% extends 'global.html'%}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
# {% block title %}Place erstellen{% 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>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=place_form.name %}
|
||||||
|
</div>
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=place_form.location %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=place_form.latitude %}
|
||||||
|
</div>
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=place_form.longitude %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="LP-Form__Composition">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=place_form.description %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="LP-Form__Composition">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=place_image_form.filename %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock maincontent %}
|
30
lostplaces/lostplaces_app/templates/place/place_delete.html
Normal file
30
lostplaces/lostplaces_app/templates/place/place_delete.html
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
{% extends 'global.html'%}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Lost Place Deletion{% endblock %}
|
||||||
|
|
||||||
|
{% block maincontent %}
|
||||||
|
|
||||||
|
<form class="LP-Form" method="POST">
|
||||||
|
<fieldset class="LP-Form__Fieldset">
|
||||||
|
<legend class="LP-Form__Legend">Delete place</legend>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="LP-Form__Composition">
|
||||||
|
<div class="LP-Form__Field LP-Form__InfoText">
|
||||||
|
<p class="LP-Paragraph">Are you sure you want to delete "{{place.name}}"? </p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||||
|
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||||
|
<button class="LP-Button">Delete</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>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
{% endblock maincontent %}
|
53
lostplaces/lostplaces_app/templates/place/place_detail.html
Normal file
53
lostplaces/lostplaces_app/templates/place/place_detail.html
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
{% extends 'global.html'%}
|
||||||
|
{% load static %}
|
||||||
|
{% load thumbnail %}
|
||||||
|
|
||||||
|
{% 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>
|
||||||
|
{% endblock additional_menu_items %}
|
||||||
|
|
||||||
|
{% block maincontent %}
|
||||||
|
<article class="LP-PlaceDetail">
|
||||||
|
|
||||||
|
<header class="LP-PlaceDetail__Header">
|
||||||
|
<h1 class="LP-Headline">{{ place.name }}</h1>
|
||||||
|
{% if place.images.first.filename.hero.url %}
|
||||||
|
<figure class="LP-PlaceDetail__Image">
|
||||||
|
<img src="{{ place.images.first.filename.hero.url }}" class="LP-Image" />
|
||||||
|
</figure>
|
||||||
|
{% endif %}
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="LP-PlaceDetail__Description">
|
||||||
|
<p class="LP-Paragraph">{{ place.description }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section class="LP-Section">
|
||||||
|
<h1 class="LP-Headline">Map-Links</h1>
|
||||||
|
<div class="LP-LinkList">
|
||||||
|
<ul class="LP-LinkList__List">
|
||||||
|
<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>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="LP-Section">
|
||||||
|
<h1 class="LP-Headline">Bilder</h1>
|
||||||
|
<div class="LP-ImageGrid">
|
||||||
|
<ul class="LP-ImageGrid__List">
|
||||||
|
{% for place_image in place.images.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>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
</article>
|
||||||
|
{% endblock maincontent %}
|
52
lostplaces/lostplaces_app/templates/place/place_list.html
Normal file
52
lostplaces/lostplaces_app/templates/place/place_list.html
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{% extends 'global.html'%}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
{% block title %}Lost Places{% endblock %}
|
||||||
|
|
||||||
|
{% block maincontent %}
|
||||||
|
<div class="LP-PlaceList">
|
||||||
|
<h1 class="LP-Headline">Listing our places</h1>
|
||||||
|
<ul class="LP-PlaceList__List">
|
||||||
|
{% for place in place_list %}
|
||||||
|
<li class="LP-PlaceList__Item">
|
||||||
|
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
||||||
|
<article class="LP-PlaceTeaser LP-PlaceTeaser--extended">
|
||||||
|
<div class="LP-PlaceTeaser__Image">
|
||||||
|
<img class="LP-Image" src="{{ place.images.first.filename.thumbnail.url }}" />
|
||||||
|
</div>
|
||||||
|
<div class="LP-PlaceTeaser__Meta">
|
||||||
|
<div class="LP-PlaceTeaser__Info">
|
||||||
|
<span class="LP-PlaceTeaser__Title">
|
||||||
|
<h2 class="LP-Headline LP-Headline--teaser">{{place.name}}</h2>
|
||||||
|
</span>
|
||||||
|
<span class="LP-PlaceTeaser__Detail">
|
||||||
|
<p class="LP-Paragraph">{{place.location}}</p>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="LP-PlaceTeaser__Description">
|
||||||
|
<p class="LP-Paragraph">
|
||||||
|
{% if place.description|length > 210 %}
|
||||||
|
{{place.description|truncatechars:210|truncatewords:-1}}
|
||||||
|
{% else %}
|
||||||
|
{{place.description}}
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="LP-PlaceTeaser__Icons">
|
||||||
|
<ul class="LP-Icon__List">
|
||||||
|
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/favourite.svg' %}" /></li>
|
||||||
|
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/location.svg' %}" /></li>
|
||||||
|
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</article>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
{% include 'partials/nav/pagination.html' %}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock maincontent %}
|
55
lostplaces/lostplaces_app/templates/place/place_update.html
Normal file
55
lostplaces/lostplaces_app/templates/place/place_update.html
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{% extends 'global.html'%}
|
||||||
|
{% load static %}
|
||||||
|
|
||||||
|
# {% block title %}Update place{% endblock %}
|
||||||
|
|
||||||
|
{% block maincontent %}
|
||||||
|
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
||||||
|
<fieldset class="LP-Form__Fieldset">
|
||||||
|
<legend class="LP-Form__Legend">Update place</legend>
|
||||||
|
{% csrf_token %}
|
||||||
|
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.name %}
|
||||||
|
</div>
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.location %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.latitude %}
|
||||||
|
</div>
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.longitude %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="LP-Form__Composition">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.description %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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">
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
{% endblock maincontent %}
|
@@ -1,35 +0,0 @@
|
|||||||
{% extends 'global.html'%}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
{% block title %}Lost Places{% endblock %}
|
|
||||||
|
|
||||||
{% block maincontent %}
|
|
||||||
<ul class="LP-Place__List">
|
|
||||||
{% for place in place_list %}
|
|
||||||
<li class="LP-Place__Item">
|
|
||||||
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
|
||||||
<article class="LP-Place">
|
|
||||||
<div class="LP-Place__ImageContainer">
|
|
||||||
<img class="LP-Place__Image" src="{{ place.images.first.filename.thumbnail.url }}" />
|
|
||||||
</div>
|
|
||||||
<div class="LP-Place__Assets">
|
|
||||||
<div class="LP-Place__Info">
|
|
||||||
<h3 class="LP-Place__Title">{{place.name}}</h3>
|
|
||||||
<p class="LP-Place__Detail">{{place.location}}</p>
|
|
||||||
</div>
|
|
||||||
<p class="LP-TextSection LP-Place__Description">
|
|
||||||
{{place.description|truncatechars:210|truncatewords:-1}}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</article>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
{% endblock maincontent %}
|
|
@@ -1,81 +0,0 @@
|
|||||||
{% extends 'global.html'%}
|
|
||||||
{% load static %}
|
|
||||||
{% load thumbnail %}
|
|
||||||
|
|
||||||
{% block title %}{{place.name}}{% endblock %}
|
|
||||||
|
|
||||||
{% block maincontent %}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<article class="LP-PlaceOverview">
|
|
||||||
<div class="LP-PlaceOverview__Info">
|
|
||||||
<div class="LP-PlaceOveriew__Image">
|
|
||||||
<img src="{{ place.images.first.filename.hero.url }}" class="LP-Image" />
|
|
||||||
</div>
|
|
||||||
<article class="LP-PlaceOverView__Description">
|
|
||||||
<div class="LP-TextSection">
|
|
||||||
<h1 class="LP-Headline LP-Headline">{{place.name}}</h1>
|
|
||||||
<p class="LP-Paragraph LP-Paragraph">{{place.description}}</p>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</div>
|
|
||||||
<article class="LP-Section">
|
|
||||||
<h1 class="LP-Headline LP-Headline">Sicherheitsmaßnahmen</h1>
|
|
||||||
<div class="LP-Content__Wrapper">
|
|
||||||
<div class="LP-Content">
|
|
||||||
<div class="LP-TagList">
|
|
||||||
<ul class="LP-TagList__List">
|
|
||||||
<li class="LP-TagList__Item">
|
|
||||||
<div class="LP-Tag">
|
|
||||||
<p class="LP-Paragraph LP-Paragraph">Kamera</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="LP-TagList__Item">
|
|
||||||
<div class="LP-Tag">
|
|
||||||
<p class="LP-Paragraph LP-Paragraph">Wachhund</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="LP-TagList__Item">
|
|
||||||
<div class="LP-Tag">
|
|
||||||
<p class="LP-Paragraph LP-Paragraph">Zaun</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li class="LP-TagList__Item">
|
|
||||||
<div class="LP-Tag">
|
|
||||||
<p class="LP-Paragraph LP-Paragraph">Security</p>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<article class="LP-Section">
|
|
||||||
<h1 class="LP-Headline LP-Headline">Links</h1>
|
|
||||||
<div class="LP-Content__Wrapper">
|
|
||||||
<div class="LP-Content">
|
|
||||||
<ul class="LP-LinkList__List">
|
|
||||||
<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>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
<article class="LP-Section">
|
|
||||||
<h1 class="LP-Headline LP-Headline">Bilder</h1>
|
|
||||||
<div class="LP-Content__Wrapper">
|
|
||||||
<div class=" LP-Content">
|
|
||||||
<ul class="LP-PlaceOverView__ImageList">
|
|
||||||
{% for place_image in place.images.all %}
|
|
||||||
<li class="LP-PlaceOverView__ImageItem">
|
|
||||||
<a href="{{ place_image.filename.large.url }}" class="LP-Link"><img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}"></a>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</article>
|
|
||||||
{% endblock maincontent %}
|
|
@@ -1,48 +0,0 @@
|
|||||||
{% extends 'global.html'%}
|
|
||||||
{% load static %}
|
|
||||||
|
|
||||||
# {% block title %}Place aktualisieren{% endblock %}
|
|
||||||
|
|
||||||
{% block maincontent %}
|
|
||||||
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
|
||||||
<fieldset class="LP-Form__Fieldset">
|
|
||||||
<legend class="LP-Form__Legend">Place aktualisieren</legend>
|
|
||||||
{% csrf_token %}
|
|
||||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=form.name %}
|
|
||||||
</div>
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=form.location %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=form.latitude %}
|
|
||||||
</div>
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=form.longitude %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="LP-Form__Composition">
|
|
||||||
<div class="LP-Form__Field">
|
|
||||||
{% include 'partials/form/inputField.html' with field=form.description %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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">
|
|
||||||
<input type="submit" class="LP-Button" value="Abschicken"/>
|
|
||||||
</div>
|
|
||||||
</fieldset>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
|
|
||||||
{% endblock maincontent %}
|
|
22
lostplaces/lostplaces_app/templatetags/lostplaces.py
Normal file
22
lostplaces/lostplaces_app/templatetags/lostplaces.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
from django import template
|
||||||
|
|
||||||
|
register = template.Library()
|
||||||
|
|
||||||
|
@register.filter(name='proper_paginate')
|
||||||
|
def proper_paginate(paginator, current_page, neighbors=2):
|
||||||
|
if paginator.num_pages > 2*neighbors:
|
||||||
|
start_index = max(1, current_page-neighbors)
|
||||||
|
end_index = min(paginator.num_pages, current_page + neighbors)
|
||||||
|
if end_index < start_index + 2*neighbors:
|
||||||
|
end_index = start_index + 2*neighbors
|
||||||
|
elif start_index > end_index - 2*neighbors:
|
||||||
|
start_index = end_index - 2*neighbors
|
||||||
|
if start_index < 1:
|
||||||
|
end_index -= start_index
|
||||||
|
start_index = 1
|
||||||
|
elif end_index > paginator.num_pages:
|
||||||
|
start_index -= (end_index-paginator.num_pages)
|
||||||
|
end_index = paginator.num_pages
|
||||||
|
page_list = [f for f in range(start_index, end_index+1)]
|
||||||
|
return page_list[:(2*neighbors + 1)]
|
||||||
|
return paginator.page_range
|
@@ -1,20 +1,20 @@
|
|||||||
from django.urls import path
|
from django.urls import path
|
||||||
from .views import (
|
from .views import (
|
||||||
hello_world,
|
HomeView,
|
||||||
HomeView,
|
PlaceDetailView,
|
||||||
place_detail_view,
|
PlaceListView,
|
||||||
place_list_view,
|
|
||||||
SignUpView,
|
SignUpView,
|
||||||
PlaceCreateView,
|
PlaceCreateView,
|
||||||
PlaceUpdateView
|
PlaceUpdateView,
|
||||||
|
PlaceDeleteView
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('hello_world/', hello_world), # You know what this is :P
|
path('', HomeView.as_view(), name='home'),
|
||||||
path('', HomeView.as_view(), name='home'),
|
|
||||||
path('signup/', SignUpView.as_view(), name='signup'),
|
path('signup/', SignUpView.as_view(), name='signup'),
|
||||||
path('place/<int:pk>/', place_detail_view, name='place_detail'),
|
path('place/<int:pk>/', PlaceDetailView.as_view(), name='place_detail'),
|
||||||
path('place/create/', PlaceCreateView.as_view(), name='place_create'),
|
path('place/create/', PlaceCreateView.as_view(), name='place_create'),
|
||||||
path('place/update/<int:pk>/', PlaceUpdateView.as_view(), name='place_edit'),
|
path('place/update/<int:pk>/', PlaceUpdateView.as_view(), name='place_edit'),
|
||||||
path('place/', place_list_view, name='place_list')
|
path('place/delete/<int:pk>/', PlaceDeleteView.as_view(), name='place_delete'),
|
||||||
|
path('place/', PlaceListView.as_view(), name='place_list')
|
||||||
]
|
]
|
||||||
|
@@ -4,47 +4,81 @@
|
|||||||
''' Django views. '''
|
''' Django views. '''
|
||||||
from django.shortcuts import render, redirect, get_object_or_404
|
from django.shortcuts import render, redirect, get_object_or_404
|
||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.views.generic.edit import CreateView
|
from django.views.generic.edit import CreateView, UpdateView, DeleteView
|
||||||
|
from django.views.generic import ListView
|
||||||
from django.views import View
|
from django.views import View
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.views.generic.edit import UpdateView
|
from django.contrib import messages
|
||||||
|
from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
|
||||||
|
|
||||||
from .forms import ExplorerCreationForm, PlaceForm, PlaceImageCreateForm
|
from django.contrib.messages.views import SuccessMessageMixin
|
||||||
|
|
||||||
|
from .forms import (
|
||||||
|
ExplorerCreationForm,
|
||||||
|
PlaceForm,
|
||||||
|
PlaceImageCreateForm
|
||||||
|
)
|
||||||
from .models import Place, PlaceImage, Voucher
|
from .models import Place, PlaceImage, Voucher
|
||||||
|
|
||||||
# Create your views here.
|
# Create your views here.
|
||||||
|
|
||||||
class SignUpView(CreateView):
|
# BaseView that checks if user is logged in.
|
||||||
|
class IsAuthenticated(LoginRequiredMixin, View):
|
||||||
|
redirect_field_name = 'redirect_to'
|
||||||
|
|
||||||
|
# BaseView that checks if logged in user is submitter of place.
|
||||||
|
class IsSubmitter(UserPassesTestMixin, View):
|
||||||
|
def test_func(self):
|
||||||
|
""" Check if user is eligible to modify place. """
|
||||||
|
if self.request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check if currently logged in user was the submitter
|
||||||
|
place_obj = self.get_object()
|
||||||
|
|
||||||
|
if self.request.user == place_obj.submitted_by:
|
||||||
|
return True
|
||||||
|
|
||||||
|
messages.error(
|
||||||
|
self.request, 'You do not have permission to do this.')
|
||||||
|
return False
|
||||||
|
|
||||||
|
class SignUpView(SuccessMessageMixin, CreateView):
|
||||||
form_class = ExplorerCreationForm
|
form_class = ExplorerCreationForm
|
||||||
success_url = reverse_lazy('login')
|
success_url = reverse_lazy('login')
|
||||||
template_name = 'signup.html'
|
template_name = 'signup.html'
|
||||||
|
success_message = 'User created.'
|
||||||
|
|
||||||
def place_list_view(request,):
|
class PlaceListView(IsAuthenticated, ListView):
|
||||||
return render(request, 'placeList.html', {'place_list':Place.objects.all()})
|
paginate_by = 2
|
||||||
|
model = Place
|
||||||
|
template_name = 'place/place_list.html'
|
||||||
|
|
||||||
def place_detail_view(request, pk):
|
class PlaceDetailView(IsAuthenticated, View):
|
||||||
return render(request, 'placeOverview.html', {'place':Place.objects.get(pk=pk)})
|
def get(self, request, pk):
|
||||||
|
context = {
|
||||||
def hello_world(request):
|
'place': Place.objects.get(pk=pk)
|
||||||
return render(request, 'hello_world.html', {'text':'Hello World!'})
|
}
|
||||||
|
return render(request, 'place/place_detail.html', context)
|
||||||
|
|
||||||
class HomeView(View):
|
class HomeView(View):
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
place_list = Place.objects.all().order_by('submitted_when')[:10]
|
place_list = Place.objects.all().order_by('-submitted_when')[:10]
|
||||||
context = {
|
context = {
|
||||||
'place_list': place_list
|
'place_list': place_list
|
||||||
}
|
}
|
||||||
return render(request, 'home.html', context)
|
return render(request, 'home.html', context)
|
||||||
|
|
||||||
class PlaceUpdateView(UpdateView):
|
class PlaceUpdateView(IsAuthenticated, IsSubmitter, SuccessMessageMixin, UpdateView):
|
||||||
template_name = 'update_place.html'
|
template_name = 'place/place_update.html'
|
||||||
model = Place
|
model = Place
|
||||||
form_class = PlaceForm
|
form_class = PlaceForm
|
||||||
|
success_message = 'Successfully updated place.'
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse_lazy('place_detail', kwargs={'pk':self.get_object().pk})
|
return reverse_lazy('place_detail', kwargs={'pk':self.get_object().pk})
|
||||||
|
|
||||||
class PlaceCreateView(View):
|
class PlaceCreateView(IsAuthenticated, View):
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
def get(self, request, *args, **kwargs):
|
||||||
place_image_form = PlaceImageCreateForm()
|
place_image_form = PlaceImageCreateForm()
|
||||||
@@ -54,7 +88,7 @@ class PlaceCreateView(View):
|
|||||||
'place_form': place_form,
|
'place_form': place_form,
|
||||||
'place_image_form': place_image_form
|
'place_image_form': place_image_form
|
||||||
}
|
}
|
||||||
return render(request, 'create_place.html', context)
|
return render(request, 'place/place_create.html', context)
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
place_form = PlaceForm(request.POST)
|
place_form = PlaceForm(request.POST)
|
||||||
@@ -76,17 +110,37 @@ class PlaceCreateView(View):
|
|||||||
kwargs_to_pass = {
|
kwargs_to_pass = {
|
||||||
'pk': place.pk
|
'pk': place.pk
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messages.success(
|
||||||
|
self.request, 'Successfully created place.')
|
||||||
return redirect(reverse_lazy('place_detail', kwargs=kwargs_to_pass))
|
return redirect(reverse_lazy('place_detail', kwargs=kwargs_to_pass))
|
||||||
|
|
||||||
else:
|
else:
|
||||||
context = {
|
context = {
|
||||||
'form': form_place
|
'form': form_place
|
||||||
}
|
}
|
||||||
return render(request, 'create_place.html', context)
|
|
||||||
|
|
||||||
def _apply_multipart_image_upload(self, files, place, submitter)::
|
# Usually the browser should have checked the form before sending.
|
||||||
|
messages.error(
|
||||||
|
self.request, 'Please fill in all required fields.')
|
||||||
|
return render(request, 'place/place_create.html', context)
|
||||||
|
|
||||||
|
def _apply_multipart_image_upload(self, files, place, submitter):
|
||||||
|
for image in files:
|
||||||
place_image = PlaceImage.objects.create(
|
place_image = PlaceImage.objects.create(
|
||||||
filename=image,
|
filename=image,
|
||||||
place=place,
|
place=place,
|
||||||
submitted_by=submitter
|
submitted_by=submitter
|
||||||
)
|
)
|
||||||
place_image.save()
|
place_image.save()
|
||||||
|
|
||||||
|
class PlaceDeleteView(IsAuthenticated, IsSubmitter, DeleteView):
|
||||||
|
template_name = 'place/place_delete.html'
|
||||||
|
model = Place
|
||||||
|
success_message = 'Successfully deleted place.'
|
||||||
|
success_url = reverse_lazy('place_list')
|
||||||
|
success_message = 'Place deleted'
|
||||||
|
|
||||||
|
def delete(self, request, *args, **kwargs):
|
||||||
|
messages.success(self.request, self.success_message)
|
||||||
|
return super().delete(request, *args, **kwargs)
|
||||||
|
15
lostplaces/templates/403.html
Normal file
15
lostplaces/templates/403.html
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{% extends 'global.html'%}
|
||||||
|
|
||||||
|
{% block title %}Forbidden{% endblock %}
|
||||||
|
|
||||||
|
{% block additional_head %}
|
||||||
|
{% if request.META.HTTP_REFERER %}
|
||||||
|
<meta http-equiv="refresh" content="5;url={{ request.META.HTTP_REFERER }}" />
|
||||||
|
{% endif %}
|
||||||
|
{% endblock additional_head %}
|
||||||
|
|
||||||
|
{% 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>
|
||||||
|
{% endif %}
|
||||||
|
{% endblock maincontent %}
|
@@ -5,11 +5,27 @@
|
|||||||
|
|
||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
|
|
||||||
<h2>Login</h2>
|
<form class="LP-Form" method="POST" enctype="multipart/form-data">
|
||||||
<form method="post">
|
<fieldset class="LP-Form__Fieldset">
|
||||||
{% csrf_token %}
|
<legend class="LP-Form__Legend">Login</legend>
|
||||||
{{ form.as_p }}
|
{% csrf_token %}
|
||||||
<button type="submit">Login</button>
|
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.username %}
|
||||||
|
</div>
|
||||||
|
<div class="LP-Form__Field">
|
||||||
|
{% include 'partials/form/inputField.html' with field=form.password %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock maincontent %}
|
{% endblock maincontent %}
|
@@ -7,38 +7,40 @@
|
|||||||
{% block maincontent %}
|
{% block maincontent %}
|
||||||
|
|
||||||
<form class="LP-Form" method="POST">
|
<form class="LP-Form" method="POST">
|
||||||
<fieldset class="LP-Form__Fieldset">
|
<fieldset class="LP-Form__Fieldset">
|
||||||
<legend class="LP-Form__Legend">Registrierung</legend>
|
<legend class="LP-Form__Legend">Registration</legend>
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
<div class="LP-Form__Composition LP-Form__Composition--breakable">
|
||||||
<div class="LP-Form__Field">
|
<div class="LP-Form__Field">
|
||||||
{% include 'partials/form/inputField.html' with field=form.username %}
|
{% include 'partials/form/inputField.html' with field=form.username %}
|
||||||
</div>
|
</div>
|
||||||
<div class="LP-Form__Field">
|
<div class="LP-Form__Field">
|
||||||
{% include 'partials/form/inputField.html' with field=form.email %}
|
{% include 'partials/form/inputField.html' with field=form.email %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="LP-Form__Composition">
|
<div class="LP-Form__Composition">
|
||||||
<div class="LP-Form__Field">
|
<div class="LP-Form__Field">
|
||||||
{% include 'partials/form/inputField.html' with field=form.password1 %}
|
{% include 'partials/form/inputField.html' with field=form.password1 %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="LP-Form__Composition">
|
<div class="LP-Form__Composition">
|
||||||
<div class="LP-Form__Field">
|
<div class="LP-Form__Field">
|
||||||
{% include 'partials/form/inputField.html' with field=form.password2 %}
|
{% include 'partials/form/inputField.html' with field=form.password2 %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="LP-Form__Composition">
|
<div class="LP-Form__Composition">
|
||||||
<div class="LP-Form__Field">
|
<div class="LP-Form__Field">
|
||||||
{% include 'partials/form/inputField.html' with field=form.voucher %}
|
{% include 'partials/form/inputField.html' with field=form.voucher %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="LP-Form__Composition">
|
<div class="LP-Form__Composition LP-Form__Composition--buttons">
|
||||||
<input type="submit" class="LP-Button" value="Registrieren"/>
|
<div class="LP-Form__Field LP-Form__Button LP-Input">
|
||||||
</div>
|
<button class="LP-Button">Sign up</button>
|
||||||
</fieldset>
|
</div>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user