diff --git a/django_lostplaces/lostplaces/admin.py b/django_lostplaces/lostplaces/admin.py
index ec58dac..357df41 100644
--- a/django_lostplaces/lostplaces/admin.py
+++ b/django_lostplaces/lostplaces/admin.py
@@ -35,3 +35,4 @@ admin.site.register(Voucher, VoucherAdmin)
admin.site.register(Place, PlacesAdmin)
admin.site.register(PlaceImage, PlaceImagesAdmin)
admin.site.register(PhotoAlbum, PhotoAlbumsAdmin)
+admin.site.register(PlaceVoting)
diff --git a/django_lostplaces/lostplaces/forms.py b/django_lostplaces/lostplaces/forms.py
index 865751b..e68bef2 100644
--- a/django_lostplaces/lostplaces/forms.py
+++ b/django_lostplaces/lostplaces/forms.py
@@ -22,7 +22,7 @@ class SignupVoucherForm(UserCreationForm):
)
def is_valid(self):
- super().is_valid()
+ super_result = super().is_valid()
submitted_voucher = self.cleaned_data.get('voucher')
try:
fetched_voucher = Voucher.objects.get(code=submitted_voucher)
@@ -35,7 +35,7 @@ class SignupVoucherForm(UserCreationForm):
return False
fetched_voucher.delete()
- return True
+ return super_result
class ExplorerUserChangeForm(UserChangeForm):
class Meta:
diff --git a/django_lostplaces/lostplaces/models/place.py b/django_lostplaces/lostplaces/models/place.py
index acfcda7..2df13b4 100644
--- a/django_lostplaces/lostplaces/models/place.py
+++ b/django_lostplaces/lostplaces/models/place.py
@@ -1,4 +1,5 @@
import os
+from math import floor
from django.db import models
from django.urls import reverse
@@ -6,7 +7,7 @@ from django.dispatch import receiver
from django.db.models.signals import post_delete, pre_save
from django.utils.translation import ugettext_lazy as _
-from lostplaces.models.abstract_models import Submittable, Taggable, Mapable
+from lostplaces.models.abstract_models import Submittable, Taggable, Mapable, Expireable
from easy_thumbnails.fields import ThumbnailerImageField
from easy_thumbnails.files import get_thumbnailer
@@ -15,7 +16,7 @@ PLACE_LEVELS = (
(1, 'Ruin'),
(2, 'Vandalized'),
(3, 'Natures Treasure'),
- (4, 'Long Time no See'),
+ (4, 'Lost in History'),
(5, 'Time Capsule')
)
@@ -58,10 +59,15 @@ class Place(Submittable, Taggable, Mapable):
return reverse('place_detail', kwargs={'pk': self.pk})
def get_hero_index_in_queryset(self):
+ '''
+ Calculates the index of the hero image within
+ the list / queryset of images. Necessary for
+ the lightbox.
+ '''
for i in range(0, len(self.placeimages.all())):
image = self.placeimages.all()[i]
if image == self.hero:
- return i
+ return i
return None
@@ -84,6 +90,24 @@ class Place(Submittable, Taggable, Mapable):
return {'latitude': latitude, 'longitude': longitude}
+ def calculate_place_level(self):
+ self.remove_expired_votes()
+
+ if self.placevotings.count() == 0:
+ return 5
+
+ level = 0
+
+ for vote in self.placevotings.all():
+ level += vote.vote
+
+ self.level = floor(level / self.placevotings.count())
+
+ def remove_expired_votes(self):
+ for vote in self.placevotings.all():
+ if vote.is_expired:
+ vote.delete()
+
def __str__(self):
return self.name
@@ -104,7 +128,7 @@ class PlaceAsset(Submittable):
"""
class Meta:
- abstract = True
+ abstract = True
place = models.ForeignKey(
Place,
@@ -180,3 +204,13 @@ def auto_delete_file_on_change(sender, instance, **kwargs):
new_file = instance.filename
if not old_file == new_file:
old_file.delete(save=False)
+
+
+class PlaceVoting(PlaceAsset, Expireable):
+ vote = models.IntegerField(choices=PLACE_LEVELS)
+
+ def get_human_readable_level(self):
+ return PLACE_LEVELS[self.vote - 1][1]
+
+ def get_all_choices(self):
+ return reversed(PLACE_LEVELS)
\ No newline at end of file
diff --git a/django_lostplaces/lostplaces/templates/partials/voting.html b/django_lostplaces/lostplaces/templates/partials/voting.html
new file mode 100644
index 0000000..8c12cd2
--- /dev/null
+++ b/django_lostplaces/lostplaces/templates/partials/voting.html
@@ -0,0 +1,39 @@
+{% load i18n %}
+
+
+
+
+ Place level
+
+
+
+ {{place.get_level_display}}
+
+
+
+
+
+ You voted this place as
+ {{voting.get_human_readable_level}}
+
+
+
+ Your vote expires on
+
+
+ {{voting.expires_when|date:'d.m.Y'}}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/django_lostplaces/lostplaces/templates/place/place_detail.html b/django_lostplaces/lostplaces/templates/place/place_detail.html
index eeb77b2..f01c9f5 100644
--- a/django_lostplaces/lostplaces/templates/place/place_detail.html
+++ b/django_lostplaces/lostplaces/templates/place/place_detail.html
@@ -40,25 +40,64 @@
{{ place.description }}
-
-
- {% url 'place_tag_submit' place_id=place.id as tag_submit_url%}
- {% partial tagging %}
- {% set config=tagging_config %}
- {% endpartial %}
-
-
+
+
+ {% url 'place_tag_submit' place_id=place.id as tag_submit_url %}
+ {% partial tagging %}
+ {% set config=tagging_config %}
+ {% endpartial %}
+
+
+ {{votingplace.vote}}
+
+ {% partial voting %}
+ {% set place=place %}
+ {% set voting=placevoting %}
+ {% endpartial %}
+
+
{% translate 'Map links' %}
{% partial osm_map config=mapping_config %}
-
+
diff --git a/django_lostplaces/lostplaces/urls.py b/django_lostplaces/lostplaces/urls.py
index 35f6ce4..ca4cf5c 100644
--- a/django_lostplaces/lostplaces/urls.py
+++ b/django_lostplaces/lostplaces/urls.py
@@ -22,7 +22,8 @@ from lostplaces.views import (
PhotoAlbumCreateView,
PhotoAlbumDeleteView,
ExplorerProfileView,
- ExplorerProfileUpdateView
+ ExplorerProfileUpdateView,
+ PlaceVoteView
)
urlpatterns = [
@@ -47,6 +48,8 @@ urlpatterns = [
path('place_image/create//', PlaceImageCreateView.as_view(), name='place_image_create'),
path('place_image/delete//', PlaceImageDeleteView.as_view(), name='place_image_delete'),
+
+ path('place/vote//', PlaceVoteView.as_view(), name='place_vote'),
path('photo_album/create//', PhotoAlbumCreateView.as_view(), name='photo_album_create'),
path('photo_album/delete//', PhotoAlbumDeleteView.as_view(), name='photo_album_delete')
diff --git a/django_lostplaces/lostplaces/views/place_views.py b/django_lostplaces/lostplaces/views/place_views.py
index bb63435..71e08cb 100644
--- a/django_lostplaces/lostplaces/views/place_views.py
+++ b/django_lostplaces/lostplaces/views/place_views.py
@@ -1,5 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
+from datetime import timedelta
from django.db.models.functions import Lower
@@ -10,11 +11,17 @@ from django.views.generic.detail import SingleObjectMixin
from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.utils.translation import ugettext_lazy as _
+from django.utils import timezone
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy, reverse
-from lostplaces.models import Place, PlaceImage
+from lostplaces.models import (
+ Place,
+ PlaceImage,
+ PlaceVoting
+)
+
from lostplaces.views.base_views import (
IsAuthenticatedMixin,
IsPlaceSubmitterMixin,
@@ -46,8 +53,10 @@ class PlaceDetailView(IsAuthenticatedMixin, IsEligibleToSeePlaceMixin, View):
def get_place(self):
return get_object_or_404(Place, pk=self.kwargs['pk'])
- def get(self, request, pk):
+ def get(self, request, pk):
place = self.get_place()
+ place.calculate_place_level()
+ explorer = request.user.explorer
context = {
'place': place,
@@ -61,7 +70,8 @@ class PlaceDetailView(IsAuthenticatedMixin, IsEligibleToSeePlaceMixin, View):
'tagged_item': place,
'submit_url': reverse('place_tag_submit', kwargs={'tagged_id': place.id}),
'delete_url_name': 'place_tag_delete'
- }
+ },
+ 'placevoting': PlaceVoting.objects.filter(place=place, submitted_by=explorer).first()
}
return render(request, 'place/place_detail.html', context)
@@ -185,3 +195,32 @@ class PlaceVisitDeleteView(IsAuthenticatedMixin, View):
request.user.explorer.save()
return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
+
+
+class PlaceVoteView(IsEligibleToSeePlaceMixin, View):
+ delta = timedelta(weeks=24)
+
+ def get(self, request, place_id, vote):
+ place = get_object_or_404(Place, id=place_id)
+ explorer = request.user.explorer
+
+ voting = PlaceVoting.objects.filter(
+ submitted_by=explorer,
+ place=place
+ ).first()
+
+ if voting is None:
+ voting = PlaceVoting.objects.create(
+ submitted_by=explorer,
+ place=place,
+ vote=vote,
+ expires_when=timezone.now()+self.delta
+ )
+ messages.success(self.request, _('Vote submitted'))
+ else:
+ voting.expires_when=timezone.now()+self.delta
+ voting.vote = vote
+ messages.success(self.request, _('Your vote has been update'))
+
+ voting.save()
+ return redirect_referer_or(request, reverse('place_detail', kwargs={'pk': place.pk}))
\ No newline at end of file