50 Commits

Author SHA1 Message Date
a02d4f5e86 yes yes indeed 2021-07-10 14:43:56 +02:00
a7043651e0 , 2021-07-10 13:44:09 +02:00
bcf3377190 Trying to use pipenv in jenkins 2021-07-10 13:42:26 +02:00
ceabe3f6f8 No manual sync with repo since this is done by jenkins 2021-07-10 13:34:29 +02:00
6b33d20f90 :: 2021-07-10 13:32:56 +02:00
1d787a3b1d . 2021-07-10 13:31:34 +02:00
1960bf3792 . 2021-07-10 13:30:10 +02:00
0c3898163e ... 2021-07-10 13:27:46 +02:00
2c6676d2c9 Havin' fun with jenkins 2021-07-10 13:25:58 +02:00
52f9df8b2a Jenkinsfile to build a snapshot 2021-07-10 13:22:11 +02:00
ab669b9f5e Changes in MapContext 2021-06-25 11:04:18 +02:00
0fe98d4f8f Testing place views 2021-06-25 11:04:01 +02:00
51addd8fbb Testing messgaes 2021-06-12 17:06:09 +02:00
29d2813fcc Some weird bug only occuring when testing 2021-06-12 17:05:54 +02:00
cc9343270a explorers -> explorer 2021-06-12 17:05:32 +02:00
4f465b3162 400 Response when submitting invalid place data and testing more edge cases 2021-06-12 15:52:52 +02:00
b0bf40aa0b More tests of views 2021-06-12 15:07:14 +02:00
822a536ebe Fixing idention 2021-05-16 13:03:46 +02:00
5b9672e21e Testing PlaceAssetCreateView 2021-05-16 13:03:41 +02:00
0a5d22d4d9 More comments 2021-05-15 23:27:33 +02:00
9c86eab14c Testing home view 2021-05-15 23:27:25 +02:00
29d067002e Mixin Test does not rely on actual place view 2021-05-15 23:26:27 +02:00
f5f5980f9b Tests for global templates 2021-05-15 23:26:02 +02:00
10c08a2f5e Current CSS 2021-04-10 08:24:33 +02:00
50f60be10a Shifting index 2021-04-10 08:24:23 +02:00
8b32b56dd9 Custom Widget to select content/invisible radio input 2021-04-10 08:24:08 +02:00
74d842a668 #47 Settinge of Place Hero Image 2021-04-10 08:23:36 +02:00
2ac39f719f Removing debug 2021-04-09 19:51:45 +02:00
9b6121e448 Small fix 2021-04-09 19:51:17 +02:00
a139594863 Fixin Partial and Set Tag 2021-04-06 19:15:22 +02:00
f2eb048f0b Small check is this partial is used within place 2021-04-06 19:14:58 +02:00
120e63808a Replace include with partial tag 2021-04-06 19:14:36 +02:00
201ef73639 Accidently removed place url 2021-04-04 17:03:26 +02:00
af7afd0311 Accidently removed the add image tile 2021-04-04 17:01:00 +02:00
cf6346fdf0 Fixed #49 2021-04-04 16:56:18 +02:00
d641d7b44d Backwards compatibality 2021-04-04 16:55:56 +02:00
d35cb8131a Merge branch 'master' into develop 2021-04-03 23:07:16 +02:00
ceeae9e8c9 rudimentary implementation of a lightbox 2021-04-03 23:03:44 +02:00
092b91825f Following new naming https://is.gd/cRmcip 2021-04-02 22:06:52 +02:00
52271811ad using block in partial 2021-04-02 22:00:21 +02:00
fb1237f111 set variable and partial template tag 2021-04-02 22:00:13 +02:00
bae4e13137 Partial for PlaceImageGrid 2021-04-02 17:22:28 +02:00
b752454233 #39 Partial for Images 2021-04-02 17:21:00 +02:00
36eb9566d9 Fixed 404 because of misnamed font file. 2020-12-26 14:33:57 +01:00
b876435d8c Removed 'the mother of all debugging' again. :D 2020-12-25 19:50:34 +01:00
224eb87d76 Changed migration file reference after renaming it. 2020-12-25 19:47:05 +01:00
a78f123d1f Merge commit 'a22c988e948438415d1a58cac627243ae24785f4' into develop 2020-12-25 19:39:05 +01:00
947f6520aa CSS für Profil 2020-12-25 18:07:54 +01:00
196fb02436 Release 2020-12-19 15:31:29 +01:00
9be993d9ba New Migrations for release 2020-12-19 15:31:22 +01:00
46 changed files with 1304 additions and 279 deletions

28
Jenkinsfile vendored Normal file
View File

@@ -0,0 +1,28 @@
pipeline {
agent { docker { image 'python:3.7.2' } }
environment {
// pipenv
PIPENV_YES="true"
PIPENV_NOSPIN="YES"
}
stages {
stage('migration') {
steps {
script {
sh 'pipenv run makemigrations'
}
}
}
stage('build') {
steps {
script {
sh 'cd django_lostplaces'
sh 'python setup.py bdist_wheel --universal'
}
}
}
}
}

View File

@@ -28,6 +28,6 @@ from lostplaces.views import SignUpView
urlpatterns = [
path('admin/', admin.site.urls),
path('signup/', SignUpView.as_view(), name='signup'),
path('explorers/', include('django.contrib.auth.urls')),
path('explorer/', include('django.contrib.auth.urls')),
path('', include('lostplaces.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@@ -8,6 +8,8 @@ from django.db import models
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _
from lostplaces import widgets
from lostplaces.models import Place, PlaceImage, Voucher, Explorer
class SignupVoucherForm(UserCreationForm):
@@ -67,16 +69,25 @@ class PlaceForm(forms.ModelForm):
class Meta:
model = Place
fields = '__all__'
exclude = ['submitted_by', 'latitude', 'longitute']
exclude = ['submitted_by']
widgets = {
'hero': widgets.SelectContent()
}
latitude = forms.IntegerField(
widget=forms.NumberInput(attrs={'min':-90,'max': 90,'type': 'number'})
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if 'instance' in kwargs:
self.fields['hero'].queryset = PlaceImage.objects.filter(place=kwargs['instance'])
self.fields['hero'].widget.attrs['item_template'] = 'partials/select_place_image_item.html'
latitude = forms.DecimalField(
widget=forms.NumberInput(attrs={'min':-90,'max': 90,'type': 'number', 'step': 'any'})
)
longitude = forms.IntegerField(
widget=forms.NumberInput(attrs={'min':-180,'max': 180,'type': 'number'})
)
longitude = forms.DecimalField(
widget=forms.NumberInput(attrs={'min':-180,'max': 180,'type': 'number', 'step': 'any'})
)
class PlaceImageForm(forms.ModelForm):
class Meta:
model = PlaceImage
@@ -89,9 +100,24 @@ class PlaceImageForm(forms.ModelForm):
super().__init__(*args, **kwargs)
self.fields['filename'].required = False
class PlaceSetHeroForm(forms.ModelForm):
class Meta:
model = Place
fields = ['hero']
widgets = {
'hero': widgets.SelectContent()
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['hero'].queryset = PlaceImage.objects.filter(place=kwargs['instance'])
self.fields['hero'].widget.attrs['item_template'] = 'partials/select_place_image_item.html'
class TagSubmitForm(forms.Form):
tag_list = forms.CharField(
tag_list = forms.CharField(
max_length=500,
required=False,
widget=forms.TextInput(attrs={'autocomplete':'off'})

View File

@@ -0,0 +1,102 @@
# Generated by Django 3.1.1 on 2020-12-19 13:53
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import easy_thumbnails.fields
import lostplaces.models.place
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0003_voucher'),
]
operations = [
migrations.AlterField(
model_name='photoalbum',
name='label',
field=models.CharField(max_length=100, verbose_name='link text'),
),
migrations.AlterField(
model_name='photoalbum',
name='submitted_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='photoalbums', to='lostplaces.explorer', verbose_name='Submitter'),
),
migrations.AlterField(
model_name='photoalbum',
name='submitted_when',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date'),
),
migrations.AlterField(
model_name='photoalbum',
name='url',
field=models.URLField(verbose_name='URL'),
),
migrations.AlterField(
model_name='place',
name='description',
field=models.TextField(help_text="Description of the place: e.g. how to get there, where to be careful, the place's history...", verbose_name='Description'),
),
migrations.AlterField(
model_name='place',
name='latitude',
field=models.FloatField(help_text='Latitude in decimal format: e. g. 41.40338', validators=[django.core.validators.MinValueValidator(-90), django.core.validators.MaxValueValidator(90)], verbose_name='Latitude'),
),
migrations.AlterField(
model_name='place',
name='location',
field=models.CharField(max_length=50, verbose_name='Location'),
),
migrations.AlterField(
model_name='place',
name='longitude',
field=models.FloatField(help_text='Longitude in decimal format: e. g. 2.17403', validators=[django.core.validators.MinValueValidator(-180), django.core.validators.MaxValueValidator(180)], verbose_name='Longitude'),
),
migrations.AlterField(
model_name='place',
name='name',
field=models.CharField(max_length=50, verbose_name='Name'),
),
migrations.AlterField(
model_name='place',
name='submitted_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='places', to='lostplaces.explorer', verbose_name='Submitter'),
),
migrations.AlterField(
model_name='place',
name='submitted_when',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date'),
),
migrations.AlterField(
model_name='placeimage',
name='description',
field=models.TextField(blank=True, verbose_name='Description'),
),
migrations.AlterField(
model_name='placeimage',
name='filename',
field=easy_thumbnails.fields.ThumbnailerImageField(help_text='Optional: One or more images to upload', upload_to=lostplaces.models.place.generate_image_upload_path, verbose_name='Filename(s)'),
),
migrations.AlterField(
model_name='placeimage',
name='submitted_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer', verbose_name='Submitter'),
),
migrations.AlterField(
model_name='placeimage',
name='submitted_when',
field=models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date'),
),
migrations.AlterField(
model_name='voucher',
name='created_when',
field=models.DateTimeField(auto_now_add=True, verbose_name='Creation date'),
),
migrations.AlterField(
model_name='voucher',
name='expires_when',
field=models.DateTimeField(verbose_name='Expiration date'),
),
]

View File

@@ -6,7 +6,7 @@ from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0004_auto_20201225_1702'),
('lostplaces', '0004_gory_fix'),
]
operations = [

View File

@@ -95,7 +95,6 @@ def auto_delete_file_on_change(sender, instance, **kwargs):
old_file = Explorer.objects.get(pk=instance.pk).profile_image
except Explorer.DoesNotExist:
return False
print("Deleting:", old_file)
new_file = instance.profile_image
if not old_file == new_file:
old_file.delete(save=False)

View File

@@ -11,6 +11,7 @@ from lostplaces.models.abstract_models import Submittable, Taggable, Mapable
from easy_thumbnails.fields import ThumbnailerImageField
from easy_thumbnails.files import get_thumbnailer
class Place(Submittable, Taggable, Mapable):
"""
Place defines a lost place (location, name, description etc.).
@@ -25,8 +26,31 @@ class Place(Submittable, Taggable, Mapable):
verbose_name=_('Description'),
)
hero = models.ForeignKey(
'PlaceImage',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='place_heros'
)
def get_hero_image(self):
if self.hero:
return self.hero
elif len(self.placeimages.all()) > 0:
return self.placeimages.first()
else:
return None
def get_absolute_url(self):
return reverse('place_detail', kwargs={'pk': self.pk})
def get_hero_index_in_queryset(self):
for i in range(0, len(self.placeimages.all())):
image = self.placeimages.all()[i]
if image == self.hero:
return i
return None
@classmethod
@@ -48,7 +72,6 @@ class Place(Submittable, Taggable, Mapable):
def __str__(self):
return self.name
def generate_place_image_filename(instance, filename):
"""
Callback for generating filename for uploaded place images.
@@ -57,6 +80,9 @@ def generate_place_image_filename(instance, filename):
return 'places/' + str(instance.place.pk) + '-' + str(instance.place.name) + '.' + filename.split('.')[-1]
def generate_image_upload_path(instance, filename):
return generate_place_image_filename(instance, filename)
class PlaceAsset(Submittable):
"""
Assets to a place, i.e. images
@@ -72,6 +98,9 @@ class PlaceAsset(Submittable):
null=True
)
class DummyAsset(PlaceAsset):
name = models.CharField(max_length=50)
class PlaceImage(PlaceAsset):
"""
PlaceImage defines an image file object that points to a file in uploads/.
@@ -87,7 +116,7 @@ class PlaceImage(PlaceAsset):
upload_to=generate_place_image_filename,
resize_source=dict(size=(2560, 2560),
sharpen=True),
verbose_name=_('Filename(s)'),
verbose_name=_('Images'),
help_text=_('Optional: One or more images to upload')
)
place = models.ForeignKey(
@@ -102,7 +131,7 @@ class PlaceImage(PlaceAsset):
of this image as textual representation of this instance
"""
return 'Image ' + str(self.pk)
return 'Image ' + str(self.place.name)
# These two auto-delete files from filesystem when they are unneeded:

View File

@@ -611,6 +611,12 @@ body {
font-weight: bold;
cursor: pointer;
white-space: nowrap; }
.LP-Button--fullWidth {
text-align: center; }
.LP-Button.LP-Link {
display: block; }
.LP-Button.LP-Link:hover {
color: #f9f9f9; }
.LP-Button:active {
background-color: #76323F;
color: #f9f9f9; }
@@ -717,6 +723,10 @@ body {
margin: 0;
padding: 0; }
.LP-Figure {
padding: 0;
margin: 0; }
.LP-Logo {
max-width: 100%;
max-height: 100%;
@@ -848,6 +858,13 @@ body {
.LP-Pagination .LP-Pagination__Item .LP-Link {
padding: 8px 11px; } }
.LP-Select {
display: block;
cursor: pointer; }
.LP-Select:checked,
:checked + .LP-Select, .LP-Select--active {
box-shadow: 0 0 3px 3px #C09F80; }
.LP-Content {
padding: 35px; }
@@ -1665,6 +1682,12 @@ body {
object-position: botom; }
.LP-ImageGrid__Item--center img {
object-position: center; }
.LP-ImageGrid__Item img {
height: unset;
width: unset; }
.LP-ImageGrid__Item .LP-Image {
height: 100%;
width: 100%; }
.LP-ImageGrid__Item--add .LP-Link {
width: 100%;
height: 100%;
@@ -1698,6 +1721,59 @@ body {
top: 7.8125px; }
.LP-ImageGrid__Item > .LP-Link:hover + .LP-ImageGrid__DeleteItem, .LP-ImageGrid__DeleteItem:hover {
visibility: visible; }
.LP-ImageGrid__LightBox {
visibility: hidden;
display: none;
position: fixed;
pointer-events: none;
flex-direction: row;
justify-content: center;
align-items: center;
background-color: rgba(86, 86, 86, 0.9);
padding: 2rem;
padding-bottom: 0;
width: 100vw;
height: 100vh;
z-index: 30;
top: 0;
left: 0;
box-sizing: border-box; }
.LP-ImageGrid__LightBox:target {
visibility: visible;
display: grid;
justify-items: center;
grid-template-areas: 'picture picture' 'previous next';
grid-template-rows: 1fr 4rem;
grid-template-columns: 1fr 1fr;
pointer-events: initial; }
.LP-ImageGrid__FullSizeImage {
grid-area: picture;
max-width: 100%;
max-height: 100%;
height: unset;
width: unset; }
.LP-ImageGrid__Previous {
grid-area: previous;
align-self: center;
justify-self: end; }
.LP-ImageGrid__Next {
grid-area: next;
align-self: center;
justify-self: start; }
.LP-ImageGrid__Previous, .LP-ImageGrid__Next {
padding: 25px;
color: #D7CEC7;
text-decoration: none;
font-family: "Montserrat", Helvetica, sans-serif;
font-weight: bold;
font-size: 20px; }
.LP-ImageGrid__Close {
position: fixed;
right: 1rem;
top: 1rem;
left: unset;
visibility: visible;
opacity: 1; }
.LP-Map {
margin-bottom: 25px; }

View File

@@ -1,7 +1,7 @@
{% extends 'global.html'%}
{% load i18n %}
{% block title %}{% trans 'Forbidden' %}{% endblock %}
{% block title %}{% translate 'Forbidden' %}{% endblock %}
{% block additional_head %}
{% if request.META.HTTP_REFERER %}
@@ -11,6 +11,6 @@
{% block maincontent %}
{% if request.META.HTTP_REFERER %}
<p class="LP-Headline">{% trans 'You will be redirected in 5 seconds' %}</p><p class="LP-Headline"><a href="{{ request.META.HTTP_REFERER }}" class="LP-Link">{% trans 'Go Back' %}</a></p>
<p class="LP-Headline">{% translate 'You will be redirected in 5 seconds' %}</p><p class="LP-Headline"><a href="{{ request.META.HTTP_REFERER }}" class="LP-Link">{% translate 'Go Back' %}</a></p>
{% endif %}
{% endblock maincontent %}

View File

@@ -42,14 +42,14 @@
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">
<a href="{{explorer.user.email}}" class="LP-Link">{{explorer.user.email}}</a>
<a href="mailto:{{explorer.user.email}}" class="LP-Link">{{explorer.user.email}}</a>
</span>
</td>
{% endif %}
</tr>
<tr>
<td class="LP-UserInfo__Key">
<span class="LP-Paragraph">{% trans 'Joined' %}</span>
<span class="LP-Paragraph">{% translate 'Joined' %}</span>
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">{{explorer.user.date_joined|date:'d.m.Y'}}</span>
@@ -57,7 +57,7 @@
</tr>
<tr>
<td class="LP-UserInfo__Key">
<span class="LP-Paragraph">{% trans 'Places'%}</span>
<span class="LP-Paragraph">{% translate 'Places'%}</span>
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">{{place_count}}</span>
@@ -65,61 +65,33 @@
</tr>
<tr>
<td class="LP-UserInfo__Key">
<span class="LP-Paragraph">{% trans 'Place assets'%}</span>
<span class="LP-Paragraph">{% translate 'Place Assets'%}</span>
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">{{asset_count}}</span>
</td>
</tr>
<tr>
<td>
<a href="/explorer/update/"><button class="LP-Button LP-Button">{% trans 'Edit Profile' %}</button></a>
</td>
</tr>
</table>
<div class="LP-UserInfo__Edit">
<a href="{% url 'explorer_profile_update' %}" class="LP-Button LP-Button--fullWidth LP-Link">{% trans 'Edit Profile' %}</a>
</div>
</div>
</div>
</div>
</div>
<section class="LP-Section">
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Favorite places' %}</h1>
<ul class="LP-PlaceList__List">
{% for place in explorer.favorite_places.all %}
<li class="LP-PlaceList__Item">
{% include 'partials/place_teaser.html' with place=place extended=True %}
</li>
{% endfor %}
</ul>
{% include 'partials/nav/pagination.html' %}
</div>
</section>
<section class="LP-Section">
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Visited places' %}</h1>
<ul class="LP-PlaceList__List">
{% for place in explorer.visited_places.all %}
<li class="LP-PlaceList__Item">
{% include 'partials/place_teaser.html' with place=place extended=True %}
</li>
{% endfor %}
</ul>
{% include 'partials/nav/pagination.html' %}
</div>
</section>
<section class="LP-Section">
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Places submitted by' %} {{explorer.user.username}}</h1>
<ul class="LP-PlaceList__List">
{% for place in place_list %}
<li class="LP-PlaceList__Item">
{% include 'partials/place_teaser.html' with place=place extended=True %}
</li>
{% endfor %}
</ul>
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% translate 'Places submitted by' %} {{explorer.user.username}}</h1>
<ul class="LP-PlaceList__List">
{% for place in place_list %}
<li class="LP-PlaceList__Item">
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
{% include 'partials/place_teaser.html' with place=place extended=True %}
</a>
</li>
{% endfor %}
</ul>
{% include 'partials/nav/pagination.html' %}
@@ -127,47 +99,30 @@
</section>
<section class="LP-Section">
<h1 class="LP-Headline">{% trans 'Images submitted by' %} {{explorer.user.username}}</h1>
<div class="LP-ImageGrid">
<ul class="LP-ImageGrid__Container">
{% for place_image in assets.placeimages.all %}
<li class="LP-ImageGrid__Item">
<a href="{{ place_image.filename.large.url }}" class="LP-Link">
<img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}">
</a>
{% if user.explorer == place_image.submitted_by%}
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
<a href="{% url 'place_image_delete' pk=place_image.id %}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}" />
</a>
</span>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% translate 'Images submitted by' as submitted_by %}
{% include 'partials/placeImageGrid.html' with headline=submitted_by|add:' '|add:explorer.user.username image_list=assets.placeimages.all%}
</section>
<section class=" LP-Section">
<h1 class="LP-Headline">{% trans 'Photo albums submitted by' %} {{explorer.user.username}}</h1>
<div class="LP-LinkList">
<ul class="LP-LinkList__Container">
{% for photo_album in assets.photoalbums.all %}
<li class="LP-LinkList__Item">
<a target="_blank" href="{{photo_album.url}}" class="LP-Link">
<span class="LP-Text">{{photo_album.label}}</span>
</a>
{% if user.explorer == photo_album.submitted_by%}
<a href="{% url 'photo_album_delete' pk=photo_album.pk%}" class="LP-Link LP-LinkList__ItemHover" title="Delete Photo Album">
<div class="RV-Iconized__Container RV-Iconized__Container--small">
{% icon 'trash' className="RV-Iconized__Icon" %}
</div>
</a>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
<h1 class="LP-Headline">{% translate 'Photo albums submitted by' %} {{explorer.user.username}}</h1>
<div class="LP-LinkList">
<ul class="LP-LinkList__Container">
{% for photo_album in assets.photoalbums.all %}
<li class="LP-LinkList__Item">
<a target="_blank" href="{{photo_album.url}}" class="LP-Link">
<span class="LP-Text">{{photo_album.label}}</span>
</a>
{% if user.explorer == photo_album.submitted_by%}
<a href="{% url 'photo_album_delete' pk=photo_album.pk%}" class="LP-Link LP-LinkList__ItemHover" title="Delete Photo Album">
<div class="RV-Iconized__Container RV-Iconized__Container--small">
{% icon 'trash' className="RV-Iconized__Icon" %}
</div>
</a>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</section>
{% endblock maincontent %}

View File

@@ -0,0 +1,4 @@
<form method={{form.method}}>
{{form}}
<input type="submit"/>
</form>

View File

@@ -1,5 +1,6 @@
{% load static %}
{% load i18n %}
{% load lostplaces%}
<!DOCTYPE html>
<html lang="en">
@@ -29,16 +30,16 @@
<span class="LP-Paragraph">
{% if user.is_authenticated %}
Hi {{ user.username }}!
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">{% trans 'Logout' %}</span></a> |
<a class="LP-Link" href="{% url 'explorer_profile' explorer_id=user.pk%}"><span class="LP-Link__Text">{% trans 'Profile' %}</span></a>
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">{% translate 'Logout' %}</span></a> |
<a class="LP-Link" href="{% url 'explorer_profile' explorer_id=user.pk%}"><span class="LP-Link__Text">{% translate 'Profile' %}</span></a>
{% if user.is_superuser %}
| <a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">{% trans 'Admin' %}</span></a>
| <a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">{% translate 'Admin' %}</span></a>
{% endif %}
{% else %}
You are not logged in.
<a class="LP-Link" href="{% url 'login' %}"><span class="LP-Link__Text">{% trans 'Login' %}</span></a> |
<a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign up' %}</span></a>
<a class="LP-Link" href="{% url 'login' %}"><span class="LP-Link__Text">{% translate 'Login' %}</span></a> |
<a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% translate 'Sign up' %}</span></a>
{% endif %}
</span>
</div>
@@ -48,14 +49,14 @@
<aside class="LP-Main__Sidebar">
<nav class="LP-Menu LP-Menu--sidebar">
<ul class="LP-Menu__List">
<li class="LP-Menu__Item"><a href="{% url 'lostplaces_home' %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Home' %}</span></a></li>
<li class="LP-Menu__Item"><a href="{% url 'flatpage' slug='codex' %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'UrBex Codex' %}</span></a></li>
<li class="LP-Menu__Item"><a href="{% url 'osm' %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Map' %}</span></a></li>
<li class="LP-Menu__Item"><a href="{% url 'lostplaces_home' %}" class="LP-Link"><span class="LP-Link__Text">{% translate 'Home' %}</span></a></li>
<li class="LP-Menu__Item"><a href="{% url 'flatpage' slug='codex' %}" class="LP-Link"><span class="LP-Link__Text">{% translate 'UrBex Codex' %}</span></a></li>
{% block additional_menu_items %}
{% endblock additional_menu_items %}
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_create'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Create place' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_list'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'All places' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_create'%}" class="LP-Link"><span class="LP-Link__Text">{% translate '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">{% translate 'All places' %}</span></a></li>
</ul>
</nav>
</aside>
@@ -87,7 +88,7 @@
</div>
{% block footer %}
{% include 'partials/nav/footer.html' %}
{% partial 'nav/footer' %}
{% endblock footer %}
</body>

View File

@@ -2,22 +2,25 @@
{% load static %}
{% load i18n %}
{% load lostplaces %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
# {% block title %}{% trans 'Home' %}{% endblock %}
# {% block title %}{% translate 'Home' %}{% endblock %}
{% block maincontent %}
{% include 'partials/welcome.html' %}
{% partial 'welcome' %}
<article class="LP-TextSection">
</article>
{% include 'partials/osm_map.html' with config=mapping_config modifier='wide' %}
{% partial 'osm_map' %}
{% set config mapping_config %}
{% set modifier 'wide' %}
{% endpartial %}
<div class="LP-PlaceGrid">
<h1 class="LP-Headline LP-Headline">{% trans 'Explore the latest places' %}</h1>
<h1 class="LP-Headline LP-Headline">{% translate 'Explore the latest places' %}</h1>
<ul class="LP-PlaceGrid__Grid">
{% for place in place_list %}
<li class="LP-PlaceGrid__Item">
@@ -26,5 +29,4 @@
{% endfor %}
</ul>
</div>
{% endblock maincontent %}

View File

@@ -1,30 +1,33 @@
{% extends 'global.html'%}
{% load i18n %}
{% load lostplaces%}
# {% block title %}Start{% endblock %}
{% block maincontent %}
{% include 'partials/welcome.html' %}
{% partial 'welcome' %}
<article class="LP-TextSection">
<p class="LP-Paragraph">
{% blocktrans %}You can create, view and share your lost places with other members of this site. You can upload photos, place links to your web galleries and contribute your knowledge by tagging other places or commenting on them. You will find detailed information on where these locations are, how to get there and what to expect from them. This might even include detailed information on the surroundings or the history of a lost place.{% endblocktrans %}
{% blocktranslate %}You can create, view and share your lost places with other members of this site. You can upload photos, place links to your web galleries and contribute your knowledge by tagging other places or commenting on them. You will find detailed information on where these locations are, how to get there and what to expect from them. This might even include detailed information on the surroundings or the history of a lost place.{% endblocktranslate %}
</p>
{% url 'signup' as signup_url %}
<p class="LP-Paragraph">
{% blocktrans %}Since vandalism is a growing problem these days, no sensitive information is available to the public. You have to <a class="LP-Link" href="{{signup_url}}"><span class="LP-Link__Text">sign up</span></a> with a voucher code as an invitation to join this community. Only admins can create these codes. Usually you are given a code when we know you in real life in person and when we trust you. A request from an unknown person will most probably be denied.{% endblocktrans %}
{% blocktranslate %}Since vandalism is a growing problem these days, no sensitive information is available to the public. You have to <a class="LP-Link" href="{{signup_url}}"><span class="LP-Link__Text">sign up</span></a> with a voucher code as an invitation to join this community. Only admins can create these codes. Usually you are given a code when we know you in real life in person and when we trust you. A request from an unknown person will most probably be denied.{% endblocktranslate %}
</p>
</article>
<div class="LP-PlaceGrid">
<h1 class="LP-Headline LP-Headline">{% trans 'Explore the latest places' %}</h1>
<h1 class="LP-Headline LP-Headline">{% translate 'Explore the latest places' %}</h1>
<ul class="LP-PlaceGrid__Grid">
{% for place in place_list %}
<li class="LP-PlaceGrid__Item">
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
<article class="LP-PlaceTeaser">
<div class="LP-PlaceTeaser__Image">
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
{% partial 'image' %}
{% set source_url place.placeimages.first.filename.thumbnail.url %}
{% endpartial %}
</div>
<div class="LP-PlaceTeaser__Meta">
<div class="LP-PlaceTeaser__Info">

View File

@@ -2,9 +2,7 @@
<div class="LP-Input {% if classes%}{{classes}}{% endif %} {% if field.errors %} LP-Input--error {% endif %}">
<label for="{{field.id_for_label}}" class="LP-Input__Label">{{field.label}}</label>
{% with class="LP-Input__Field "%}
{% render_field field class=class%}
{% endwith %}
{% render_field field class+='LP-Input__Field' %}
<span class="LP-Input__Message">
{% if field.errors %}

View File

@@ -1,9 +1,9 @@
{% load i18n %}
<div class="LP-Form__Field LP-Form__Button LP-Input">
<button class="LP-Button">{% if action %}{{ action }}{% else %}{% trans 'Submit' %}{% endif %}</button>
<button class="LP-Button">{% if action %}{{ action }}{% else %}{% translate 'Submit' %}{% endif %}</button>
</div>
<div class="LP-Form__Field LP-Form__Button LP-Input">
<a class="LP-Link" href="{% if referer %}{{ referer }}{% else %}{% url 'lostplaces_home' %}{% endif %}">
<button type="button" class="LP-Button LP-Button--cancel">{% trans 'Cancel' %}</button>
<button type="button" class="LP-Button LP-Button--cancel">{% translate 'Cancel' %}</button>
</a>
</div>

View File

@@ -0,0 +1,18 @@
{% if link_url %}
<a
class="LP-Link"
href="{{link_url}}"
>
{% endif %}
<figure class="LP-Figure">
<img
src="{{ source_url }}"
{% if alt_text %}
alt="{{alt_text}}"
{% else %}
alt="{{block}}"
{% endif %}
class="LP-Image"
/>
</figure>
{% if link_url %}</a>{% endif %}

View File

@@ -61,13 +61,13 @@
<!-- Bottom section with last line of text and links. -->
<section class="LP-Footer__BottomSection LP-Footer__Flex">
<div class="LP-Footer__BottomWrapper">
{% trans 'Made by' %} <a href="https://git.mowoe.com/reverend" class="LP-Footer__GenericAnchor">Reverend</a>
{% trans 'and' %} <a href="https://www.commander1024.de" class="LP-Footer__GenericAnchor">Commander1024.</a></span>
{% translate 'Made by' %} <a href="https://git.mowoe.com/reverend" class="LP-Footer__GenericAnchor">Reverend</a>
{% translate 'and' %} <a href="https://www.commander1024.de" class="LP-Footer__GenericAnchor">Commander1024.</a></span>
</div>
<div class="LP-Footer__BottomWrapper">
<a href="{% url 'flatpage' slug='privacy-policy' %}" class="LP-Footer__GenericAnchor">{% trans 'Privacy Policy' %}</a>
<a href="{% url 'flatpage' slug='privacy-policy' %}" class="LP-Footer__GenericAnchor">{% translate 'Privacy Policy' %}</a>
|
<a href="{% url 'flatpage' slug='imprint' %}" class="LP-Footer__GenericAnchor">{% trans 'Imprint' %}</a>
<a href="{% url 'flatpage' slug='imprint' %}" class="LP-Footer__GenericAnchor">{% translate 'Imprint' %}</a>
</div>
</section>
</footer>

View File

@@ -8,26 +8,26 @@
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--first">
<a href="?page=1" class="LP-Link">
<span class="LP-Icon"></span>
<span class="LP-Text">{% trans 'First' %}</span>
<span class="LP-Text">{% translate '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">{% trans 'Previous' %}</span>
<span class="LP-Text">{% translate '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">{% trans 'First' %}</span>
<span class="LP-Text">{% translate '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">{% trans 'Previous' %}</span>
<span class="LP-Text">{% translate 'Previous' %}</span>
</a>
</li>
{% endif %}
@@ -47,25 +47,25 @@
{% if page_obj.has_next %}
<li class="LP-Pagination__Item LP-Pagination__Item--other LP-Pagination__Item--next">
<a href="?page={{ page_obj.next_page_number }}" class="LP-Link">
<span class="LP-Text">{% trans 'Next' %}</span>
<span class="LP-Text">{% translate '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">{% trans 'Last' %}</span>
<span class="LP-Text">{% translate '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">{% trans 'Next' %}</span>
<span class="LP-Text">{% translate '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">{% trans 'Last' %}</span>
<span class="LP-Text">{% translate 'Last' %}</span>
<span class="LP-Icon"></span>
</a>
</li>

View File

@@ -0,0 +1,43 @@
{% load static %}
{% load lostplaces %}
{% if headline %}
<h1 class="LP-Headline">{{headline}}</h1>
{% endif %}
<div class="LP-ImageGrid">
<ul class="LP-ImageGrid__Container">
{% for image in image_list %}
<li id="thumbnail{{forloop.counter0}}" class="LP-ImageGrid__Item">
{% include 'partials/image.html' with source_url=image.filename.thumbnail.url link_url="#image"|addstr:forloop.counter0 %}
{% if user.explorer == image.submitted_by%}
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
<a href="{% url 'place_image_delete' pk=image.id %}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}" />
</a>
</span>
{% endif %}
<div id="image{{forloop.counter0}}" class="LP-ImageGrid__LightBox">
<img class="LP-ImageGrid__FullSizeImage" src="{{image.filename.large.url}}" loading="lazy"/>
{% if forloop.counter0 < image_list|length|add:-1 %}
<a href="#image{{forloop.counter0|add:1}}" class="LP-ImageGrid__Next">Next</a>
{% endif %}
{% if forloop.counter0 > 0 %}
<a href="#image{{forloop.counter0|add:-1}}" class="LP-ImageGrid__Previous">Previous</a>
{% endif %}
<span class="LP-ImageGrid__Close LP-ImageGrid__DeleteItem" title="Schließen">
<a href="#thumbnail{{forloop.counter0}}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}"/>
</a>
</span>
</div>
</li>
{% endfor %}
{% if place %}
<li class="LP-ImageGrid__Item LP-ImageGrid__Item--add" title="Bild hinzufügen">
<a class="LP-Link" href="{% url 'place_image_create' place_id=place.id %}">
<img class="LP-Icon" src="{% static 'icons/plus.svg' %}" />
</a>
</li>
{% endif %}
</ul>
</div>

View File

@@ -1,13 +1,14 @@
{%load static %}
<article class="LP-PlaceTeaser {% if extended %} LP-PlaceTeaser--extended{% endif %}">
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
<div class="LP-PlaceTeaser__Image">
{% if place.placeimages.all|length > 0 %}
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
{% else %}
<img class="LP-Image" src="{% static 'images/missing_image.png' %}" />
{% endif %}
<div class="LP-PlaceTeaser__Image">
{% if place.get_hero_image %}
{% include 'partials/image.html' with source_url=place.get_hero_image.filename.thumbnail.url link_url=place.get_absolute_url%}
{% else %}
<a href="{{place.get_absolute_url}}">
<img class="LP-Image" src="{% static 'images/missing_image.png' %}" />
</a>
{% endif %}
</div>
</a>
<div class="LP-PlaceTeaser__Meta">

View File

@@ -0,0 +1,3 @@
{%load lostplaces %}
{% include 'partials/image.html' with source_url=object.filename.thumbnail.url %}

View File

@@ -25,13 +25,13 @@
</ul>
</div>
<form id="id_tag_submit_form" class="LP-Form LP-Form--inline LP-Form--tagging" method="POST" action="{% url config.submit_url_name tagged_id=config.tagged_item.id%}">
<form id="id_tag_submit_form" class="LP-Form LP-Form--inline LP-Form--tagging" method="POST" action="{{config.submit_url}}">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Add tags' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Add tags' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field LP-Form__Button LP-Input LP-Input--tagging">
<button id="id_tag_submit_button" class="LP-Button">{% trans 'Add tags' %}</button>
<button id="id_tag_submit_button" class="LP-Button">{% translate 'Add tags' %}</button>
</div>
<div class="LP-Form__Field">
{% include 'partials/form/inputField.html' with field=config.submit_form.tag_list classes="LP-Input--tagging" %}

View File

@@ -1,21 +1,21 @@
{% load i18n %}
<header class="LP-TextSection__Headline">
<h1 class="LP-Headline">{% trans 'Start' %}</h1>
<h1 class="LP-Headline">{% translate 'Start' %}</h1>
</header>
<div class="LP-TextSection__Text">
<p class="LP-Paragraph">{% trans 'Welcome to our Urban Exploration community catalogue,' %}
<p class="LP-Paragraph">{% translate 'Welcome to our Urban Exploration community catalogue,' %}
{% if user.is_authenticated %}
{{ user.username }}
{% else %}
{% trans 'explorer' %}
{% translate 'explorer' %}
{% endif %}
!
</p>
<p class="LP-Paragraph">
{% trans 'We strictly follow our' %}
<a class="LP-Link" href="{% url 'flatpage' slug='codex' %}"><span class="LP-Link__Text">{% trans 'UrBex codex' %}</span></a>
{% trans 'and expect you to do so, too.' %}'
{% translate 'We strictly follow our' %}
<a class="LP-Link" href="{% url 'flatpage' slug='codex' %}"><span class="LP-Link__Text">{% translate 'UrBex codex' %}</span></a>
{% translate 'and expect you to do so, too.' %}'
</p>
</div>

View File

@@ -1,19 +1,19 @@
{% extends 'global.html'%}
{% load i18n %}
{% block title %}{% trans 'Submit a photo album' %}{% endblock %}
{% block title %}{% translate 'Submit a photo album' %}{% endblock %}
{% block additional_menu_items %}
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_edit' pk=place.pk %}" class="LP-Link"><span
class="LP-Link__Text">{% trans 'Edit place' %}</span></a></li>
class="LP-Link__Text">{% translate 'Edit place' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_delete' pk=place.pk %}" class="LP-Link"><span
class="LP-Link__Text">{% trans 'Delete place' %}</span></a></li>
class="LP-Link__Text">{% translate 'Delete place' %}</span></a></li>
{% endblock additional_menu_items %}
{% block maincontent %}
<form class="LP-Form" method="POST">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Submit a photo album for' %} {{place.name}}</legend>
<legend class="LP-Form__Legend">{% translate 'Submit a photo album for' %} {{place.name}}</legend>
{% csrf_token %}
<div class="LP-Form__Composition">
<div class="LP-Form__Field">

View File

@@ -2,12 +2,12 @@
{% load static %}
{% load i18n %}
# {% block title %}{% trans 'Create place' %}{% endblock %}
# {% block title %}{% translate 'Create place' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Create place' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Create place' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">
@@ -39,7 +39,7 @@
</div>
</div>
{% trans 'Create' as action %}
{% translate 'Create' as action %}
<div class="LP-Form__Composition LP-Form__Composition--buttons">
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER action=action %}
</div>

View File

@@ -2,21 +2,21 @@
{% load static %}
{% load i18n %}
{% block title %}{% trans 'Delete lost place' %}{% endblock %}
{% block title %}{% translate 'Delete lost place' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Delete place' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Delete place' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition">
<div class="LP-Form__Field LP-Form__InfoText">
<p class="LP-Paragraph">{% blocktrans with place_name=place.name%}Are you sure you want to delete {{place_name}}?{% endblocktrans %}</p>
<p class="LP-Paragraph">{% blocktranslate with place_name=place.name%}Are you sure you want to delete {{place_name}}?{% endblocktranslate %}</p>
</div>
</div>
{% trans 'Delete' as action %}
{% translate 'Delete' as action %}
<div class="LP-Form__Composition LP-Form__Composition--buttons">
{% include 'partials/form/submit.html' with referer=request.META.HTTP_REFERER action=action %}
</div>

View File

@@ -4,6 +4,7 @@
{% load thumbnail %}
{% load svg_icon %}
{% load lostplaces %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
@@ -15,19 +16,23 @@
{% 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">{% trans 'Edit place' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_delete' pk=place.pk %}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Delete place' %}</span></a></li>
<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">{% translate '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">{% translate '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 }} {% include 'partials/icons/place_favorite.html' %} {% include 'partials/icons/place_visited.html' %}</h1>
{% if place.placeimages.first.filename.hero.url %}
<figure class="LP-PlaceDetail__Image">
<img src="{{ place.placeimages.first.filename.hero.url }}" class="LP-Image" />
</figure>
{% if place.get_hero_image %}
<div class="LP-PlaceDetail__Image">
{% partial image %}
{% set source_url place.get_hero_image.filename.hero.url %}
{% set link_url %}
{{"#image"|addstr:place.get_hero_index_in_queryset}}
{% endset %}
{% endpartial %}
</div>
{% endif %}
</header>
@@ -38,13 +43,15 @@
<section class="LP-Section">
{% url 'place_tag_submit' place_id=place.id as tag_submit_url%}
{% include 'partials/tagging.html' with config=tagging_config %}
{% partial tagging %}
{% set config=tagging_config %}
{% endpartial %}
</section>
<section class="LP-Section">
<h1 class="LP-Headline">{% trans 'Map links' %}</h1>
{% include 'partials/osm_map.html' with config=mapping_config modifier='wide' %}
<h1 class="LP-Headline">{% translate 'Map links' %}</h1>
{% partial osm_map config=mapping_config %}
<div class="LP-LinkList">
<ul class="LP-LinkList__Container">
<li class="LP-LinkList__Item"><a target="_blank" href="https://www.google.com/maps?q={{place.latitude|safe}},{{place.longitude|safe}}" class="LP-Link"><span class="LP-Text">Google Maps</span></a></li>
@@ -55,7 +62,7 @@
</section>
<section class=" LP-Section">
<h1 class="LP-Headline">{% trans 'Photo albums' %}</h1>
<h1 class="LP-Headline">{% translate 'Photo albums' %}</h1>
<div class="LP-LinkList">
<ul class="LP-LinkList__Container">
{% for photo_album in place.photoalbums.all %}
@@ -81,7 +88,7 @@
v216c0,11.046,8.954,20,20,20s20-8.954,20-20V276h216c11.046,0,20-8.954,20-20C512,244.954,503.046,236,492,236z" />
</g>
</svg>
<span class="RV-Iconized__Text">{% trans 'Add photo album' %}</span>
<span class="RV-Iconized__Text">{% translate 'Add photo album' %}</span>
</div>
</a>
</li>
@@ -90,30 +97,8 @@
</section>
<section class="LP-Section">
<h1 class="LP-Headline">{% trans 'Images' %}</h1>
<div class="LP-ImageGrid">
<ul class="LP-ImageGrid__Container">
{% for place_image in place.placeimages.all %}
<li class="LP-ImageGrid__Item">
<a href="{{ place_image.filename.large.url }}" class="LP-Link">
<img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}">
</a>
{% if user.explorer == place_image.submitted_by or user.explorer == place.submitted_by %}
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
<a href="{% url 'place_image_delete' pk=place_image.id %}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}" />
</a>
</span>
{% endif %}
</li>
{% endfor %}
<li class="LP-ImageGrid__Item LP-ImageGrid__Item--add" title="Bild hinzufügen">
<a class="LP-Link" href="{% url 'place_image_create' place_id=place.id%}">
<img class="LP-Icon" src="{% static 'icons/plus.svg' %}" />
</a>
</li>
</ul>
</div>
{% translate 'Images' as headline %}
{% partial "placeImageGrid" image_list=place.placeimages.all %}
</section>
</article>

View File

@@ -7,13 +7,13 @@
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
{% block title %}{% trans 'All Places' %}{% endblock %}
{% block title %}{% translate 'All Places' %}{% endblock %}
{% block maincontent %}
{% include 'partials/osm_map.html' with config=mapping_config modifier='wide' %}
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Our lost places' %}</h1>
<h1 class="LP-Headline">{% translate 'Our lost places' %}</h1>
<ul class="LP-PlaceList__List">
{% for place in place_list %}
<li class="LP-PlaceList__Item">

View File

@@ -1,13 +1,14 @@
{% extends 'global.html'%}
{% load static %}
{% load i18n %}
{% load widget_tweaks %}
# {% block title %}{% trans 'Edit place' %}{% endblock %}
# {% block title %}{% translate 'Edit place' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Edit place' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Edit place' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">
@@ -38,8 +39,17 @@
{% include 'partials/form/inputField.html' with field=form.filename %}
</div>
</div>
{% if object.placeimages.all|length > 0 %}
<legend class="LP-Form__Legend">{% translate 'Set Hero Image' %}</legend>
<div class="LP-Form__Composition">
<div class="LP-Form__Field">
{% render_field form.hero container_class='LP-ImageGrid__Container' item_class='LP-ImageGrid__Item LP-Select' current_selected_value=object.hero.id%}
</div>
</div>
{% endif %}
{% trans 'Update' as action %}
{% translate 'Update' as action %}
<div class="LP-Form__Composition LP-Form__Composition--buttons">
{% include 'partials/form/submit.html' with referrer=request.META.HTTP_REFERER action=action %}
</div>

View File

@@ -4,7 +4,7 @@
{% block maincontent %}
<form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Submit images to a place' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Submit images to a place' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition">

View File

@@ -1,13 +1,13 @@
{% extends 'global.html'%}
{% load static %}
{% load i18n %}
# {% block title %}{% trans 'Login' %}{% endblock %}
# {% block title %}{% translate 'Login' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Login' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Login' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">
@@ -20,12 +20,12 @@
<div class="LP-Form__Composition LP-Form__Composition--buttons">
<div class="LP-Form__Field LP-Form__Button LP-Input">
<button class="LP-Button">{% trans 'Login' %}</button>
<button class="LP-Button">{% translate 'Login' %}</button>
</div>
</div>
</fieldset>
</form>
<p class="LP-Headline">{% trans 'No account, yet?' %} <a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign up' %}</span></a></p>
<p class="LP-Headline">{% translate 'No account, yet?' %} <a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% translate 'Sign up' %}</span></a></p>
{% endblock maincontent %}

View File

@@ -3,13 +3,13 @@
{% load i18n %}
{% load widget_tweaks %}
# {% block title %}{% trans 'Sign up' %}{% endblock %}
# {% block title %}{% translate 'Sign up' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Sign up' %}</legend>
<legend class="LP-Form__Legend">{% translate 'Sign up' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">
@@ -46,7 +46,7 @@
<div class="LP-Form__Composition LP-Form__Composition--buttons">
<div class="LP-Form__Field LP-Form__Button LP-Input">
<button class="LP-Button">{% trans 'Sign up' %}</button>
<button class="LP-Button">{% translate 'Sign up' %}</button>
</div>
</div>
</fieldset>

View File

@@ -0,0 +1,23 @@
<ul class="{{widget.attrs.container_class}}">
{% for group_name, group_choices, group_index in widget.optgroups %}
{% for option in group_choices %}
{% if option.value %}
<li style="display: content;">
<input
style="display: none;"
name="{{option.name}}"
id="{{widget.attrs.id}}{{group_index}}"
type="radio"
value="{{option.value.instance.id}}"
{% if widget.attrs.current_selected_value|stringformat:'s' == option.value.instance.id|stringformat:'s' %}checked="checked"{% endif %}
/>
<label class="{{widget.attrs.item_class}}" for="{{widget.attrs.id}}{{group_index}}">
{% if widget.attrs.item_template %}
{% include widget.attrs.item_template with object=option.value.instance %}
{% endif %}
</label>
</li>
{% endif %}
{% endfor %}
{% endfor %}
</ul>

View File

@@ -6,6 +6,16 @@ from django.http import request
register = template.Library()
def remove_formatting(string):
if type(string) is str:
for to_strip in ["'", '"', ' ']:
string = string.strip(to_strip)
for to_remove in ['\t', '\n',]:
string = string.replace(to_remove, '')
return string
@register.filter(name='proper_paginate')
def proper_paginate(paginator, current_page, neighbors=2):
if paginator.num_pages > 2*neighbors:
@@ -24,3 +34,97 @@ def proper_paginate(paginator, current_page, neighbors=2):
page_list = [f for f in range(start_index, end_index+1)]
return page_list[:(2*neighbors + 1)]
return paginator.page_range
@register.filter
def addstr(value, parameter):
return str(value) + str(parameter)
class VariableNode(template.Node):
def __init__(self, name, content=None):
if content==None and '=' in name:
self.content = name.split('=')[1]
self.name = name.split('=')[0]
else:
self.content = content
self.name = name
def render(self, context):
if type(self.content) is not str:
self.content = self.content.render(context)
try:
self.content = template.Variable(self.content).resolve(context)
except template.VariableDoesNotExist:
pass
self.content = remove_formatting(self.content)
context[self.name] = self.content
return ''
class PartialNode(template.Node):
def __init__(self, name, block):
self.name = remove_formatting(name)
self.block = block
def render(self, context):
if type(self.block) is template.NodeList:
self.block = self.block.render(context)
self.block = remove_formatting(self.block)
context = context.flatten()
context['block'] = self.block
t = template.loader.get_template('partials/%s.html' % self.name)
return t.render(context)
@register.tag(name='set')
def set_block(parser, token):
split = token.split_contents()
if len(split) >= 1:
variable_name = split[1]
else:
raise template.TemplateSyntaxError('%r expects a variable name' % split[0])
if len(split) == 2:
content=None
if '=' not in variable_name:
content = parser.parse(('end%s'%split[0],))
parser.delete_first_token()
return VariableNode(variable_name, content)
else:
return VariableNode(variable_name, split[2])
@register.tag(name='partial')
def partial(parser, token):
split = token.split_contents()
if len(split) >= 1:
partial_name = split[1]
else:
raise template.TemplateSyntaxError('%r expects a partial name' % split[0])
if len(split) == 2:
block_tag = False
for token in reversed(parser.tokens):
if 'end%s'%split[0] in token.contents:
block_tag = True
break
if split[0] in token.contents:
break
if block_tag:
nodeList = parser.parse(('end%s'%split[0],))
parser.delete_first_token()
else:
nodeList = template.NodeList()
return PartialNode(partial_name, nodeList)
else:
nodeList = template.NodeList()
for parameter in split[2:]:
if '=' in parameter:
nodeList.append(
VariableNode(name=parameter)
)
else:
raise template.TemplateSyntaxError('%r expects kwargs, got args' % split[0])
return PartialNode(partial_name, nodeList)

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from django.test import TestCase
@@ -16,6 +17,20 @@ class ViewTestCase(TestCase):
'''
view = None
def assertMessage(self, response, message_text, message_type, msg=None):
self.assertNotEqual(
None,
re.search(
"""<div.*message.*%s.*>.*%s.*</div>""" % (
message_type.lower(),
message_text.lower()
),
response.content.decode().replace('\n', '').lower()
),
msg
)
def assertContext(self, response, key, value=None):
'''
Checks weather the response's context has the given key
@@ -87,7 +102,7 @@ class ViewTestCase(TestCase):
self.assertEqual(
response['location'],
redirect_to,
msg='Expecting the response to redirect to %s, where redirected to %s instea' % (
msg='Expecting the response to redirect to %s, where redirected to %s instead' % (
str(redirect_to),
str(response['location'])
)
@@ -113,6 +128,84 @@ class ViewTestCase(TestCase):
def assertHttpMethodNotAllowed(self, response):
self.assertHttpCode(response, 405)
class GlobalTemplateTestCaseMixin:
def assertGlobal(self, response):
self.assertLogo(response)
self.assertMenu(response)
self.assertProfileMenu(response)
def assertLogo(self, response):
"""
Looks for an image tag with with 'logo' or 'Logo' in the file name
all within an <header> tag.
"""
self.assertNotEqual(
None,
re.search(
"""<header.*>.*<img.*src=("|').*(logo|Logo).*("|').*>.*</header>""",
response.content.decode().replace('\n', '')
),
msg='Expecting a header containing a logo with \'logo\' in the source name'
)
def assertMenu(self, response):
"""
Looks for an '<nav>' tag containing a link to / and a link labeled 'urbex code.*'
"""
self.assertNotEqual(
None,
re.search(
"""<nav.*>.*<a.*href=("|')/("|').*>.*<a.*>.*urbex code.*</nav>""",
response.content.decode().replace('\n', '').lower()
),
msg='Expecting an menu containing a link to the homepage and a link to the urbex codex'
)
def assertMenuItem(self, response, label=None, url=None):
"""
Checks for an additional menu item by label or url. Regex can be passed.
"""
if label is None and url is None:
raise ValueError("Either a label or url has to be provided")
found_label = None
if label != None:
label = label.lower()
found_label = re.search(
"""<nav.*>.*<a.*>.*%s.*</a>.*</nav>""" % label,
response.content.decode().replace('\n', '').lower()
)
found_url = None
if url != None:
url = url.lower()
found_url = re.search(
"""<nav.*>.*<a.*href=("|')%s("|')>.*</a>.*</nav>""" % url,
response.content.decode().replace('\n', '')
)
self.assertTrue(
found_label != None and found_url != None,
msg='Expecting an menu item with either label \'%s\' or url \'%s\'' % (
label,
url
)
)
def assertProfileMenu(self, response):
"""
Looks for a logout or login+signup link within the an header tag
"""
self.assertNotEqual(
None,
re.search(
"""<header.*>.*(<a.*href=("|').*logout.*("|')|<a.*href=("|').*login.*("|').*<a.*href=("|').*signup.*("|')).*</header>""",
response.content.decode().replace('\n', '').lower()
),
msg='Expecting a profile menu containing either a logout link or a login and then a signup link'
)
class TaggableViewTestCaseMixin:
@@ -149,13 +242,13 @@ class TaggableViewTestCaseMixin:
)
self.assertTrue(
'submit_url_name' in context,
msg='Expecting the context for taggable to contain \'submit_url_name\' attribute'
'submit_url' in context,
msg='Expecting the context for taggable to contain \'submit_url\' attribute'
)
self.assertTrue(
type(context['submit_url_name']) == str,
msg='Expecting submit_url_name to be of type string'
type(context['submit_url']) == str,
msg='Expecting submit_url to be of type string'
)
self.assertTrue(

View File

@@ -1,15 +1,21 @@
#!/usr/bin/env python
23238#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.test import TestCase, RequestFactory, Client
from django.urls import reverse_lazy
from django.db import models
from django.contrib.auth.models import User, AnonymousUser
from django.contrib.messages.storage.fallback import FallbackStorage
from django.utils import timezone
from django.shortcuts import render
from lostplaces.models import Place
from lostplaces.views import IsAuthenticatedMixin
from lostplaces.views import (
IsAuthenticatedMixin,
PlaceAssetCreateView
)
from lostplaces.tests.views import ViewTestCase
from lostplaces.models import DummyAsset
class TestIsAuthenticated(ViewTestCase):
view = IsAuthenticatedMixin
@@ -20,9 +26,6 @@ class TestIsAuthenticated(ViewTestCase):
username='testpeter',
password='Develop123'
)
def setUp(self):
self.client = Client()
def test_logged_in(self):
request = RequestFactory().get('/')
@@ -33,16 +36,15 @@ class TestIsAuthenticated(ViewTestCase):
self.assertHttpMethodNotAllowed(response)
def test_not_logged_in(self):
request = RequestFactory().get('/someurl1234')
request = RequestFactory().get('/')
request.user = AnonymousUser()
request.session = 'session'
messages = FallbackStorage(request)
request._messages = messages
response = IsAuthenticatedMixin.as_view()(request)
self.assertHttpRedirect(response, '?'.join([str(reverse_lazy('login')), 'next=/someurl1234']))
self.assertHttpRedirect(response, '?'.join([str(reverse_lazy('login')), 'next=/']))
response = self.client.get(response['Location'])
self.assertTrue(len(messages) > 0)
class TestIsPlaceSubmitterMixin(TestCase):
@@ -86,4 +88,52 @@ class TestIsPlaceSubmitterMixin(TestCase):
response = self.client.get(reverse_lazy('place_edit', kwargs={'pk': 1}))
self.assertEqual(response.status_code, 403)
self.assertTrue(response.context['messages'])
self.assertTrue(len(response.context['messages']) > 0)
self.assertTrue(len(response.context['messages']) > 0)
class TestPlaceAssetCreateView(ViewTestCase):
view = PlaceAssetCreateView
class DummyAssetCreateView(PlaceAssetCreateView):
model = DummyAsset
fields = ['name']
template_name = 'flat_form.html'
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=timezone.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
def test_create_asset(self):
request = RequestFactory().post(
'/',
{
'name': 'im a place'
}
)
request.user = User.objects.get(id=1)
response = TestPlaceAssetCreateView.DummyAssetCreateView.as_view()(request, place_id=1)
self.assertTrue(
DummyAsset.objects.all().count() >= 1,
msg='Expecting a dummy place asset to be created by the view'
)
self.assertEqual(
DummyAsset.objects.get(id=1).name,
'im a place',
msg='Expecting the dummy place asset to have the correct data'
)

View File

@@ -1,10 +1,15 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import re
from os import path
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from django.utils import timezone
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from lostplaces.models import Place
@@ -17,44 +22,15 @@ from lostplaces.forms import PlaceImageForm, PlaceForm
from lostplaces.tests.views import (
ViewTestCase,
TaggableViewTestCaseMixin,
MapableViewTestCaseMixin
MapableViewTestCaseMixin,
GlobalTemplateTestCaseMixin
)
class TestPlaceCreateView(ViewTestCase):
view = PlaceCreateView
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=timezone.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def setUp(self):
self.client = Client()
def test_has_forms(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_create'))
self.assertHasForm(response, 'place_image_form', PlaceImageForm)
self.assertHasForm(response, 'place_form', PlaceForm)
class TestPlaceListView(ViewTestCase):
class TestPlaceListView(GlobalTemplateTestCaseMixin, ViewTestCase):
"""
Tests the view listing all placs
"""
view = PlaceListView
@classmethod
@@ -64,15 +40,16 @@ class TestPlaceListView(ViewTestCase):
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=timezone.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
for i in range(12):
place = Place.objects.create(
name='Im a place %d' % i,
submitted_when=timezone.now(),
submitted_by=user.explorer,
location='Test %d town' % i,
latitude=50.5 + i/10,
longitude=7.0 - i/10,
description='This is just a test, do not worry %d' % i
)
place.tags.add('I a tag', 'testlocation')
place.save()
@@ -84,7 +61,243 @@ class TestPlaceListView(ViewTestCase):
response = self.client.get(reverse('place_list'))
self.assertContext(response, 'mapping_config')
self.assertGlobal(response)
def test_first_places(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_list'))
for i in range(1, 4):
place = Place.objects.get(id=i)
self.assertTrue(
place.name in response.content.decode(),
msg='Expecting the %dth place name to be on the first page of list' % i
)
self.assertTrue(
place.description in response.content.decode(),
msg='Expecting the %dth place description to be on the first page of list' % i
)
def test_pagination(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_list'))
self.assertNotEqual(
None,
re.search(
"""<ul.*pagination.*>\s*(<li.*>.*</li>\s*){6,}</ul>""",
response.content.decode().replace('\n', '').lower()
),
msg='Expecting the place list to be paginated like [first] [previous] [item] at least 2 times [next] [last]'
)
class TestPlaceCreateView(ViewTestCase):
view = PlaceCreateView
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
def setUp(self):
self.client = Client()
def test_has_forms(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_create'))
self.assertHasForm(response, 'place_image_form', PlaceImageForm)
self.assertHasForm(response, 'place_form', PlaceForm)
def test_positive_no_image(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.post(
reverse('place_create'),
data={
'name': 'test place 486',
'location': 'test location',
'latitude': 45.804192,
'longitude': 1.860222,
'description': """
Cupiditate harum reprehenderit ipsam iure consequuntur eaque eos reiciendis. Blanditiis vel minima minus repudiandae voluptate aut quia sed. Provident ex omnis illo molestiae. Ullam eos et est provident enim deserunt.
"""
},
follow=True
)
self.assertHttpOK(response)
place = Place.objects.get(name='test place 486')
self.assertNotEqual(
None,
place,
msg='Submitted place not found in database / model'
),
self.assertEqual(
reverse(
'place_detail', kwargs={'pk': place.id}
),
response.redirect_chain[-1][0]
)
self.assertMessage(
response,
_('Successfully created place'),
'success',
msg='Expecting a visible success message'
)
def test_positive_image(self):
self.client.login(username='testpeter', password='Develop123')
image = open(
path.join(
settings.BASE_DIR,
'testdata',
'test_image.jpg'
),
'rb'
)
response = self.client.post(
reverse('place_create'),
data={
'name': 'test place 894',
'location': 'test location',
'latitude': 45.804192,
'longitude': 1.860222,
'description': """
Cupiditate harum reprehenderit ipsam iure consequuntur eaque eos reiciendis. Blanditiis vel minima minus repudiandae voluptate aut quia sed. Provident ex omnis illo molestiae. Ullam eos et est provident enim deserunt.
""",
'filename': [image]
},
follow=True
)
self.assertHttpOK(response)
place = Place.objects.get(name='test place 894')
self.assertNotEqual(
None,
place,
msg='Submitted place not found in database / model'
),
self.assertEqual(
reverse(
'place_detail', kwargs={'pk': place.id}
),
response.redirect_chain[-1][0]
)
self.assertEqual(
len(place.placeimages.all()),
1,
msg='Expecting the place to have exactly 1 place image'
)
self.assertMessage(
response,
_('Successfully created place'),
'success',
msg='Expecting a visible success message'
)
def test_negative_no_name(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.post(
reverse('place_create'),
{
'location': 'test location 456',
'latitude': 45.804192,
'longitude': 1.860222,
'description': """
Cupiditate harum reprehenderit ipsam iure consequuntur eaque eos reiciendis. Blanditiis vel minima minus repudiandae voluptate aut quia sed. Provident ex omnis illo molestiae. Ullam eos et est provident enim deserunt.
"""
}
)
self.assertHttpBadRequest(response)
self.assertEqual(
len(Place.objects.filter(location='test location 456')),
0,
msg='Expecting no place to be created'
)
self.assertMessage(
response,
_('Please fill in all required fields.'),
'error',
msg='Expecing a visible error message'
)
def test_negative_no_location(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.post(
reverse('place_create'),
{
'name': 'test name 376',
'latitude': 45.804192,
'longitude': 1.860222,
'description': """
Cupiditate harum reprehenderit ipsam iure consequuntur eaque eos reiciendis. Blanditiis vel minima minus repudiandae voluptate aut quia sed. Provident ex omnis illo molestiae. Ullam eos et est provident enim deserunt.
"""
}
)
self.assertHttpBadRequest(response)
self.assertEqual(
len(Place.objects.filter(name='test name 376')),
0,
msg='Expecting no place to be created'
)
self.assertMessage(
response,
_('Please fill in all required fields.'),
'error',
msg='Expecing a visible error message'
)
def test_negative_no_latitude(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.post(
reverse('place_create'),
{
'name': 'test name 417',
'location': 'location',
'longitude': 1.860222,
'description': """
Cupiditate harum reprehenderit ipsam iure consequuntur eaque eos reiciendis. Blanditiis vel minima minus repudiandae voluptate aut quia sed. Provident ex omnis illo molestiae. Ullam eos et est provident enim deserunt.
"""
}
)
self.assertHttpBadRequest(response)
self.assertEqual(
len(Place.objects.filter(name='test name 417')),
0,
msg='Expecting no place to be created'
)
self.assertMessage(
response,
_('Please fill in all required fields.'),
'error',
msg='Expecing a visible error message'
)
def test_negative_no_longitude(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.post(
reverse('place_create'),
{
'name': 'test name 417',
'location': 'location',
'latitude': 45.804192,
'description': """
Cupiditate harum reprehenderit ipsam iure consequuntur eaque eos reiciendis. Blanditiis vel minima minus repudiandae voluptate aut quia sed. Provident ex omnis illo molestiae. Ullam eos et est provident enim deserunt.
"""
}
)
self.assertHttpBadRequest(response)
self.assertEqual(
len(Place.objects.filter(name='test name 417')),
0,
msg='Expecting no place to be created'
)
self.assertMessage(
response,
_('Please fill in all required fields.'),
'error',
msg='Expecing a visible error message'
)
class PlaceDetailViewTestCase(TaggableViewTestCaseMixin, MapableViewTestCaseMixin, ViewTestCase):
view = PlaceDetailView
@@ -108,6 +321,19 @@ class PlaceDetailViewTestCase(TaggableViewTestCaseMixin, MapableViewTestCaseMixi
place.tags.add('I a tag', 'testlocation')
place.save()
def test_not_authenticated(self):
response = self.client.get(reverse('place_detail', kwargs={'pk': 1}))
self.assertHttpRedirect(response)
self.assertEqual(
'%s?next=%s' % (
reverse('login'),
reverse('place_detail', kwargs={'pk': 1})
),
response.url,
msg='Expecting unauthenticated user to be redirected to login page, using the \'next\' GET-Param to store the places details page'
)
def test_context(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_detail', kwargs={'pk': 1}))
@@ -127,3 +353,131 @@ class PlaceDetailViewTestCase(TaggableViewTestCaseMixin, MapableViewTestCaseMixi
)
)
self.assertMapableContext(response.context['mapping_config'])
def test_place_data(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_detail', kwargs={'pk': 1}))
place = Place.objects.get(id=1)
self.assertTrue(
place.name in response.content.decode(),
msg='Expecting the places name to be on the page'
)
self.assertTrue(
place.description in response.content.decode(),
msg='Expecting the places description to be on the page'
)
self.assertTrue(
str(place.latitude) in response.content.decode(),
msg='Expecting the places latitude to be on the page'
)
self.assertTrue(
str(place.longitude) in response.content.decode(),
msg='Expecting the places longitude to be on the page'
)
def test_favorite(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_detail', kwargs={'pk': 1}))
user = User.objects.get(username='testpeter')
place = Place.objects.get(id=1)
self.assertTrue(
reverse('place_favorite', kwargs={'place_id': 1}) in response.content.decode(),
msg='Expecting the (right) create favorite url to be on the page '
)
response = self.client.get(
reverse('place_favorite', kwargs={'place_id': 1}),
follow=True
)
self.assertHttpOK(response)
self.assertTrue(
reverse('place_unfavorite', kwargs={'place_id': 1}) in response.content.decode(),
msg='Expecting the (right) delete favorite url to be on the page '
)
self.assertTrue(
place in user.explorer.favorite_places.all(),
msg='Expecting the place to be in the explorers favorites'
)
self.assertTrue(
user.explorer in place.explorer_favorites.all(),
msg='Expecting the explorere to be in the reverse list of favorites'
)
response = self.client.get(
reverse('place_unfavorite', kwargs={'place_id': 1}),
follow=True
)
self.assertHttpOK(response)
self.assertTrue(
reverse('place_favorite', kwargs={'place_id': 1}) in response.content.decode(),
msg='Expecting the (right) create favorite url to be on the page after unfavorite'
)
self.assertTrue(
place not in user.explorer.favorite_places.all(),
msg='Expecting the place to not be in the explorers favorites after unfavorite'
)
self.assertTrue(
user.explorer not in place.explorer_favorites.all(),
msg='Expecting the explorere to not be in the reverse list of favorites after unfavorite'
)
def test_visit(self):
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('place_detail', kwargs={'pk': 1}))
user = User.objects.get(username='testpeter')
place = Place.objects.get(id=1)
self.assertTrue(
reverse('place_visit_create', kwargs={'place_id': 1}) in response.content.decode(),
msg='Expecting the (right) create visit url to be on the page '
)
response = self.client.get(
reverse('place_visit_create', kwargs={'place_id': 1}),
follow=True
)
self.assertHttpOK(response)
self.assertTrue(
reverse('place_visit_delete', kwargs={'place_id': 1}) in response.content.decode(),
msg='Expecting the (right) delete visist url to be on the page '
)
self.assertTrue(
place in user.explorer.visited_places.all(),
msg='Expecting the place to be in the explorers visits'
)
self.assertTrue(
user.explorer in place.explorer_visits.all(),
msg='Expecting the explorer to be in the reverse list of visits'
)
response = self.client.get(
reverse('place_visit_delete', kwargs={'place_id': 1}),
follow=True
)
self.assertHttpOK(response)
self.assertTrue(
reverse('place_visit_create', kwargs={'place_id': 1}) in response.content.decode(),
msg='Expecting the (right) create favorite url to be on the page after deleting visit'
)
self.assertTrue(
place not in user.explorer.visited_places.all(),
msg='Expecting the place to not be in the explorers visits after deleting visit'
)
self.assertTrue(
user.explorer not in place.explorer_visits.all(),
msg='Expecting the explorer to not be in the reverse list of visits after deleting visit'
)

View File

@@ -0,0 +1,112 @@
import re
from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from django.utils import timezone
from lostplaces.models import Place
from lostplaces.tests.views import (
ViewTestCase,
GlobalTemplateTestCaseMixin
)
class TestHomeView(GlobalTemplateTestCaseMixin, ViewTestCase):
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(
username='testpeter',
password='Develop123'
)
place = Place.objects.create(
name='Im a place',
submitted_when=timezone.now(),
submitted_by=user.explorer,
location='Testtown',
latitude=50.5,
longitude=7.0,
description='This is just a test, do not worry'
)
place.tags.add('I a tag', 'testlocation')
place.save()
def setUp(self):
self.client = Client()
def test_global(self):
response = self.client.get(reverse('lostplaces_home'))
self.assertGlobal(response)
def test_place_list_authenticated(self):
"""
Testing there is the place list containing the name,
location and description of the latest place for
authenticated users.
"""
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('lostplaces_home'))
self.assertNotEqual(
None,
re.search(
"""Im a place.*Testtown.*This is just a test, do not worry""",
response.content.decode().replace('\n', '')
),
msg='Expecting the test place to show up on the homepage'
)
def test_place_list_unauthenticated(self):
"""
Testing there is a place list of the lates places
containing the place names only for unauthenticated users.
"""
response = self.client.get(reverse('lostplaces_home'))
self.assertNotEqual(
None,
re.search(
"""Im a place""",
response.content.decode().replace('\n', '')
),
msg='Expecting the test place to show up on the homepage'
)
self.assertEqual(
None,
re.search(
"""Testtown.*This is just a test, do not worry""",
response.content.decode().replace('\n', '')
),
msg='Expecting the test place to show up on the homepage'
)
def test_map_authenticated(self):
"""
Testing there is a map showing all the lates places
on a map for authenticated users.
"""
self.client.login(username='testpeter', password='Develop123')
response = self.client.get(reverse('lostplaces_home'))
self.assertNotEqual(
None,
re.search(
"""map.*7.0,.*50.5.*Im a place""",
response.content.decode().replace('\n', '')
),
msg='Expecting the test place to show up on the map'
)
def test_map_unauthenticated(self):
"""
Testing there is no map for unauthenticated users.
"""
response = self.client.get(reverse('lostplaces_home'))
self.assertEqual(
None,
re.search(
"""7.0,.*50.5.*Im a place""",
response.content.decode().replace('\n', '')
),
msg='Expecting the test place to show up on the map'
)

View File

@@ -61,6 +61,9 @@ class IsPlaceSubmitterMixin(UserPassesTestMixin, View):
return False
class PlaceAssetCreateView(IsAuthenticatedMixin, SuccessMessageMixin, CreateView):
"""
Abstract View for creating a place asset (i.e. PlaceImage)
"""
model = None
template_name = ''
success_message = ''

View File

@@ -56,7 +56,6 @@ class ExplorerProfileUpdateView(IsAuthenticatedMixin, View):
return render(request, 'explorer/profile_update.html', context)
def post(self, request, *args, **kwargs):
print(request.POST)
explorer_user_change_form = ExplorerUserChangeForm(
request.POST,
instance=request.user
@@ -71,8 +70,6 @@ class ExplorerProfileUpdateView(IsAuthenticatedMixin, View):
explorer_user_change_form.save()
explorer_change_form.save()
print(explorer_change_form.cleaned_data)
messages.success(
self.request,
_('Successfully updated Explorer profile')

View File

@@ -50,7 +50,7 @@ class PlaceDetailView(IsAuthenticatedMixin, View):
'all_tags': Tag.objects.all(),
'submit_form': TagSubmitForm(),
'tagged_item': place,
'submit_url_name': 'place_tag_submit',
'submit_url': reverse('place_tag_submit', kwargs={'tagged_id': place.id}),
'delete_url_name': 'place_tag_delete'
}
}
@@ -111,7 +111,8 @@ class PlaceCreateView(MultiplePlaceImageUploadMixin, IsAuthenticatedMixin, View)
context={
'place_form': place_form,
'place_image_form': PlaceImageForm()
}
},
status=400
)
class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView):

View File

@@ -0,0 +1,5 @@
from django import forms
class SelectContent(forms.Select):
template_name = 'widgets/select_content.html'

View File

@@ -8,7 +8,7 @@ with open('../Readme.md') as f:
setup(
name='django-lostplaces',
version='0.1.2 HotFix',
version='0.1.3',
description='A django app to manage lost places',
author='Reverend',
author_email='reverend@reverend2048.de',

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB