Compare commits
No commits in common. "0185c13a9559f486be61ce20ed0752748d9ccfae" and "85a34b20f9520721c28ef63fc1aaca8521933389" have entirely different histories.
0185c13a95
...
85a34b20f9
20
Readme.md
20
Readme.md
@ -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, 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.
|
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.
|
||||||
|
|
||||||
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 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.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
- Manage lost places with lots of useful information.
|
- Manage lost places with lots of usefull information.
|
||||||
- OSM-Maps
|
- OSM-Maps
|
||||||
- Sensitive information is not accessible for anonymous (not logged in) users.
|
- Sensitive information is not accesiable 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 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.
|
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.
|
||||||
|
|
||||||
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.
|
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.
|
||||||
|
|
||||||
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 releases 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 realeases 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 `urlpatterns` like this:
|
In the `urls.py` configure the `urlpatter` like this:
|
||||||
```python
|
```python
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
@ -133,7 +133,5 @@ 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.
|
|
||||||
|
@ -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.explorer
|
user.explorere
|
||||||
```
|
```
|
||||||
|
|
||||||
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.explorer.placeimages
|
user.explorere.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 characters
|
Name of the object, displayed on the map, max length 50 characeter
|
||||||
`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_absolute_url, in order to provide a link when clicked.
|
A mapable model has to provide its own get_aboslute_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, automatically set by django (auto_now_add=True)
|
When the object was submitted, automaticly 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 characters
|
The voucher code, max length 30 character
|
||||||
`created_when`
|
`created_when`
|
||||||
When the voucher was created automatically set by django (auto_now_add=True)
|
When the voucher was created automaticly 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 characters
|
Human readable location description (town, village, street), max length 50 character
|
||||||
`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
|
||||||
|
@ -19,9 +19,9 @@ class ExplorerCreationForm(UserCreationForm):
|
|||||||
|
|
||||||
def is_valid(self):
|
def is_valid(self):
|
||||||
super().is_valid()
|
super().is_valid()
|
||||||
submitted_voucher = self.cleaned_data.get('voucher')
|
sumitted_voucher = self.cleaned_data.get('voucher')
|
||||||
try:
|
try:
|
||||||
fetched_voucher = Voucher.objects.get(code=submitted_voucher)
|
fetched_voucher = Voucher.objects.get(code=sumitted_voucher)
|
||||||
except Voucher.DoesNotExist:
|
except Voucher.DoesNotExist:
|
||||||
self.add_error('voucher', 'Invalid voucher')
|
self.add_error('voucher', 'Invalid voucher')
|
||||||
return False
|
return False
|
||||||
|
@ -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 taggable
|
This abstract model represtens an object that is taggalble
|
||||||
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: place_pk-placename{-rnd_string}.jpg
|
Returns filename as: placepk-placename{-rndstring}.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 representation of this instance
|
of this image as textual represntation of this instance
|
||||||
"""
|
"""
|
||||||
|
|
||||||
return 'Image ' + str(self.pk)
|
return 'Image ' + str(self.pk)
|
||||||
|
@ -1,3 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
@ -1,6 +1,3 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
|
|
||||||
register = template.Library()
|
register = template.Library()
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import json, os
|
import json, os
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class PlaceTestCase(ModelTestCase):
|
|||||||
max_length=100
|
max_length=100
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_description(self):
|
def test_decsription(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: (no places) average longitude missmatch' % (
|
msg='%s: a(no places) verage longitude missmatch' % (
|
||||||
self.model.__name__
|
self.model.__name__
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -10,7 +10,7 @@ from lostplaces.models import Voucher
|
|||||||
from lostplaces.tests.models import ModelTestCase
|
from lostplaces.tests.models import ModelTestCase
|
||||||
|
|
||||||
|
|
||||||
class VoucherTestCase(ModelTestCase):
|
class VoucheTestCase(ModelTestCase):
|
||||||
model = Voucher
|
model = Voucher
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -9,7 +9,7 @@ from taggit.models import Tag
|
|||||||
|
|
||||||
class ViewTestCase(TestCase):
|
class ViewTestCase(TestCase):
|
||||||
'''
|
'''
|
||||||
This is a Mixin for testing views. It provides functionality to
|
This is a mixni 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 location
|
if it redirected to the expected loaction
|
||||||
'''
|
'''
|
||||||
|
|
||||||
self.assertTrue(
|
self.assertTrue(
|
||||||
@ -87,7 +87,7 @@ class ViewTestCase(TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
response['location'],
|
response['location'],
|
||||||
redirect_to,
|
redirect_to,
|
||||||
msg='Expecting the response to redirect to %s, where redirected to %s instea' % (
|
msg='Expecing the response to redirect to %s, where redirected to %s instea' % (
|
||||||
str(redirect_to),
|
str(redirect_to),
|
||||||
str(response['location'])
|
str(response['location'])
|
||||||
)
|
)
|
||||||
|
@ -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 logged in or not.
|
A view mixin that checks wether a user is loged 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 wether a user is the submitter
|
A view mixin that checks wethe 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, which returns the
|
has to provide a get_place method, wich returns the
|
||||||
place to check.
|
place to check.
|
||||||
'''
|
'''
|
||||||
place_submitter_error_message = None
|
place_submitter_error_message = None
|
||||||
|
3992
django_lostplaces/testdata/testdata.json
vendored
3992
django_lostplaces/testdata/testdata.json
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user