diff --git a/django_lostplaces/lostplaces/forms.py b/django_lostplaces/lostplaces/forms.py index 325ee0f..7cd51e3 100644 --- a/django_lostplaces/lostplaces/forms.py +++ b/django_lostplaces/lostplaces/forms.py @@ -17,7 +17,7 @@ class ExplorerCreationForm(UserCreationForm): voucher = forms.CharField( max_length=30, help_text=_('The Voucher you got from an administrator') - ) + ) def is_valid(self): super().is_valid() @@ -28,7 +28,7 @@ class ExplorerCreationForm(UserCreationForm): self.add_error('voucher', _('Invalid voucher')) return False - if not submitted_voucher.valid: + if not fetched_voucher.valid: self.add_error('voucher', _('Expired voucher')) return False diff --git a/django_lostplaces/lostplaces/locale/de/LC_MESSAGES/django.po b/django_lostplaces/lostplaces/locale/de/LC_MESSAGES/django.po index 3d6a6c1..b575421 100644 --- a/django_lostplaces/lostplaces/locale/de/LC_MESSAGES/django.po +++ b/django_lostplaces/lostplaces/locale/de/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-10-11 02:14+0200\n" +"POT-Creation-Date: 2020-10-11 07:48+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: Commander1024 \n" "Language-Team: LANGUAGE \n" @@ -30,23 +30,23 @@ msgstr "Ungültiger Voucher" msgid "Expired voucher" msgstr "Abgelaufener Voucher" -#: models/abstract_models.py:28 +#: models/abstract_models.py:29 msgid "Name" msgstr "Name" -#: models/abstract_models.py:35 +#: models/abstract_models.py:36 msgid "Latitude" msgstr "Breitengrad" -#: models/abstract_models.py:36 +#: models/abstract_models.py:37 msgid "Latitude in decimal format: e. g. 41.40338" msgstr "Breitengrad in dezimaler Form: z. B. 51.95021" -#: models/abstract_models.py:43 +#: models/abstract_models.py:44 msgid "Longitude" msgstr "Längengrad" -#: models/abstract_models.py:44 +#: models/abstract_models.py:45 msgid "Longitude in decimal format: e. g. 2.17403" msgstr "Breitengrad in dezimaler Form: z. B. 7.4840155" @@ -322,4 +322,56 @@ msgstr "Registrieren" #: views/base_views.py:25 msgid "Please login to proceed" -msgstr "Bitte log Dich ein um fortzufahren." +msgstr "Bitte log Dich ein um fortzufahren" + +#: views/place_image_views.py:26 +msgid "Image(s) submitted successfully" +msgstr "Bild(er) erfolgreich hinzugefügt" + +#: views/place_image_views.py:41 +msgid "Image(s) deleted successfully" +msgstr "Bild(er) erfolgreich gelöscht" + +#: views/place_image_views.py:42 +msgid "You are not allowed to delete this image" +msgstr "Du darfst dieses Bild nicht löschen" + +#: views/place_views.py:62 +#, fuzzy +#| msgid "Successfully deleted place" +msgid "Successfully updated place" +msgstr "Place erfolgreich gelöscht" + +#: views/place_views.py:63 +msgid "You do no have permissions to alter this place" +msgstr "Du hast nicht die Berechtigung, diesen Place zu bearbeiten" + +#: views/place_views.py:97 +#, fuzzy +#| msgid "Successfully deleted place" +msgid "Successfully created place" +msgstr "Place erfolgreich gelöscht" + +#: views/place_views.py:112 +msgid "Successfully deleted place" +msgstr "Place erfolgreich gelöscht" + +#: views/place_views.py:114 +msgid "You do no have permission to delete this place" +msgstr "Du hast nicht die Berechtigung, diesen Place zu löschen" + +#: views/views.py:29 +msgid "User created" +msgstr "User erstellt" + +#: views/views.py:54 +msgid "Photo Album submitted" +msgstr "Fotoalbum hinzugefügt" + +#: views/views.py:59 +msgid "Photo Album deleted" +msgstr "Fotoalbum gelöscht" + +#: views/views.py:60 +msgid "You do not have permissions to alter this photo album" +msgstr "Du hast nicht die Berechtigung, diesen Place zu bearbeiten" diff --git a/django_lostplaces/lostplaces/migrations/0002_remove_vouchers.py b/django_lostplaces/lostplaces/migrations/0002_remove_vouchers.py new file mode 100644 index 0000000..76a1aaf --- /dev/null +++ b/django_lostplaces/lostplaces/migrations/0002_remove_vouchers.py @@ -0,0 +1,22 @@ +# Generated by Django 3.1.1 on 2020-10-04 19:37 +# Edited by reverend + +import datetime +from django.db import migrations, models +import django.utils.timezone +from django.utils.timezone import utc + +class Migration(migrations.Migration): + + dependencies = [ + ('lostplaces', '0001_initial'), + ] + + operations = [ + migrations.DeleteModel( + name='Voucher' + ), + migrations.DeleteModel( + name='Expireable' + ) + ] diff --git a/django_lostplaces/lostplaces/migrations/0003_voucher.py b/django_lostplaces/lostplaces/migrations/0003_voucher.py new file mode 100644 index 0000000..6fd6747 --- /dev/null +++ b/django_lostplaces/lostplaces/migrations/0003_voucher.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.1 on 2020-10-04 19:52 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('lostplaces', '0002_remove_vouchers'), + ] + + operations = [ + migrations.CreateModel( + name='Voucher', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_when', models.DateTimeField(auto_now_add=True)), + ('expires_when', models.DateTimeField()), + ('code', models.CharField(max_length=30, unique=True)), + ], + options={ + 'abstract': False, + }, + ), + ] diff --git a/django_lostplaces/lostplaces/models/abstract_models.py b/django_lostplaces/lostplaces/models/abstract_models.py index d0446a7..ee7f5ce 100644 --- a/django_lostplaces/lostplaces/models/abstract_models.py +++ b/django_lostplaces/lostplaces/models/abstract_models.py @@ -1,4 +1,5 @@ +from django.utils import timezone from django.db import models from django.utils.translation import ugettext_lazy as _ from django.core.validators import MaxValueValidator, MinValueValidator @@ -63,7 +64,14 @@ class Submittable(models.Model): class Expireable(models.Model): """ - Base class for things that can expire, i.e. VouchersAv + Base class for things that can expire, i.e. Vouchers """ + class Meta: + abstract = True + created_when = models.DateTimeField(auto_now_add=True) expires_when = models.DateTimeField() + + @property + def is_expired(self): + return timezone.now() > self.expires_when diff --git a/django_lostplaces/lostplaces/models/models.py b/django_lostplaces/lostplaces/models/models.py index a545fe0..16b53da 100644 --- a/django_lostplaces/lostplaces/models/models.py +++ b/django_lostplaces/lostplaces/models/models.py @@ -49,6 +49,10 @@ class Voucher(Expireable): """ code = models.CharField(unique=True, max_length=30) + + @property + def valid(self): + return not self.is_expired def __str__(self): return "Voucher " + str(self.code) diff --git a/django_lostplaces/lostplaces/templates/place/place_detail.html b/django_lostplaces/lostplaces/templates/place/place_detail.html index 1852d58..6d91170 100644 --- a/django_lostplaces/lostplaces/templates/place/place_detail.html +++ b/django_lostplaces/lostplaces/templates/place/place_detail.html @@ -63,7 +63,7 @@ {{photo_album.label}} - {% if user.explorer == photo_album.submitted_by or user.explorer == place.submitted_by %} + {% if user.explorer == photo_album.submitted_by or user.explorer == place.submitted_by %}
{% icon 'trash' className="RV-Iconized__Icon" %} diff --git a/django_lostplaces/lostplaces/templatetags/lostplaces.py b/django_lostplaces/lostplaces/templatetags/lostplaces.py index d5262f5..c2a09d9 100644 --- a/django_lostplaces/lostplaces/templatetags/lostplaces.py +++ b/django_lostplaces/lostplaces/templatetags/lostplaces.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- from django import template +from django.http import request register = template.Library() @@ -22,4 +23,4 @@ def proper_paginate(paginator, current_page, neighbors=2): end_index = paginator.num_pages page_list = [f for f in range(start_index, end_index+1)] return page_list[:(2*neighbors + 1)] - return paginator.page_range \ No newline at end of file + return paginator.page_range diff --git a/django_lostplaces/lostplaces/tests/forms/__init__.py b/django_lostplaces/lostplaces/tests/forms/__init__.py new file mode 100644 index 0000000..0cf6568 --- /dev/null +++ b/django_lostplaces/lostplaces/tests/forms/__init__.py @@ -0,0 +1,76 @@ +from django.test import TestCase +from django.core.exceptions import FieldDoesNotExist + +class FormTestCase(TestCase): + ''' + Base class for FormTests. + Parameters: + - form : Form to test + ''' + form = None + + def assertField(self, field_name, field_class, must_have={}, must_not_have={}): + ''' + Tests if a field exists under the given name and + if the field is of the right type. + Also checks if the field has the given must_have attributes + and does not have any of the must_not_have attributes. If you + dont care about the value of the attribute you can just set it to + something that fullfills value == False (i.e. '' or 0) + ''' + try: + field = self.form.base_fields[field_name] + except FieldDoesNotExist: + self.fail( + 'Expecting %s to have a field named \'%s\'' % ( + self.form.__name__, + field_name + ) + ) + self.assertEqual( + type(field), field_class, + msg='Expecting type of %s to be %s' % ( + str(field), + field_class.__name__ + ) + ) + + for key, value in must_have.items(): + if value: + self.assertEqual( + getattr(field, key), value, + msg='Expeting the value of %s %s to be \'%s\'' % ( + str(field), + key, + value + ) + ) + else: + self.assertTrue( + hasattr(field, key), + msg='Expeting %s to have \'%s\'' % ( + str(field), + key + ) + ) + + for key, value in must_not_have.items(): + if value: + self.assertTrue( + getattr(field, key) != value, + msg='Expeting the value of %s %s to not be \'%s\'' % ( + str(field), + key, + value + ) + ) + else: + self.assertFalse( + hasattr(field, value), + msg='Expeting %s to not have \'%s\'' % ( + str(field), + key + ) + ) + + return field \ No newline at end of file diff --git a/django_lostplaces/lostplaces/tests/forms/test_explorer_forms.py b/django_lostplaces/lostplaces/tests/forms/test_explorer_forms.py new file mode 100644 index 0000000..89b6986 --- /dev/null +++ b/django_lostplaces/lostplaces/tests/forms/test_explorer_forms.py @@ -0,0 +1,59 @@ +import datetime + +from django import forms +from django.utils import timezone + +from lostplaces.tests.forms import FormTestCase +from lostplaces.forms import ExplorerCreationForm +from lostplaces.models.models import Voucher + +class ExplorerCreationFormTestCase(FormTestCase): + """ + This test case only tests for the voucher since all other aspects don't realy matter + to this project and are already tested by django + """ + form = ExplorerCreationForm + + @classmethod + def setUpTestData(cls): + Voucher.objects.create( + code='Imacode123', + expires_when=timezone.now() + datetime.timedelta(minutes=1) + ) + + def setUp(self): + self.post_data = { + 'voucher': 'Imacode123', + 'username': 'testpeter', + 'email': 'testpeter@example.org', + 'password1': 'Develop123', + 'password2': 'Develop123' + } + + def test_voucher_field(self): + self.assertField( + field_name='voucher', + field_class=forms.CharField + ) + + def test_validation_valid(self): + form = ExplorerCreationForm(self.post_data) + self.assertTrue( + form.is_valid(), + msg='Expecting the %s to validate' % ( + self.form.__name__ + ) + ) + + def test_validation_invalid(self): + self.post_data = { + 'voucher': 'Imanotacode123' + } + form = ExplorerCreationForm(self.post_data) + self.assertFalse( + form.is_valid(), + msg='Expecting the %s to not validate' % ( + self.form.__name__ + ) + ) + \ No newline at end of file diff --git a/django_lostplaces/lostplaces/tests/models/__init__.py b/django_lostplaces/lostplaces/tests/models/__init__.py index 1e5f7f6..70b5253 100644 --- a/django_lostplaces/lostplaces/tests/models/__init__.py +++ b/django_lostplaces/lostplaces/tests/models/__init__.py @@ -2,11 +2,9 @@ # -*- coding: utf-8 -*- from django.db import models -from django.contrib.auth.models import User from django.core.exceptions import FieldDoesNotExist from django.test import TestCase -# Creating a test user class ModelTestCase(TestCase): ''' diff --git a/django_lostplaces/lostplaces/tests/models/test_abstract_models.py b/django_lostplaces/lostplaces/tests/models/test_abstract_models.py index 30415de..3d32b25 100644 --- a/django_lostplaces/lostplaces/tests/models/test_abstract_models.py +++ b/django_lostplaces/lostplaces/tests/models/test_abstract_models.py @@ -1,6 +1,9 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +import datetime + +from django.utils import timezone from django.test import TestCase from django.db import models from django.contrib.auth.models import User @@ -10,7 +13,8 @@ from lostplaces.models import ( Mapable, Submittable, PlaceAsset, - Expireable + Expireable, + Voucher ) from lostplaces.tests.models import ModelTestCase @@ -112,4 +116,34 @@ class PlaceAssetTestCase(ModelTestCase): ) class ExpireableTestCase(ModelTestCase): - model = Expireable \ No newline at end of file + model = Expireable + + def test_fields(self): + self.assertField( + field_name='created_when', + field_class=models.DateTimeField, + must_have={'auto_now_add': True} + ) + self.assertField( + field_name='expires_when', + field_class=models.DateTimeField + ) + + def test_is_expired(self): + valid_voucher = Voucher.objects.create( + code='Test123', + expires_when=timezone.now() + datetime.timedelta(minutes=2) + ) + self.assertFalse( + valid_voucher.is_expired, + msg='Expecing the expirable object to not be expired' + ) + + invalid_voucher = Voucher.objects.create( + code='Test1234', + expires_when=timezone.now() - datetime.timedelta(minutes=2) + ) + self.assertTrue( + invalid_voucher.is_expired, + msg='Expecing the expirable object to be expired' + ) \ No newline at end of file diff --git a/django_lostplaces/lostplaces/views/place_image_views.py b/django_lostplaces/lostplaces/views/place_image_views.py index 4b4ce58..79f6266 100644 --- a/django_lostplaces/lostplaces/views/place_image_views.py +++ b/django_lostplaces/lostplaces/views/place_image_views.py @@ -1,5 +1,6 @@ from django.views import View from django.shortcuts import get_object_or_404, redirect +from django.utils.translation import ugettext_lazy as _ from lostplaces.views.base_views import PlaceAssetCreateView, PlaceAssetDeleteView from lostplaces.models import PlaceImage, Place @@ -22,7 +23,7 @@ class PlaceImageCreateView(MultiplePlaceImageUploadMixin, PlaceAssetCreateView): model = PlaceImage form_class = PlaceImageForm template_name = 'place_image/place_image_create.html' - success_message = 'Place Images submitted' + success_message = _('Image(s) submitted successfully') commit = False def post(self, request, place_id, *args, **kwargs): @@ -37,7 +38,5 @@ class PlaceImageCreateView(MultiplePlaceImageUploadMixin, PlaceAssetCreateView): class PlaceImageDeleteView(PlaceAssetDeleteView): model = PlaceImage - success_message = 'Images deleted successfully' - permission_denied_message = 'You\'r not allowed to delete this image' - - \ No newline at end of file + success_message = _('Image(s) deleted successfully') + permission_denied_message = _('You are not allowed to delete this image') diff --git a/django_lostplaces/lostplaces/views/place_views.py b/django_lostplaces/lostplaces/views/place_views.py index f367623..7a5c129 100644 --- a/django_lostplaces/lostplaces/views/place_views.py +++ b/django_lostplaces/lostplaces/views/place_views.py @@ -10,6 +10,7 @@ from django.views.generic import ListView from django.contrib import messages from django.contrib.messages.views import SuccessMessageMixin +from django.utils.translation import ugettext_lazy as _ from django.shortcuts import render, redirect, get_object_or_404 from django.urls import reverse_lazy @@ -58,8 +59,8 @@ class PlaceUpdateView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, SuccessMessag template_name = 'place/place_update.html' model = Place form_class = PlaceForm - success_message = 'Successfully updated place.' - place_submitter_error_message = 'You do no have permissions to alter this place' + success_message = _('Successfully updated place') + place_submitter_error_message = _('You do no have permissions to alter this place') def get_success_url(self): return reverse_lazy('place_detail', kwargs={'pk':self.get_object().pk}) @@ -93,7 +94,7 @@ class PlaceCreateView(MultiplePlaceImageUploadMixin, IsAuthenticatedMixin, View) messages.success( self.request, - 'Successfully created place.' + _('Successfully created place') ) return redirect(reverse_lazy('place_detail', kwargs={'pk': place.pk})) @@ -108,14 +109,13 @@ class PlaceCreateView(MultiplePlaceImageUploadMixin, IsAuthenticatedMixin, View) class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView): template_name = 'place/place_delete.html' model = Place - success_message = 'Successfully deleted place.' + success_message = _('Successfully deleted place') success_url = reverse_lazy('place_list') - success_message = 'Place deleted' - place_submitter_error_message = 'You do no have permission to delete this place' + place_submitter_error_message = _('You do no have permission to delete this place') def delete(self, request, *args, **kwargs): messages.success(self.request, self.success_message) return super().delete(request, *args, **kwargs) def get_place(self): - return self.get_object() \ No newline at end of file + return self.get_object() diff --git a/django_lostplaces/lostplaces/views/views.py b/django_lostplaces/lostplaces/views/views.py index 1918feb..7a92abe 100644 --- a/django_lostplaces/lostplaces/views/views.py +++ b/django_lostplaces/lostplaces/views/views.py @@ -9,6 +9,7 @@ from django.contrib import messages from django.urls import reverse_lazy from django.shortcuts import render, redirect, get_object_or_404 from django.http import HttpResponseForbidden +from django.utils.translation import ugettext_lazy as _ from lostplaces.forms import ExplorerCreationForm, TagSubmitForm from lostplaces.models import Place, PhotoAlbum @@ -25,7 +26,7 @@ class SignUpView(SuccessMessageMixin, CreateView): form_class = ExplorerCreationForm success_url = reverse_lazy('login') template_name = 'signup.html' - success_message = 'User created.' + success_message = _('User created') class HomeView(IsAuthenticatedMixin, View): def get(self, request, *args, **kwargs): @@ -50,13 +51,13 @@ class PhotoAlbumCreateView(PlaceAssetCreateView): model = PhotoAlbum fields = ['url', 'label'] template_name = 'photo_album/photo_album_create.html' - success_message = 'Photo Album submitted' + success_message = _('Photo Album submitted') class PhotoAlbumDeleteView(PlaceAssetDeleteView): model = PhotoAlbum pk_url_kwarg = 'pk' - success_message = 'Photo Album deleted' - permission_denied_messsage = 'You do not have permissions to alter this photo album' + success_message = _('Photo Album deleted') + permission_denied_messsage = _('You do not have permissions to alter this photo album') class PlaceTagSubmitView(IsAuthenticatedMixin, View): def post(self, request, tagged_id, *args, **kwargs): diff --git a/setup.py b/setup.py index ede7639..c8e8ed8 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ with open('Readme.md') as f: setup( name='django-lostplaces', - version='0.1.a5', + version='0.1.2 HotFix', description='A django app to manage lost places', author='Reverend', author_email='reverend@reverend2048.de',