9 Commits

13 changed files with 158 additions and 175 deletions

3
.gitignore vendored
View File

@@ -92,6 +92,3 @@ venv.bak/
# twine / pypi
.pypirc
# Django Migrations for Development branches
django_lostplaces/lostplaces/migrations/*

View File

@@ -14,6 +14,7 @@ pandoc = "*"
pylint-django = "*"
setuptools = "*"
django-nose = "*"
invoke = "*"
[packages]
django = "*"
@@ -30,3 +31,7 @@ showmigrations = "django_lostplaces/manage.py showmigrations"
makemigrations = "django_lostplaces/manage.py makemigrations --no-input"
migrate = "django_lostplaces/manage.py migrate"
build = "django_lostplaces/setup.py bdist_wheel --universal"
createsuperuser = "django_lostplaces/manage.py createsuperuser --noinput --username admin --email admin@example.org"
createsuperuser_prompt = "django_lostplaces/manage.py createsuperuser"
quickstart = "invoke quickstart"
security = "pipenv check"

View File

@@ -35,7 +35,7 @@ Right now it depends on the following non-core Python 3 libraries. These can be
# Installing a development instance
## Clone the repository
`git clone https://git.mowoe.com/reverend/lostplaces-backend.git`
`git clone https://git.commander1024.de/Commander1024/lostplaces-backend`
## Setting up a (pipenv) virtual environment for development
After having obtained the repository contents (either via .zip download or git clone), you can easily setup a [pipenv](https://docs.pipenv.org/) virtual environment. The repo provides a Pipfile for easy dependency management that does not mess with your system.
@@ -65,6 +65,21 @@ Visit: [admin](http://localhost:8000/admin) for administrative backend or
Happy developing ;-)
# Pipenv Scripts
This project comes with a bunch of convinient scripts, like:
|Script|Description|
|---|---|
|test|Runs the tests|
|server|Starts a **development** server|
|dbshell|Opens a shell session in the database|
|showmigrations|Lists all Migrations|
|makemigrations|Creates a migration|
|migrate|Applies unapplied migrations|
|build|Builds this project into a wheel file|
|createsuperuser|Creates a superuser with the username **admin** and the password **develop**. This is for development and demo instances only!
|quickstart|Runs *migrate*, *createsuperuser* and *server*|
# Installing a productive instance
Currently there are two ways to deploy the lostplaces project:

View File

@@ -1,118 +0,0 @@
# 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

@@ -1,18 +0,0 @@
# 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_gory_fix'),
]
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

@@ -0,0 +1,85 @@
# Generated by Django 3.2.10 on 2021-12-31 17:20
from django.db import migrations, models
import django.db.models.deletion
import easy_thumbnails.fields
import lostplaces.models.models
import lostplaces.models.place
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0004_release_0_1_3'),
]
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='level',
field=models.IntegerField(choices=[(1, 'Newbie'), (2, 'Scout'), (3, 'Explorer'), (4, 'Journalist'), (5, 'Housekeeper')], default=1),
),
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=lostplaces.models.generate_profile_image_filename, verbose_name='Profile image'),
),
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'),
),
migrations.AddField(
model_name='place',
name='hero',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='place_heros', to='lostplaces.placeimage'),
),
migrations.AddField(
model_name='place',
name='level',
field=models.IntegerField(choices=[(1, 'Ruin'), (2, 'Vandalized'), (3, 'Natures Treasure'), (4, 'Lost in History'), (5, 'Time Capsule')], default=5),
),
migrations.AlterField(
model_name='placeimage',
name='filename',
field=easy_thumbnails.fields.ThumbnailerImageField(help_text='Optional: One or more images to upload', upload_to=lostplaces.models.place.generate_place_image_filename, verbose_name='Images'),
),
migrations.CreateModel(
name='PlaceVoting',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('submitted_when', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date')),
('created_when', models.DateTimeField(auto_now_add=True, verbose_name='Creation date')),
('expires_when', models.DateTimeField(verbose_name='Expiration date')),
('vote', models.IntegerField(choices=[(1, 'Ruin'), (2, 'Vandalized'), (3, 'Natures Treasure'), (4, 'Lost in History'), (5, 'Time Capsule')])),
('place', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='placevotings', to='lostplaces.place')),
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placevotings', to='lostplaces.explorer', verbose_name='Submitter')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='DummyAsset',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('submitted_when', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date')),
('name', models.CharField(max_length=50)),
('place', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='dummyassets', to='lostplaces.place')),
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='dummyassets', to='lostplaces.explorer', verbose_name='Submitter')),
],
options={
'abstract': False,
},
),
]

View File

@@ -1,14 +0,0 @@
# Generated by Django 3.2.5 on 2021-07-16 11:15
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0004_release_0_1_3'),
('lostplaces', '0005_add_visited_places'),
]
operations = [
]

View File

@@ -94,7 +94,9 @@ class Place(Submittable, Taggable, Mapable):
self.remove_expired_votes()
if self.placevotings.count() == 0:
return 5
self.level = 5
self.save()
return
level = 0
@@ -102,6 +104,7 @@ class Place(Submittable, Taggable, Mapable):
level += vote.vote
self.level = floor(level / self.placevotings.count())
self.save()
def remove_expired_votes(self):
for vote in self.placevotings.all():

View File

@@ -6,7 +6,7 @@
Place level
</h2>
<div class="LP-Voting__Choices">
{% for choice in voting.get_all_choices %}
{% for choice in voting.all_choices %}
<a href="{% url 'place_vote' place_id=place.id vote=choice.0 %}" class="LP-Voting__Vote {% if choice.0 <= place.level %} LP-Voting__Vote--overall{% endif %}" title="Vote place as &quot;{{choice.1}}&quot;">
<i class="mdi mdi-shield-home"></i>
<span class="LP-Voting__Label">
@@ -19,21 +19,23 @@
{{place.get_level_display}}
</div>
</div>
{% if voting.users_vote %}
<div class="LP-Voting__Right">
<div class="LP-Voting__Info">
<div class="LP-Voting__UserVote">
<span class="LP-Voting__InfoLabel">You voted this place as</span>
<span class="LP-Voting__Vote">{{voting.get_human_readable_level}}</span>
<span class="LP-Voting__Vote">{{voting.users_vote.get_human_readable_level}} <i>Level {{voting.users_vote.vote}}</i></span>
</div>
<div class="LP-Voting__Expiration">
<span class="LP-Voting__InfoLabel">Your vote expires on</span>
<span class="LP-Voting__Date">
<time datetime="{{voting.expires_when|date:'Y-m-d'}}">
{{voting.expires_when|date:'d.m.Y'}}
{{voting.users_vote.expires_when|date:'d.m.Y'}}
</time>
</span>
</div>
</div>
</div>
{% endif %}
</div>

View File

@@ -14,7 +14,6 @@ from lostplaces.tests.views import (
)
class TestHomeView(GlobalTemplateTestCaseMixin, ViewTestCase):
@classmethod
def setUpTestData(cls):
user = User.objects.create_user(

View File

@@ -19,7 +19,8 @@ from django.urls import reverse_lazy, reverse
from lostplaces.models import (
Place,
PlaceImage,
PlaceVoting
PlaceVoting,
PLACE_LEVELS
)
from lostplaces.views.base_views import (
@@ -71,7 +72,10 @@ class PlaceDetailView(IsAuthenticatedMixin, IsEligibleToSeePlaceMixin, View):
'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()
'placevoting': {
'users_vote': PlaceVoting.objects.filter(place=place, submitted_by=explorer).first(),
'all_choices': reversed(PLACE_LEVELS)
}
}
return render(request, 'place/place_detail.html', context)

View File

@@ -6,9 +6,11 @@ from setuptools import setup, find_packages
with open('Readme.md') as f:
readme = f.read()
# Keep PEP 440 for version identification in mind
# https://www.python.org/dev/peps/pep-0440/#post-releases
setup(
name='django-lostplaces',
version='0.1.3',
version='0.1.4.post1',
description='A django app to manage lost places',
author='Reverend',
author_email='reverend@reverend2048.de',

21
tasks.py Normal file
View File

@@ -0,0 +1,21 @@
from invoke import task
@task
def quickstart(c):
commands = [
'pipenv run migrate',
'pipenv run createsuperuser',
'pipenv run server'
]
c.run(' && '.join(commands))
@task
def live(c):
commands = [
'pipenv check',
'pipenv run test',
'pipenv run migrate',
'pipenv run createsuperuser_prompt'
'pipenv run server'
]
c.run(' && '.join(commands))