33 Commits

Author SHA1 Message Date
a22c988e94 Added visited_places attribute to Explorer. 2020-12-25 19:36:11 +01:00
7f2283325c gory migration fuckery (rename) 2020-12-25 19:35:35 +01:00
6b7c71ef30 Addid visited_places system. (mostly copy&paste) :P 2020-12-25 19:32:54 +01:00
067bf36118 SVG paths updated. 2020-12-25 19:20:44 +01:00
9eef044af9 Renamed favorite* svgs. 2020-12-25 19:19:01 +01:00
a4780a22f2 Changed urlpattern tree. 2020-12-25 18:17:05 +01:00
0d1d829abe Regrouped views. 2020-12-25 17:56:17 +01:00
59cfa82ce9 Resorted and -grouped urls. 2020-12-25 17:54:15 +01:00
d47c85795c FU migrations! 2020-12-25 17:33:45 +01:00
8e80614eee Merge commit 'c5f6355f193df939ebb1b158be6b4dc2ba425a60' into develop 2020-12-25 16:51:49 +01:00
6a1e2d975b New Icon 2020-12-25 16:24:28 +01:00
c5f6355f19 Updated translations (de). 2020-12-25 16:07:50 +01:00
dac63e99ba Added Edit button to profile page. 2020-12-25 16:00:29 +01:00
9f369456d5 Changed easy_thumbnails image/thumb deletion. Now working. 2020-12-25 15:42:02 +01:00
011a58f6b3 Use thumbnail in profile_update. 2020-12-25 14:29:38 +01:00
67ce6cb50b Added working explorer_profile_image upload. 2020-12-25 14:06:53 +01:00
5df7cc5ec6 #46 Large Map 2020-12-25 13:29:34 +01:00
e242dc4add Partial takes parameter to change size of map 2020-12-25 13:29:18 +01:00
86cc7f23fe description_fuckery. 2020-12-25 13:19:34 +01:00
f73fa616d0 Minor reordering 2020-12-25 13:05:59 +01:00
629a609ff5 Forgott imports for #45 2020-12-25 13:00:30 +01:00
04fe93c7bb #45 Redirect after asset deletion 2020-12-25 12:57:05 +01:00
3eaa186b66 Delete profile_image on user_deletion. 2020-12-25 12:53:52 +01:00
b42be489dc #44 Text in place teaser is cut of 2020-12-25 12:39:13 +01:00
cc59254ba4 Added clean_username function to validate form. 2020-12-25 12:24:09 +01:00
67a6517716 Comment improved. 2020-12-25 11:14:54 +01:00
0f5474c2d3 half-working :P 2020-12-25 11:14:21 +01:00
17e71b71d4 Fix typo. 2020-12-25 08:04:35 +01:00
b1aa4473e9 Added failsafe, if there is no profile_image. 2020-12-25 02:11:02 +01:00
871acd1dce Improved class comment. 2020-12-25 01:41:09 +01:00
14ca45d111 Comments for customizations of UserChangeForm. 2020-12-25 01:36:14 +01:00
dc79b9d05c #43 Lat/Long Check when place is submitted 2020-12-24 19:47:17 +01:00
b845cc054a Small Tweaks 2020-12-24 19:25:37 +01:00
31 changed files with 580 additions and 118 deletions

View File

@@ -6,6 +6,9 @@ The software is currently in early development status, neither scope, datamodel(
We value privacy as a whole, all resources the frontend requires will be shipped with lostplace's distribution. We also try to minimize the use of JavaScript as far as we can and try to offer JS-less alternatives where we can. We value privacy as a whole, all resources the frontend requires will be shipped with lostplace's distribution. We also try to minimize the use of JavaScript as far as we can and try to offer JS-less alternatives where we can.
## Contact
If you run into any issues, have any questions or If you are interested in this project in general, feel free to get in touch with us via [reverend@reverend2048.de](mailto:reverend@reverend2048.de), we do speak English and German.
## Features ## Features
- Manage lost places with lots of useful information. - Manage lost places with lots of useful information.
- OSM-Maps - OSM-Maps
@@ -145,8 +148,4 @@ Before making the django instance public, you should tweak the config `settings.
4. Set a new (random) SECRET_KEY in settings.py, e. g.: `base64 /dev/urandom | head -c50` 4. Set a new (random) SECRET_KEY in settings.py, e. g.: `base64 /dev/urandom | head -c50`
Run `django_lostplaces/manage.py collectstatic` you should be ready to go. Run `django_lostplaces/manage.py collectstatic` you should be ready to go.
### Contact
If you run into any issues, have any questions or If you are interested in this project in general, feel free to get in touch with us via [reverend@reverend2048.de](mailto:reverend@reverend2048.de), we do speak English and German.

View File

@@ -1,3 +1,5 @@
from django.shortcuts import redirect
def get_all_subclasses(cls): def get_all_subclasses(cls):
''' '''
Gets all subclasses recursively, does not contain Gets all subclasses recursively, does not contain
@@ -8,4 +10,16 @@ def get_all_subclasses(cls):
if not subclass._meta.abstract: if not subclass._meta.abstract:
subclass_list.append(subclass) subclass_list.append(subclass)
subclass_list += get_all_subclasses(subclass) subclass_list += get_all_subclasses(subclass)
return subclass_list return subclass_list
def redirect_referer_or(request, url='/'):
'''
Returns a django redirect to the requests referer,
if there is no referer the redirect will poin to the given url
Default url is /
'''
referer = request.META.get('HTTP_REFERER')
if referer is not None:
return redirect(referer)
else:
return redirect(url)

View File

@@ -39,13 +39,23 @@ class ExplorerUserChangeForm(UserChangeForm):
class Meta: class Meta:
model = User model = User
fields = [ 'username', 'first_name', 'last_name', 'email' ] fields = [ 'username', 'first_name', 'last_name', 'email' ]
''' Hide password hint.'''
password = None password = None
''' Display username, but display it non-editable and not required. '''
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.fields['username'].required = False self.fields['username'].required = False
self.fields['username'].help_text = None self.fields['username'].help_text = None
self.fields['username'].widget.attrs['disabled'] = 'disabled' self.fields['username'].widget.attrs['disabled'] = 'disabled'
def clean_username(self):
# As shown in the above answer.
instance = getattr(self, 'instance', None)
if instance:
return instance.username
else:
return self.cleaned_data.get('username', None)
class ExplorerChangeForm(forms.ModelForm): class ExplorerChangeForm(forms.ModelForm):
class Meta: class Meta:
@@ -57,7 +67,15 @@ class PlaceForm(forms.ModelForm):
class Meta: class Meta:
model = Place model = Place
fields = '__all__' fields = '__all__'
exclude = ['submitted_by'] exclude = ['submitted_by', 'latitude', 'longitute']
latitude = forms.IntegerField(
widget=forms.NumberInput(attrs={'min':-90,'max': 90,'type': 'number'})
)
longitude = forms.IntegerField(
widget=forms.NumberInput(attrs={'min':-180,'max': 180,'type': 'number'})
)
class PlaceImageForm(forms.ModelForm): class PlaceImageForm(forms.ModelForm):
class Meta: class Meta:

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n" "Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-12-25 01:22+0100\n" "POT-Creation-Date: 2020-12-25 16:04+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Commander1024 <commander@commander1024.de>\n" "Last-Translator: Commander1024 <commander@commander1024.de>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -74,21 +74,21 @@ msgstr "Adresse (URL)"
msgid "link text" msgid "link text"
msgstr "Linktext" msgstr "Linktext"
#: models/models.py:46 #: models/models.py:47
msgid "Biography / Description" msgid "Biography"
msgstr "Beschreibung" msgstr "Beschreibung"
#: models/models.py:47 #: models/models.py:48
msgid "Describe yourself, your preferences, etc. in a few sentences." msgid "Describe yourself, your preferences, etc. in a few sentences."
msgstr "Beschreibe Dich selbst, Deine Vorlieben, usw. in ein paar Sätzen." msgstr "Beschreibe Dich selbst, Deine Vorlieben, usw. in ein paar Sätzen."
#: models/models.py:55 #: models/models.py:56
msgid "Profile image" msgid "Profile image"
msgstr "Profilbild" msgstr "Profilbild"
#: models/models.py:56 #: models/models.py:57
msgid "Optional profile image for display in Explorer profile" msgid "Optional profile image for display in Explorer profile"
msgstr "Optionales Profilbind zur Anzeige im Explorerprofil" msgstr "Optionales Profilbild zur Anzeige im Explorerprofil"
#: models/place.py:21 #: models/place.py:21
msgid "Location" msgid "Location"
@@ -144,19 +144,25 @@ msgstr "Alle Places"
msgid "Place assets" msgid "Place assets"
msgstr "" msgstr ""
#: templates/explorer/profile.html:82 #: templates/explorer/profile.html:76
msgid "Favorite places" #, fuzzy
msgstr "Favoriten-Places" #| msgid "Edit Explorer profile"
msgid "Edit Profile"
msgstr "Explorerprofil bearbeiten"
#: templates/explorer/profile.html:98 #: templates/explorer/profile.html:87
msgid "Favorite places"
msgstr "Favoriten"
#: templates/explorer/profile.html:103
msgid "Places submitted by" msgid "Places submitted by"
msgstr "Places hinzugefügt von" msgstr "Places hinzugefügt von"
#: templates/explorer/profile.html:113 #: templates/explorer/profile.html:118
msgid "Images submitted by" msgid "Images submitted by"
msgstr "Bilder hinzugefügt von" msgstr "Bilder hinzugefügt von"
#: templates/explorer/profile.html:135 #: templates/explorer/profile.html:140
msgid "Photo albums submitted by" msgid "Photo albums submitted by"
msgstr "Fotoalben hinzugefügt von" msgstr "Fotoalben hinzugefügt von"
@@ -176,7 +182,7 @@ msgstr "Ausloggen"
#: templates/global.html:33 #: templates/global.html:33
msgid "Profile" msgid "Profile"
msgstr "" msgstr "Profil"
#: templates/global.html:35 #: templates/global.html:35
msgid "Admin" msgid "Admin"
@@ -402,6 +408,16 @@ msgstr "Noch kein Konto?"
msgid "Please login to proceed" msgid "Please login to proceed"
msgstr "Bitte log Dich ein um fortzufahren" msgstr "Bitte log Dich ein um fortzufahren"
#: views/explorer_views.py:78
#, fuzzy
#| msgid "Successfully updated place"
msgid "Successfully updated Explorer profile"
msgstr "Place erfolgreich aktualisiert"
#: views/explorer_views.py:84 views/place_views.py:105
msgid "Please fill in all required fields."
msgstr "Bitte füll alle benötigten Felder aus."
#: views/place_image_views.py:26 #: views/place_image_views.py:26
msgid "Image(s) submitted successfully" msgid "Image(s) submitted successfully"
msgstr "Bild(er) erfolgreich hinzugefügt" msgstr "Bild(er) erfolgreich hinzugefügt"
@@ -426,10 +442,6 @@ msgstr "Du darfst diesen Place nicht bearbeiten"
msgid "Successfully created place" msgid "Successfully created place"
msgstr "Place erfolgreich erstellt" msgstr "Place erfolgreich erstellt"
#: views/place_views.py:105
msgid "Please fill in all required fields."
msgstr "Bitte füll alle benötigten Felder aus."
#: views/place_views.py:112 #: views/place_views.py:112
msgid "Successfully deleted place" msgid "Successfully deleted place"
msgstr "Place erfolgreich gelöscht" msgstr "Place erfolgreich gelöscht"

View File

@@ -65,7 +65,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)), ('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
('description', models.TextField(blank=True)), ('description', models.TextField(blank=True)),
('filename', easy_thumbnails.fields.ThumbnailerImageField(upload_to=lostplaces.models.place.generate_image_upload_path)), ('filename', easy_thumbnails.fields.ThumbnailerImageField(upload_to=lostplaces.models.place.generate_place_image_filename)),
('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='placeimages', to='lostplaces.place')), ('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='placeimages', to='lostplaces.place')),
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer')), ('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer')),
], ],

View File

@@ -1,22 +0,0 @@
# Generated by Django 3.1.1 on 2020-10-04 19:37
# Edited by reverend
import datetime
from django.db import migrations, models
import django.utils.timezone
from django.utils.timezone import utc
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0001_initial'),
]
operations = [
migrations.DeleteModel(
name='Voucher'
),
migrations.DeleteModel(
name='Expireable'
)
]

View File

@@ -0,0 +1,118 @@
# Generated by Django 3.1.4 on 2020-12-25 16:02
import django.core.validators
from django.db import migrations, models
import django.db.models.deletion
import easy_thumbnails.fields
from lostplaces.models.models import generate_profile_image_filename
from lostplaces.models.place import generate_place_image_filename
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0003_voucher'),
]
operations = [
migrations.AddField(
model_name='explorer',
name='bio',
field=models.TextField(blank=True, help_text='Describe yourself, your preferences, etc. in a few sentences.', null=True, verbose_name='Biography / Description'),
),
# migrations.AddField(
# model_name='explorer',
# name='favorite_places',
# field=models.ManyToManyField(blank=True, related_name='explorer_favorites', to='lostplaces.Place', verbose_name='Explorers favorite places'),
# ),
migrations.AddField(
model_name='explorer',
name='profile_image',
field=easy_thumbnails.fields.ThumbnailerImageField(blank=True, help_text='Optional profile image for display in Explorer profile', null=True, upload_to=generate_profile_image_filename, verbose_name='Profile image'),
),
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=generate_place_image_filename, 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

@@ -0,0 +1,18 @@
# Generated by Django 3.1.4 on 2020-12-25 18:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0004_auto_20201225_1702'),
]
operations = [
migrations.AddField(
model_name='explorer',
name='visited_places',
field=models.ManyToManyField(blank=True, related_name='explorer_visits', to='lostplaces.Place', verbose_name='Explorers visited places'),
),
]

View File

@@ -11,7 +11,7 @@ import uuid
from django.db import models from django.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db.models.signals import post_save from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -31,8 +31,9 @@ def generate_profile_image_filename(instance, filename):
class Explorer(models.Model): class Explorer(models.Model):
""" """
Profile that is linked to the a User. Profile that is linked to the Django user.
Every user has a profile. Every user has a profile.
Provides additional attributes for user profile.
""" """
user = models.OneToOneField( user = models.OneToOneField(
@@ -57,14 +58,20 @@ class Explorer(models.Model):
) )
favorite_places = models.ManyToManyField( favorite_places = models.ManyToManyField(
Place, Place,
related_name='favorite_places', related_name='explorer_favorites',
verbose_name='Explorers favorite places', verbose_name='Explorers favorite places',
blank=True blank=True
) )
visited_places = models.ManyToManyField(
Place,
related_name='explorer_visits',
verbose_name='Explorers visited places',
blank=True
)
def __str__(self): def __str__(self):
return self.user.username return self.user.username
@receiver(post_save, sender=User) @receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs): def create_user_profile(sender, instance, created, **kwargs):
if created: if created:
@@ -74,6 +81,25 @@ def create_user_profile(sender, instance, created, **kwargs):
def save_user_profile(sender, instance, **kwargs): def save_user_profile(sender, instance, **kwargs):
instance.explorer.save() instance.explorer.save()
@receiver(pre_save, sender=Explorer)
def auto_delete_file_on_change(sender, instance, **kwargs):
"""
Deletes old file from filesystem
when corresponding `Explorer` object is updated
with new file.
"""
if not instance.pk:
return False
try:
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)
class Voucher(Expireable): class Voucher(Expireable):
""" """
Vouchers are authorization tokens to allow the registration of new users. Vouchers are authorization tokens to allow the registration of new users.

View File

@@ -72,7 +72,7 @@ class PlaceAsset(Submittable):
null=True null=True
) )
class PlaceImage (PlaceAsset): class PlaceImage(PlaceAsset):
""" """
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 THUMBNAIL_ALIASES. Intermediate image sizes are generated as defined in THUMBNAIL_ALIASES.
@@ -104,7 +104,6 @@ class PlaceImage (PlaceAsset):
return 'Image ' + str(self.pk) return 'Image ' + 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(post_delete, sender=PlaceImage) @receiver(post_delete, sender=PlaceImage)
@@ -118,7 +117,6 @@ def auto_delete_file_on_delete(sender, instance, **kwargs):
thumbmanager = get_thumbnailer(instance.filename) thumbmanager = get_thumbnailer(instance.filename)
thumbmanager.delete(save=False) thumbmanager.delete(save=False)
@receiver(pre_save, sender=PlaceImage) @receiver(pre_save, sender=PlaceImage)
def auto_delete_file_on_change(sender, instance, **kwargs): def auto_delete_file_on_change(sender, instance, **kwargs):
""" """
@@ -137,5 +135,4 @@ def auto_delete_file_on_change(sender, instance, **kwargs):
# No need to delete thumbnails, as they will be overwritten on regeneration. # No need to delete thumbnails, as they will be overwritten on regeneration.
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): old_file.delete(save=False)
os.remove(old_file.path)

View File

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -13,7 +13,7 @@
viewBox="0 0 512.07 512.07" viewBox="0 0 512.07 512.07"
width="512" width="512"
version="1.1" version="1.1"
sodipodi:docname="favourite_filled.svg" sodipodi:docname="favorite_filled.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"> inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata <metadata
id="metadata11"> id="metadata11">

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 368.16 368.16" style="enable-background:new 0 0 368.16 368.16;" xml:space="preserve">
<g>
<g>
<g>
<path d="M184.08,0c-74.992,0-136,61.008-136,136c0,24.688,11.072,51.24,11.536,52.36c3.576,8.488,10.632,21.672,15.72,29.4
l93.248,141.288c3.816,5.792,9.464,9.112,15.496,9.112s11.68-3.32,15.496-9.104l93.256-141.296
c5.096-7.728,12.144-20.912,15.72-29.4c0.464-1.112,11.528-27.664,11.528-52.36C320.08,61.008,259.072,0,184.08,0z
M293.8,182.152c-3.192,7.608-9.76,19.872-14.328,26.8l-93.256,141.296c-1.84,2.792-2.424,2.792-4.264,0L88.696,208.952
c-4.568-6.928-11.136-19.2-14.328-26.808C74.232,181.816,64.08,157.376,64.08,136c0-66.168,53.832-120,120-120
c66.168,0,120,53.832,120,120C304.08,157.408,293.904,181.912,293.8,182.152z"/>
<path d="M184.08,64.008c-39.704,0-72,32.304-72,72c0,39.696,32.296,72,72,72c39.704,0,72-32.304,72-72
C256.08,96.312,223.784,64.008,184.08,64.008z M184.08,192.008c-30.872,0-56-25.12-56-56s25.128-56,56-56s56,25.12,56,56
S214.952,192.008,184.08,192.008z"/>
</g>
</g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
<g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,105 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="Capa_1"
x="0px"
y="0px"
viewBox="0 0 368.16 368.16"
style="enable-background:new 0 0 368.16 368.16;"
xml:space="preserve"
sodipodi:docname="pin_filled.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"><metadata
id="metadata47"><rdf:RDF><cc:Work
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
id="defs45" /><sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1366"
inkscape:window-height="712"
id="namedview43"
showgrid="false"
inkscape:zoom="1.4803346"
inkscape:cx="184.08"
inkscape:cy="181.37791"
inkscape:window-x="0"
inkscape:window-y="28"
inkscape:window-maximized="1"
inkscape:current-layer="Capa_1" />
<g
id="g10">
<g
id="g8">
<g
id="g6">
<path
d="M184.08,0c-74.992,0-136,61.008-136,136c0,24.688,11.072,51.24,11.536,52.36c3.576,8.488,10.632,21.672,15.72,29.4 l93.248,141.288c3.816,5.792,9.464,9.112,15.496,9.112s11.68-3.32,15.496-9.104l93.256-141.296 c5.096-7.728,12.144-20.912,15.72-29.4c0.464-1.112,11.528-27.664,11.528-52.36C320.08,61.008,259.072,0,184.08,0z M293.8,182.152c-3.192,7.608-9.76,19.872-14.328,26.8l-93.256,141.296c-1.84,2.792-2.424,2.792-4.264,0L88.696,208.952 c-4.568-6.928-11.136-19.2-14.328-26.808C74.232,181.816,64.08,157.376,64.08,136c0-66.168,53.832-120,120-120 c66.168,0,120,53.832,120,120C304.08,157.408,293.904,181.912,293.8,182.152z"
id="path2" />
<path
d="M184.08,64.008c-39.704,0-72,32.304-72,72c0,39.696,32.296,72,72,72c39.704,0,72-32.304,72-72 C256.08,96.312,223.784,64.008,184.08,64.008z M184.08,192.008c-30.872,0-56-25.12-56-56s25.128-56,56-56s56,25.12,56,56 S214.952,192.008,184.08,192.008z"
id="path4" />
</g>
</g>
</g>
<g
id="g12">
</g>
<g
id="g14">
</g>
<g
id="g16">
</g>
<g
id="g18">
</g>
<g
id="g20">
</g>
<g
id="g22">
</g>
<g
id="g24">
</g>
<g
id="g26">
</g>
<g
id="g28">
</g>
<g
id="g30">
</g>
<g
id="g32">
</g>
<g
id="g34">
</g>
<g
id="g36">
</g>
<g
id="g38">
</g>
<g
id="g40">
</g>
<path
style="fill:#d40000;stroke-width:0.675523"
d="M 183.2356,15.407728 C 148.115,15.680007 113.56046,32.165752 91.281357,59.335191 67.968201,87.080284 57.903075,125.97636 67.012946,161.30636 c 5.002813,21.56622 16.217838,40.96402 28.671518,59.02158 29.047926,44.21623 57.936976,88.55418 87.673836,132.30559 2.75528,0.71398 3.44582,-3.87416 5.23173,-5.36255 32.63958,-48.91094 65.16056,-97.91511 96.89098,-147.42174 14.94799,-26.09698 23.38967,-57.3347 16.79888,-87.25041 C 297.41258,88.732147 285.50707,66.159988 267.48079,49.622901 254.86863,36.299556 238.35251,27.47624 221.24564,21.334387 209.00763,17.320382 196.11719,15.285641 183.2356,15.407728 Z m 2.03448,49.555941 c 27.46439,-0.566602 54.10132,17.912787 64.54543,43.490751 4.10895,9.11958 5.7106,19.04018 5.10583,29.01713 0.83931,19.32103 -8.79389,38.15287 -22.74612,51.10133 -14.02478,12.97799 -33.27348,19.77398 -52.19585,18.33769 -29.18994,-0.56334 -56.21632,-22.71956 -64.31454,-50.57715 -3.46488,-10.42859 -2.56691,-21.58508 -1.94784,-32.37905 3.96475,-21.34187 17.606,-41.232363 37.2523,-51.078299 10.71386,-5.480174 22.38724,-8.587404 34.30079,-7.912402 z"
id="path91" /></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -923,7 +923,8 @@ body {
justify-content: space-between; justify-content: space-between;
align-items: flex-start; align-items: flex-start;
gap: unset; } gap: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Headline, .LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Paragraph { .LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Headline,
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Paragraph {
font-size: unset; } font-size: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Info .LP-Headline { .LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Info .LP-Headline {
font-size: 28px; } font-size: 28px; }
@@ -941,7 +942,12 @@ body {
overflow: hidden; overflow: hidden;
order: unset; } order: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description .LP-Paragraph { .LP-PlaceTeaser--extended .LP-PlaceTeaser__Description .LP-Paragraph {
font-size: unset; } font-size: unset;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
overflow: hidden;
text-overflow: ellipsis; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Image { .LP-PlaceTeaser--extended .LP-PlaceTeaser__Image {
height: 165px; height: 165px;
width: 280px; width: 280px;
@@ -1695,6 +1701,11 @@ body {
.LP-Map { .LP-Map {
margin-bottom: 25px; } margin-bottom: 25px; }
.LP-Map--wide {
height: 300px; }
.LP-Map--full {
height: 100%;
width: 100%; }
.LP-Map .ol-attribution { .LP-Map .ol-attribution {
font-family: "Montserrat", Helvetica, sans-serif; font-family: "Montserrat", Helvetica, sans-serif;
color: #565656; } color: #565656; }

View File

@@ -71,6 +71,11 @@
<span class="LP-Paragraph">{{asset_count}}</span> <span class="LP-Paragraph">{{asset_count}}</span>
</td> </td>
</tr> </tr>
<tr>
<td>
<a href="/explorer/update/"><button class="LP-Button LP-Button">{% trans 'Edit Profile' %}</button></a>
</td>
</tr>
</table> </table>
</div> </div>
</div> </div>
@@ -87,9 +92,21 @@
</li> </li>
{% endfor %} {% endfor %}
</ul> </ul>
{% include 'partials/nav/pagination.html' %} {% 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> </div>
</section> </section>

View File

@@ -1,13 +1,13 @@
{% extends 'global.html'%} {% extends 'global.html'%}
{% load static %}
{% load i18n %} {% load i18n %}
{% load thumbnail %}
{% load widget_tweaks %} {% load widget_tweaks %}
# {% block title %}{% trans 'Edit Explorer profile' %}{% endblock %} # {% block title %}{% trans 'Edit Explorer profile' %}{% endblock %}
{% block maincontent %} {% block maincontent %}
<form class="LP-Form" method="POST"> <form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset"> <fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Edit Explorer profile' %}</legend> <legend class="LP-Form__Legend">{% trans 'Edit Explorer profile' %}</legend>
{% csrf_token %} {% csrf_token %}
@@ -35,9 +35,9 @@
</div> </div>
<div class="LP-Form__Composition"> <div class="LP-Form__Composition">
{% if explorer_image_url %} {% if explorer_image %}
<div class="LP-Form__Field"> <div class="LP-Form__Field">
<img class="LP-Form__Field LP-Image" src="{{ explorer_image_url }}"/> <img src="{% thumbnail explorer_image 200x200 %}"/>
</div> </div>
{% endif %} {% endif %}
<div class="LP-Form__Field"> <div class="LP-Form__Field">

View File

@@ -30,7 +30,7 @@
{% if user.is_authenticated %} {% if user.is_authenticated %}
Hi {{ user.username }}! 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 '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 'explorer_profile' explorer_id=user.pk%}"><span class="LP-Link__Text">{% trans 'Profile' %}</span></a>
{% if user.is_superuser %} {% 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">{% trans 'Admin' %}</span></a>
{% endif %} {% endif %}
@@ -50,7 +50,7 @@
<ul class="LP-Menu__List"> <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 '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 '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>
{% block additional_menu_items %} {% block additional_menu_items %}
{% endblock additional_menu_items %} {% endblock additional_menu_items %}

View File

@@ -15,7 +15,7 @@
<article class="LP-TextSection"> <article class="LP-TextSection">
</article> </article>
{% include 'partials/osm_map.html' with config=mapping_config %} {% include 'partials/osm_map.html' with config=mapping_config modifier='wide' %}
<div class="LP-PlaceGrid"> <div class="LP-PlaceGrid">
<h1 class="LP-Headline LP-Headline">{% trans 'Explore the latest places' %}</h1> <h1 class="LP-Headline LP-Headline">{% trans 'Explore the latest places' %}</h1>
<ul class="LP-PlaceGrid__Grid"> <ul class="LP-PlaceGrid__Grid">

View File

@@ -0,0 +1,16 @@
{% extends 'global.html'%}
{% load static %}
{% load i18n %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
# {% block title %}{% trans 'Map' %}{% endblock %}
{% block maincontent %}
{% include 'partials/osm_map.html' with config=mapping_config modifier='full' %}
{% endblock maincontent %}

View File

@@ -4,11 +4,11 @@
{% if request.user %} {% if request.user %}
{% if place in request.user.explorer.favorite_places.all %} {% if place in request.user.explorer.favorite_places.all %}
<a href="{% url 'place_unfavorite' place_id=place.id %}" class="LP-Link" title="{% trans 'Remove from favorites' %}"> <a href="{% url 'place_unfavorite' place_id=place.id %}" class="LP-Link" title="{% trans 'Remove from favorites' %}">
<img class="LP-Icon" src="{% static '/icons/favourite_filled.svg' %}" /> <img class="LP-Icon" src="{% static '/icons/favorite_filled.svg' %}" />
</a> </a>
{%else%} {%else%}
<a href="{% url 'place_favorite' place_id=place.id %}" class="LP-Link" title="{% trans 'Save as favorite' %}"> <a href="{% url 'place_favorite' place_id=place.id %}" class="LP-Link" title="{% trans 'Save as favorite' %}">
<img class="LP-Icon" src="{% static '/icons/favourite.svg' %}" /> <img class="LP-Icon" src="{% static '/icons/favorite.svg' %}" />
</a> </a>
{% endif %} {% endif %}
{% endif %} {% endif %}

View File

@@ -0,0 +1,14 @@
{%load static %}
{% load i18n %}
{% if request.user %}
{% if place in request.user.explorer.visited_places.all %}
<a href="{% url 'place_visit_delete' place_id=place.id %}" class="LP-Link" title="{% trans 'Remove from visits' %}">
<img class="LP-Icon" src="{% static '/icons/pin_filled.svg' %}" />
</a>
{%else%}
<a href="{% url 'place_visit_create' place_id=place.id %}" class="LP-Link" title="{% trans 'Save as visited' %}">
<img class="LP-Icon" src="{% static '/icons/pin.svg' %}" />
</a>
{% endif %}
{% endif %}

View File

@@ -1,5 +1,5 @@
{% load static %} {% load static %}
<div tabindex="1" id="map" class="LP-Map map" style="height: 300px"></div> <div tabindex="1" id="map" class="LP-Map {% if modifier %}LP-Map--{{modifier}}{% endif %} map"></div>
<div id="info" class="map-popup LP-Map__Popup"></div> <div id="info" class="map-popup LP-Map__Popup"></div>
<script type="text/javascript"> <script type="text/javascript">

View File

@@ -31,7 +31,7 @@
<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">{% include 'partials/icons/place_favorite.html' with place=place%}</li> <li class="LP-Icon__Item">{% include 'partials/icons/place_favorite.html' with place=place%}</li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/location.svg' %}" /></li> <li class="LP-Icon__Item">{% include 'partials/icons/place_visited.html' with place=place%}</li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li> <li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li>
</ul> </ul>
</div> </div>

View File

@@ -23,7 +23,7 @@
<article class="LP-PlaceDetail"> <article class="LP-PlaceDetail">
<header class="LP-PlaceDetail__Header"> <header class="LP-PlaceDetail__Header">
<h1 class="LP-Headline">{{ place.name }} {% include 'partials/icons/place_favorite.html' %}</h1> <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 %} {% if place.placeimages.first.filename.hero.url %}
<figure class="LP-PlaceDetail__Image"> <figure class="LP-PlaceDetail__Image">
<img src="{{ place.placeimages.first.filename.hero.url }}" class="LP-Image" /> <img src="{{ place.placeimages.first.filename.hero.url }}" class="LP-Image" />
@@ -44,7 +44,7 @@
<section class="LP-Section"> <section class="LP-Section">
<h1 class="LP-Headline">{% trans 'Map links' %}</h1> <h1 class="LP-Headline">{% trans 'Map links' %}</h1>
{% include 'partials/osm_map.html' with config=mapping_config%} {% include 'partials/osm_map.html' with config=mapping_config modifier='wide' %}
<div class="LP-LinkList"> <div class="LP-LinkList">
<ul class="LP-LinkList__Container"> <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> <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>

View File

@@ -11,7 +11,7 @@
{% block maincontent %} {% block maincontent %}
{% include 'partials/osm_map.html' with config=mapping_config %} {% include 'partials/osm_map.html' with config=mapping_config modifier='wide' %}
<div class="LP-PlaceList"> <div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Our lost places' %}</h1> <h1 class="LP-Headline">{% trans 'Our lost places' %}</h1>
<ul class="LP-PlaceList__List"> <ul class="LP-PlaceList__List">

View File

@@ -4,6 +4,8 @@
from django.urls import path from django.urls import path
from lostplaces.views import ( from lostplaces.views import (
HomeView, HomeView,
FlatView,
OSMMapView,
PlaceDetailView, PlaceDetailView,
PlaceListView, PlaceListView,
PlaceCreateView, PlaceCreateView,
@@ -13,35 +15,39 @@ from lostplaces.views import (
PlaceTagSubmitView, PlaceTagSubmitView,
PlaceFavoriteView, PlaceFavoriteView,
PlaceUnfavoriteView, PlaceUnfavoriteView,
PhotoAlbumCreateView, PlaceVisitCreateView,
PhotoAlbumDeleteView, PlaceVisitDeleteView,
PlaceImageCreateView, PlaceImageCreateView,
PlaceImageDeleteView, PlaceImageDeleteView,
FlatView, PhotoAlbumCreateView,
PhotoAlbumDeleteView,
ExplorerProfileView, ExplorerProfileView,
ExplorerProfileUpdateView ExplorerProfileUpdateView
) )
urlpatterns = [ urlpatterns = [
path('', HomeView.as_view(), name='lostplaces_home'), path('', HomeView.as_view(), name='lostplaces_home'),
path('place/<int:pk>/', PlaceDetailView.as_view(), name='place_detail'),
path('place/create/', PlaceCreateView.as_view(), name='place_create'),
path('photo_album/create/<int:place_id>', PhotoAlbumCreateView.as_view(), name='photo_album_create'),
path('photo_album/delete/<int:pk>', PhotoAlbumDeleteView.as_view(), name='photo_album_delete'),
path('place/update/<int:pk>/', PlaceUpdateView.as_view(), name='place_edit'),
path('place/delete/<int:pk>/', PlaceDeleteView.as_view(), name='place_delete'),
path('place/', PlaceListView.as_view(), name='place_list'),
path('place_image/create/<int:place_id>', PlaceImageCreateView.as_view(), name='place_image_create'),
path('place_image/delete/<int:pk>', PlaceImageDeleteView.as_view(), name='place_image_delete'),
path('flat/<slug:slug>/', FlatView, name='flatpage'), path('flat/<slug:slug>/', FlatView, name='flatpage'),
path('osm/', OSMMapView.as_view(), name='osm'),
# POST-only URLs for tag submission
path('place/tag/<int:tagged_id>', PlaceTagSubmitView.as_view(), name='place_tag_submit'),
path('place/tag/delete/<int:tagged_id>/<int:tag_id>', PlaceTagDeleteView.as_view(), name='place_tag_delete'),
path('explorer/<int:explorer_id>/', ExplorerProfileView.as_view(), name='explorer_profile'), path('explorer/<int:explorer_id>/', ExplorerProfileView.as_view(), name='explorer_profile'),
path('explorer/update/', ExplorerProfileUpdateView.as_view(), name='explorer_profile_update'), path('explorer/update/', ExplorerProfileUpdateView.as_view(), name='explorer_profile_update'),
path('explorer/favorite/<int:place_id>/', PlaceFavoriteView.as_view(), name='place_favorite'), path('place/', PlaceListView.as_view(), name='place_list'),
path('explorer/unfavorite/<int:place_id>/', PlaceUnfavoriteView.as_view(), name='place_unfavorite') path('place/<int:pk>/', PlaceDetailView.as_view(), name='place_detail'),
path('place/create/', PlaceCreateView.as_view(), name='place_create'),
path('place/update/<int:pk>/', PlaceUpdateView.as_view(), name='place_edit'),
path('place/delete/<int:pk>/', PlaceDeleteView.as_view(), name='place_delete'),
path('place/tag/create/<int:tagged_id>/', PlaceTagSubmitView.as_view(), name='place_tag_submit'),
path('place/tag/delete/<int:tagged_id>/<int:tag_id>/', PlaceTagDeleteView.as_view(), name='place_tag_delete'),
path('place/fav/create/<int:place_id>/', PlaceFavoriteView.as_view(), name='place_favorite'),
path('place/fav/delete/<int:place_id>/', PlaceUnfavoriteView.as_view(), name='place_unfavorite'),
path('place/visit/create/<int:place_id>/', PlaceVisitCreateView.as_view(), name='place_visit_create'),
path('place/visit/delete/<int:place_id>/', PlaceVisitDeleteView.as_view(), name='place_visit_delete'),
path('place_image/create/<int:place_id>/', PlaceImageCreateView.as_view(), name='place_image_create'),
path('place_image/delete/<int:pk>/', PlaceImageDeleteView.as_view(), name='place_image_delete'),
path('photo_album/create/<int:place_id>/', PhotoAlbumCreateView.as_view(), name='photo_album_create'),
path('photo_album/delete/<int:pk>/', PhotoAlbumDeleteView.as_view(), name='photo_album_delete')
] ]

View File

@@ -10,10 +10,11 @@ from django.contrib.auth.mixins import UserPassesTestMixin, LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.shortcuts import redirect, get_object_or_404 from django.shortcuts import redirect, get_object_or_404
from django.urls import reverse_lazy from django.urls import reverse_lazy, reverse
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from lostplaces.models import Place from lostplaces.models import Place
from lostplaces.common import redirect_referer_or
class IsAuthenticatedMixin(LoginRequiredMixin, View): class IsAuthenticatedMixin(LoginRequiredMixin, View):
''' '''
@@ -108,4 +109,4 @@ class PlaceAssetDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, SingleOb
place_id = self.get_object().place.id place_id = self.get_object().place.id
self.get_object().delete() self.get_object().delete()
messages.success(self.request, self.success_message) messages.success(self.request, self.success_message)
return redirect(reverse_lazy('place_detail', kwargs={'pk': place_id})) return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place_id}))

View File

@@ -7,6 +7,7 @@ from django.utils.translation import ugettext_lazy as _
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.contrib import messages
from lostplaces.common import get_all_subclasses from lostplaces.common import get_all_subclasses
from lostplaces.views.base_views import IsAuthenticatedMixin from lostplaces.views.base_views import IsAuthenticatedMixin
@@ -17,7 +18,7 @@ from lostplaces.forms import ExplorerChangeForm, ExplorerUserChangeForm
class ExplorerProfileView(IsAuthenticatedMixin, View): class ExplorerProfileView(IsAuthenticatedMixin, View):
def get(self, request, explorer_id): def get(self, request, explorer_id):
explorer = get_object_or_404(Explorer, pk=explorer_id) explorer = get_object_or_404(Explorer, pk=explorer_id)
place_list = Place.objects.filter(submitted_by=explorer) place_list = explorer.places.all()
place_count = place_list.count() place_count = place_list.count()
context={ context={
@@ -47,8 +48,40 @@ class ExplorerProfileUpdateView(IsAuthenticatedMixin, View):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
context = { context = {
'explorer_image_url': request.user.explorer.profile_image.url,
'explorer_user_change_form': ExplorerUserChangeForm(instance=request.user), 'explorer_user_change_form': ExplorerUserChangeForm(instance=request.user),
'explorer_change_form': ExplorerChangeForm(instance=request.user.explorer) 'explorer_change_form': ExplorerChangeForm(instance=request.user.explorer)
} }
if request.user.explorer.profile_image:
context['explorer_image'] = request.user.explorer.profile_image
return render(request, 'explorer/profile_update.html', context) 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
)
explorer_change_form = ExplorerChangeForm(
request.POST,
request.FILES,
instance=request.user.explorer
)
if explorer_change_form.is_valid() and explorer_user_change_form.is_valid():
explorer_user_change_form.save()
explorer_change_form.save()
print(explorer_change_form.cleaned_data)
messages.success(
self.request,
_('Successfully updated Explorer profile')
)
else:
# Usually the browser should have checked the form before sending.
messages.error(
self.request,
_('Please fill in all required fields.')
)
return redirect(reverse_lazy('explorer_profile_update'))

View File

@@ -13,12 +13,13 @@ from django.contrib.messages.views import SuccessMessageMixin
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
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, reverse
from lostplaces.models import Place, PlaceImage from lostplaces.models import Place, PlaceImage
from lostplaces.views.base_views import IsAuthenticatedMixin, IsPlaceSubmitterMixin from lostplaces.views.base_views import IsAuthenticatedMixin, IsPlaceSubmitterMixin
from lostplaces.views.place_image_views import MultiplePlaceImageUploadMixin from lostplaces.views.place_image_views import MultiplePlaceImageUploadMixin
from lostplaces.forms import PlaceForm, PlaceImageForm, TagSubmitForm from lostplaces.forms import PlaceForm, PlaceImageForm, TagSubmitForm
from lostplaces.common import redirect_referer_or
from taggit.models import Tag from taggit.models import Tag
@@ -104,7 +105,14 @@ class PlaceCreateView(MultiplePlaceImageUploadMixin, IsAuthenticatedMixin, View)
self.request, self.request,
_('Please fill in all required fields.') _('Please fill in all required fields.')
) )
return render(request, 'place/place_create.html', context={'form': place_form}) return render(
request=request,
template_name='place/place_create.html',
context={
'place_form': place_form,
'place_image_form': PlaceImageForm()
}
)
class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView): class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView):
template_name = 'place/place_delete.html' template_name = 'place/place_delete.html'
@@ -127,14 +135,8 @@ class PlaceFavoriteView(IsAuthenticatedMixin, View):
if request.user is not None: if request.user is not None:
request.user.explorer.favorite_places.add(place) request.user.explorer.favorite_places.add(place)
request.user.explorer.save() request.user.explorer.save()
referer = request.META.get('HTTP_REFERER') return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
if referer is not None:
return redirect(referer)
else:
return redirect(
reverse_lazy('place_detail', kwargs={'pk': place.pk})
)
class PlaceUnfavoriteView(IsAuthenticatedMixin, View): class PlaceUnfavoriteView(IsAuthenticatedMixin, View):
@@ -143,11 +145,25 @@ class PlaceUnfavoriteView(IsAuthenticatedMixin, View):
if request.user is not None: if request.user is not None:
request.user.explorer.favorite_places.remove(place) request.user.explorer.favorite_places.remove(place)
request.user.explorer.save() request.user.explorer.save()
return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
class PlaceVisitCreateView(IsAuthenticatedMixin, View):
def get(self, request, place_id):
place = get_object_or_404(Place, id=place_id)
if request.user is not None:
request.user.explorer.visited_places.add(place)
request.user.explorer.save()
return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
referer = request.META.get('HTTP_REFERER') class PlaceVisitDeleteView(IsAuthenticatedMixin, View):
if referer is not None:
return redirect(referer) def get(self, request, place_id):
else: place = get_object_or_404(Place, id=place_id)
return redirect( if request.user is not None:
reverse_lazy('place_detail', kwargs={'pk': place.pk}) request.user.explorer.visited_places.remove(place)
) request.user.explorer.save()
return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))

View File

@@ -6,7 +6,7 @@ from django.views.generic.edit import CreateView
from django.contrib.messages.views import SuccessMessageMixin from django.contrib.messages.views import SuccessMessageMixin
from django.contrib import messages from django.contrib import messages
from django.urls import reverse_lazy from django.urls import reverse_lazy, reverse
from django.shortcuts import render, redirect, get_object_or_404 from django.shortcuts import render, redirect, get_object_or_404
from django.http import HttpResponseForbidden from django.http import HttpResponseForbidden
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@@ -14,6 +14,7 @@ from django.utils.translation import ugettext_lazy as _
from lostplaces.forms import SignupVoucherForm, TagSubmitForm from lostplaces.forms import SignupVoucherForm, TagSubmitForm
from lostplaces.models import Place, PhotoAlbum from lostplaces.models import Place, PhotoAlbum
from lostplaces.views.base_views import IsAuthenticatedMixin from lostplaces.views.base_views import IsAuthenticatedMixin
from lostplaces.common import redirect_referer_or
from lostplaces.views.base_views import ( from lostplaces.views.base_views import (
PlaceAssetCreateView, PlaceAssetCreateView,
@@ -79,10 +80,22 @@ class PlaceTagDeleteView(IsAuthenticatedMixin, View):
place = get_object_or_404(Place, pk=tagged_id) place = get_object_or_404(Place, pk=tagged_id)
tag = get_object_or_404(Tag, pk=tag_id) tag = get_object_or_404(Tag, pk=tag_id)
place.tags.remove(tag) place.tags.remove(tag)
return redirect(reverse_lazy('place_detail', kwargs={'pk': tagged_id}))
return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': tagged_id}))
def FlatView(request, slug): def FlatView(request, slug):
if request.LANGUAGE_CODE == 'de': if request.LANGUAGE_CODE == 'de':
return render(request, 'flat/' + slug + '-de' + '.html') return render(request, 'flat/' + slug + '-de' + '.html')
else: else:
return render(request, 'flat/' + slug + '.html') return render(request, 'flat/' + slug + '.html')
class OSMMapView(IsAuthenticatedMixin, View):
def get(self, request):
place_list = Place.objects.all()
context = {
'mapping_config': {
'all_points': place_list,
'map_center': Place.average_latlon(place_list)
}
}
return render(request, 'osm_map_full.html', context)