Compare commits

...

2 Commits

Author SHA1 Message Date
0185c13a95 New testdata dump with 11 places. 2020-09-21 21:37:45 +02:00
9632040ade Typos and missing docstrings. 2020-09-21 21:37:28 +02:00
12 changed files with 3914 additions and 153 deletions

View File

@ -2,14 +2,14 @@
lostplaces-backend is a django (3.x) based webproject. It once wants to become a software which allows a group of urban explorers to manage, document and share the locations of lost places while not exposing too much / any information to the public. lostplaces-backend is a django (3.x) based webproject. It once wants to become a software which allows a group of urban explorers to manage, document and share the locations of lost places while not exposing too much / any information to the public.
The software is currently in early development status, neither scope, datalmodel(s) nor features are finalized yet. Therefore we would not recommend to download or install this piece of software anywhere - except your local django dev server. The software is currently in early development status, neither scope, datamodel(s) nor features are finalized yet. Therefore we would not recommend to download or install this piece of software anywhere - except your local django dev server.
We value privacy as a whole, all ressources the frontend requires will be shipped with lostplace's distribution. We also try to minimze 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.
## Features ## Features
- Manage lost places with lots of usefull information. - Manage lost places with lots of useful information.
- OSM-Maps - OSM-Maps
- Sensitive information is not accesiable for anonymous (not logged in) users. - Sensitive information is not accessible for anonymous (not logged in) users.
- User self registration using a voucher system, only people you invite can join your instance. - User self registration using a voucher system, only people you invite can join your instance.
- Collaboration, every user can add informations like tags, photos and external links to your place. - Collaboration, every user can add informations like tags, photos and external links to your place.
@ -63,9 +63,9 @@ Currently there are two ways to deploy the lostplaces project:
## Cloning the repository ## Cloning the repository
Essentially, this is the same as installing a development instance, but without the development server (manage.py runserver) and something powerfull (Apache, NGINX) instead. You have to configure the webserve to work with the *SGI Api respectivly, reference [django's guide for deployment](https://docs.djangoproject.com/en/3.1/howto/deployment/) for further information. Essentially, this is the same as installing a development instance, but without the development server (manage.py runserver) and something powerful (Apache, NGINX) instead. You have to configure the webserver to work with the *SGI Api respectively, reference [django's guide for deployment](https://docs.djangoproject.com/en/3.1/howto/deployment/) for further information.
You also should setup a dedicated database server, the built-in SQLite file is not recommened for production use. Reference [django's guide for databases](https://docs.djangoproject.com/en/3.1/ref/databases/) for further information. You also should setup a dedicated database server, the built-in SQLite file is not recommended for production use. Reference [django's guide for databases](https://docs.djangoproject.com/en/3.1/ref/databases/) for further information.
Before making the django instance public, you should tweak the config `settings.py`: Before making the django instance public, you should tweak the config `settings.py`:
1. Change the secret key, the one found in the config is already public. Choose something secure (i.e. [this](https://duckduckgo.com/?q=password+generator+64)). 1. Change the secret key, the one found in the config is already public. Choose something secure (i.e. [this](https://duckduckgo.com/?q=password+generator+64)).
@ -81,7 +81,7 @@ Run `django_lostplaces/managy.py collectstatic` and you should be ready to go.
If you haven't already setup a django instance, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/install/). If you haven't already setup a django instance, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/install/).
After that, download the desired release (probably the latest one) [from the realeases page](https://git.mowoe.com/reverend/lostplaces-backend/releases) and install it using `pip install --user name-of-the-file.tar.gz` After that, download the desired release (probably the latest one) [from the releases page](https://git.mowoe.com/reverend/lostplaces-backend/releases) and install it using `pip install --user name-of-the-file.tar.gz`
*Note: You can run pip install without the --user flag, which will require root privileges and introduces potential security issues.* *Note: You can run pip install without the --user flag, which will require root privileges and introduces potential security issues.*
@ -119,7 +119,7 @@ LOGOUT_REDIRECT_URL = reverse_lazy('django_lostplaces_home')
``` ```
### Configuring the URL's ### Configuring the URL's
In the `urls.py` configure the `urlpatter` like this: In the `urls.py` configure the `urlpatterns` like this:
```python ```python
urlpatterns = [ urlpatterns = [
path('admin/', admin.site.urls), path('admin/', admin.site.urls),
@ -133,5 +133,7 @@ Before making the django instance public, you should tweak the config `settings.
1. Change the secret key, the one found in the config is already public. Choose something secure (i.e. [this](https://duckduckgo.com/?q=password+generator+64)). 1. Change the secret key, the one found in the config is already public. Choose something secure (i.e. [this](https://duckduckgo.com/?q=password+generator+64)).
2. Turn off debug mode by setting `DEBUG = False`. 2. Turn off debug mode by setting `DEBUG = False`.
3. Tune the localization settings, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/i18n/). 3. Tune the localization settings, see [django's documentation](https://docs.djangoproject.com/en/3.1/topics/i18n/).
4. Set a new (random) SECRET_KEY in settings.py, e. g.: `base64 /dev/urandom | head -c50`
Run `django_lostplaces/managy.py collectstatic` you should be ready to go.
Run `django_lostplaces/manage.py collectstatic` you should be ready to go.

View File

@ -13,13 +13,13 @@ The class `lostplaces.models.Explorer` is our custom user profile. It has an For
You can access the explorer profile by accessing the 'explorer' attribute of any user instance You can access the explorer profile by accessing the 'explorer' attribute of any user instance
```python ```python
user.explorere user.explorer
``` ```
Currently the explorer profile is used by the abstract model 'Submittable' and thus referenced by 'Place' and 'PlaceImage'. The explorer profile therefore has two attributes Currently the explorer profile is used by the abstract model 'Submittable' and thus referenced by 'Place' and 'PlaceImage'. The explorer profile therefore has two attributes
```python ```python
user.explorer.places user.explorer.places
user.explorere.placeimages user.explorer.placeimages
``` ```
`places` `places`
A list containing all (lost) places the user has submitted A list containing all (lost) places the user has submitted
@ -36,12 +36,12 @@ TaggableManager, allows the sub class to be tagged, blank=True allows the admin
### Mapable ### Mapable
The abstract model Mapable represents an model that can be displayed on a map. It consists of tree members The abstract model Mapable represents an model that can be displayed on a map. It consists of tree members
`name` `name`
Name of the object, displayed on the map, max length 50 characeter Name of the object, displayed on the map, max length 50 characters
`latitude` `latitude`
Latitude of the referenced location, -90 <= value <= 90 Latitude of the referenced location, -90 <= value <= 90
`longitude` `longitude`
Longitude of the referenced location -180 <= value <= 180 Longitude of the referenced location -180 <= value <= 180
A mapable model has to provide its own get_aboslute_url, in order to provide a link when clicked. A mapable model has to provide its own get_absolute_url, in order to provide a link when clicked.
### Submittable ### Submittable
@ -49,15 +49,15 @@ The abstract model Submittable represents an model that can be submitted by an u
`submitted_by` `submitted_by`
Referencing the explorer profile, see [Explorer](##explorer-user-profile). If the explorer profile is deleted, this instance is kept (on_delete=models.SET_NULL). The related_name is set to the class name, lower case appending an s (%(class)s) Referencing the explorer profile, see [Explorer](##explorer-user-profile). If the explorer profile is deleted, this instance is kept (on_delete=models.SET_NULL). The related_name is set to the class name, lower case appending an s (%(class)s)
`submitted_when` `submitted_when`
When the object was submitted, automaticly set by django (auto_now_add=True) When the object was submitted, automatically set by django (auto_now_add=True)
### Voucher ### Voucher
A voucher code is needed to sign up using lostplaces sign up form. The model contains A voucher code is needed to sign up using lostplaces sign up form. The model contains
`code` `code`
The voucher code, max length 30 character The voucher code, max length 30 characters
`created_when` `created_when`
When the voucher was created automaticly set by django (auto_now_add=True) When the voucher was created automatically set by django (auto_now_add=True)
`expires_when` `expires_when`
Till what date the voucher remains valid Till what date the voucher remains valid
@ -65,7 +65,7 @@ Till what date the voucher remains valid
### Place ### Place
The place model is the heart of this project. It stores all information about a place needed. The place model is the heart of this project. It stores all information about a place needed.
`location` `location`
Human readable location description (town, village, street), max length 50 character Human readable location description (town, village, street), max length 50 characters
`description` `description`
Describing the place in detail Describing the place in detail
The place model uses these abstract super classes The place model uses these abstract super classes

View File

@ -19,9 +19,9 @@ class ExplorerCreationForm(UserCreationForm):
def is_valid(self): def is_valid(self):
super().is_valid() super().is_valid()
sumitted_voucher = self.cleaned_data.get('voucher') submitted_voucher = self.cleaned_data.get('voucher')
try: try:
fetched_voucher = Voucher.objects.get(code=sumitted_voucher) fetched_voucher = Voucher.objects.get(code=submitted_voucher)
except Voucher.DoesNotExist: except Voucher.DoesNotExist:
self.add_error('voucher', 'Invalid voucher') self.add_error('voucher', 'Invalid voucher')
return False return False

View File

@ -48,7 +48,7 @@ def save_user_profile(sender, instance, **kwargs):
class Taggable(models.Model): class Taggable(models.Model):
''' '''
This abstract model represtens an object that is taggalble This abstract model represtens an object that is taggable
using django-taggit using django-taggit
''' '''
class Meta: class Meta:
@ -150,7 +150,7 @@ class Place(Submittable, Taggable, Mapable):
def generate_image_upload_path(instance, filename): def generate_image_upload_path(instance, filename):
""" """
Callback for generating path for uploaded images. Callback for generating path for uploaded images.
Returns filename as: placepk-placename{-rndstring}.jpg Returns filename as: place_pk-placename{-rnd_string}.jpg
""" """
return 'places/' + str(instance.place.pk) + '-' + str(instance.place.name) + '.' + filename.split('.')[-1] return 'places/' + str(instance.place.pk) + '-' + str(instance.place.name) + '.' + filename.split('.')[-1]
@ -178,7 +178,7 @@ class PlaceImage (Submittable):
def __str__(self): def __str__(self):
""" """
Returning the name of the corresponding place + id Returning the name of the corresponding place + id
of this image as textual represntation of this instance of this image as textual representation of this instance
""" """
return 'Image ' + str(self.pk) return 'Image ' + str(self.pk)

View File

@ -0,0 +1,3 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django import template from django import template
register = template.Library() register = template.Library()

View File

@ -1,3 +1,6 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json, os import json, os
from importlib import import_module from importlib import import_module

View File

@ -45,7 +45,7 @@ class PlaceTestCase(ModelTestCase):
max_length=100 max_length=100
) )
def test_decsription(self): def test_description(self):
self.assertField('description', models.TextField) self.assertField('description', models.TextField)
def test_average_latlon(self): def test_average_latlon(self):
@ -112,7 +112,7 @@ class PlaceTestCase(ModelTestCase):
) )
) )
self.assertEqual(avg_latlon['longitude'], 0, self.assertEqual(avg_latlon['longitude'], 0,
msg='%s: a(no places) verage longitude missmatch' % ( msg='%s: (no places) average longitude missmatch' % (
self.model.__name__ self.model.__name__
) )
) )

View File

@ -10,7 +10,7 @@ from lostplaces.models import Voucher
from lostplaces.tests.models import ModelTestCase from lostplaces.tests.models import ModelTestCase
class VoucheTestCase(ModelTestCase): class VoucherTestCase(ModelTestCase):
model = Voucher model = Voucher
@classmethod @classmethod

View File

@ -9,7 +9,7 @@ from taggit.models import Tag
class ViewTestCase(TestCase): class ViewTestCase(TestCase):
''' '''
This is a mixni for testing views. It provides functionality to This is a Mixin for testing views. It provides functionality to
test the context, forms and HTTP Response of responses. test the context, forms and HTTP Response of responses.
All methods take responses, so this base class can be used All methods take responses, so this base class can be used
with django's RequestFactory and Test-Client with django's RequestFactory and Test-Client
@ -71,7 +71,7 @@ class ViewTestCase(TestCase):
def assertHttpRedirect(self, response, redirect_to=None): def assertHttpRedirect(self, response, redirect_to=None):
''' '''
Checks weather the response redirected, and if passed, Checks weather the response redirected, and if passed,
if it redirected to the expected loaction if it redirected to the expected location
''' '''
self.assertTrue( self.assertTrue(
@ -87,7 +87,7 @@ class ViewTestCase(TestCase):
self.assertEqual( self.assertEqual(
response['location'], response['location'],
redirect_to, redirect_to,
msg='Expecing the response to redirect to %s, where redirected to %s instea' % ( msg='Expecting the response to redirect to %s, where redirected to %s instea' % (
str(redirect_to), str(redirect_to),
str(response['location']) str(response['location'])
) )

View File

@ -16,7 +16,7 @@ from lostplaces.models import Place
class IsAuthenticatedMixin(LoginRequiredMixin, View): class IsAuthenticatedMixin(LoginRequiredMixin, View):
''' '''
A view mixin that checks wether a user is loged in or not. A view mixin that checks wether a user is logged in or not.
If the user is not logged in, he gets redirected to If the user is not logged in, he gets redirected to
the login page. the login page.
''' '''
@ -29,9 +29,9 @@ class IsAuthenticatedMixin(LoginRequiredMixin, View):
class IsPlaceSubmitterMixin(UserPassesTestMixin, View): class IsPlaceSubmitterMixin(UserPassesTestMixin, View):
''' '''
A view mixin that checks wethe a user is the submitter A view mixin that checks wether a user is the submitter
of a place Throws 403 if the user is not. The subclass of a place, throws 403 if the user is not. The subclass
has to provide a get_place method, wich returns the has to provide a get_place method, which returns the
place to check. place to check.
''' '''
place_submitter_error_message = None place_submitter_error_message = None

File diff suppressed because it is too large Load Diff