35 Commits

Author SHA1 Message Date
4a43a4bf37 typo 2020-12-24 16:43:43 +01:00
61cf148417 Displaying favorite icon on detail page 2020-12-24 16:43:33 +01:00
d547ee9db3 favorite partial 2020-12-24 16:43:14 +01:00
c7b699f615 Changed link location in place teaser 2020-12-24 16:43:01 +01:00
86f95a5dd0 New icon 2020-12-24 16:42:34 +01:00
916c4b80f7 Filed not required in django admin 2020-12-24 16:42:27 +01:00
b31dc9fc5f Url name changed 2020-12-24 16:41:30 +01:00
8f048369bf Favorite/Unfavorite Views 2020-12-24 15:56:33 +01:00
f974469996 formatting 2020-12-24 15:56:02 +01:00
dbbd7b0802 rename migrationfile 2020-12-24 15:55:37 +01:00
abca946883 Model for favorite system 2020-12-24 14:48:11 +01:00
4bacd1a28d Recopied migration files 2020-12-19 14:47:59 +01:00
086789aa88 delete miration for release 2020-12-19 14:35:20 +01:00
3c5b447d4c New CSS 2020-11-29 19:23:44 +01:00
cfbb876d2c #41 2020-11-29 19:23:39 +01:00
4e0bfef483 Incorporating Profile View into Project 2020-11-29 19:23:22 +01:00
ccdb49c8ea Profile View 2020-11-29 19:22:55 +01:00
90dd281f7c Common functionalities 2020-11-29 19:22:38 +01:00
d9df6e67a8 Hassling with migrations 2020-11-29 19:22:27 +01:00
cd20e730ba Merge branch 'master' into develop 2020-11-27 07:58:53 +01:00
c613d15e89 Updated Readme 2020-11-27 07:57:56 +01:00
2380398fa9 #36 and #37 Place Teaser 2020-10-12 20:57:04 +02:00
4c5b9c7648 Dumped a nice missing-image image. Needs resizing and logic. 2020-10-11 23:08:14 +02:00
91a3f3171d Merge branch 'feature/localization' into develop 2020-10-11 21:57:30 +02:00
01f7dad37c Translated Model fields - primarily for backend. 2020-10-11 21:56:14 +02:00
2bfdf5c172 Translated place deletion question with blrocktrans in a more natural way. 2020-10-11 21:55:38 +02:00
15f6a30cd6 Streamlined translations ... again :P 2020-10-11 21:27:27 +02:00
812c921a42 Merge commit 'dafe7eee3489e3a7c17b6560fc2aa09648773ecd' into feature/localization 2020-10-11 17:20:53 +02:00
dafe7eee34 Deleted mishap. 2020-10-11 09:47:34 +02:00
4e366d94c9 Fixing Error on sign up 2020-10-06 22:53:35 +02:00
773390b09f Moved files so only the app is packed 2020-10-04 23:23:02 +02:00
ac0121d96e removed old config 2020-10-04 23:22:53 +02:00
a0c4f2cad3 Merge branch 'develop' into master 2020-10-04 22:19:01 +02:00
66bd9f648b Merge branch 'develop' into master 2020-10-04 15:43:41 +02:00
485eb7b886 Bumping version 2020-10-01 22:06:12 +02:00
33 changed files with 646 additions and 195 deletions

View File

@@ -22,7 +22,7 @@ Right now it depends on the following non-core Python 3 libraries. These can be
* [django-widget-tweaks](https://github.com/jazzband/django-widget-tweaks) Tweak the form field rendering in templates, not in python-level form definitions.
* [django-taggit](https://github.com/jazzband/django-taggit) A simpler approach to tagging with Django.
### Bundled Dependencies
### Bundled Dependencies
We also leverage some other great OpenSource projects' code. We bundle those in the distribution to obsolete the need to pull those files from monitored CDNs.
* [OpenLayers](https://openlayers.org/) [6.4.3] OpenLayers makes it easy to put a dynamic map in any web page. It can display map tiles, vector data and markers loaded from any source.
@@ -88,7 +88,9 @@ 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/).
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`
Afterwards, either
- download the desired release [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`
- or install the latest release using `pip install django-lostplaces`
*Note: You can run pip install without the --user flag, which will require root privileges and introduces potential security issues.*
@@ -144,3 +146,7 @@ Before making the django instance public, you should tweak the config `settings.
Run `django_lostplaces/manage.py collectstatic` you should be ready to go.
### Contact
If you run into any issues, have any questions or If you are interested in this project in general, feel free to get in touch with us via [reverend@reverend2048.de](mailto:reverend@reverend2048.de), we do speak English and German.

View File

@@ -1,3 +1,4 @@
exclude
include LICENSE
include Readme.rst
include Pipfile

View File

@@ -0,0 +1,11 @@
def get_all_subclasses(cls):
'''
Gets all subclasses recursively, does not contain
abstract classes
'''
subclass_list = []
for subclass in cls.__subclasses__():
if not subclass._meta.abstract:
subclass_list.append(subclass)
subclass_list += get_all_subclasses(subclass)
return subclass_list

View File

@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-10-11 07:48+0200\n"
"POT-Creation-Date: 2020-10-11 21:53+0200\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: Commander1024 <commander@commander1024.de>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -50,6 +50,22 @@ msgstr "Längengrad"
msgid "Longitude in decimal format: e. g. 2.17403"
msgstr "Breitengrad in dezimaler Form: z. B. 7.4840155"
#: models/abstract_models.py:59
msgid "Submission date"
msgstr "Einreichungsdatum"
#: models/abstract_models.py:67
msgid "Submitter"
msgstr "Einreicher"
#: models/abstract_models.py:79
msgid "Creation date"
msgstr "Erstellungsdatum"
#: models/abstract_models.py:82
msgid "Expiration date"
msgstr "Ablaufdatum"
#: models/external_links.py:13
msgid "URL"
msgstr "Adresse (URL)"
@@ -96,7 +112,7 @@ msgstr "Zurück"
#: templates/global.html:32
msgid "Logout"
msgstr "Abmelden"
msgstr "Ausloggen"
#: templates/global.html:34
msgid "Admin"
@@ -108,8 +124,8 @@ msgid "Login"
msgstr "Anmelden"
#: templates/global.html:40 templates/registration/login.html:29
#: templates/signup.html:12 templates/signup.html:41
msgid "Sign Up"
#: templates/signup.html:6 templates/signup.html:12 templates/signup.html:41
msgid "Sign up"
msgstr "Registrieren"
#: templates/global.html:50 templates/home.html:10
@@ -122,11 +138,11 @@ msgstr "UrBex Codex"
#: templates/global.html:56 templates/place/place_create.html:5
#: templates/place/place_create.html:10
msgid "Create Place"
msgid "Create place"
msgstr "Place erstellen"
#: templates/global.html:57
msgid "All Places"
msgid "All places"
msgstr "Alle Places"
#: templates/home.html:20 templates/home_unauth.html:20
@@ -247,7 +263,8 @@ msgid "Submit a photo album"
msgstr "Fotoalbum hinzufügen"
#: templates/photo_album/photo_album_create.html:8
#: templates/place/place_detail.html:18
#: templates/place/place_detail.html:18 templates/place/place_update.html:5
#: templates/place/place_update.html:10
msgid "Edit place"
msgstr "Place bearbeiten"
@@ -265,12 +282,13 @@ msgid "Create"
msgstr "Erstellen"
#: templates/place/place_delete.html:5
msgid "Lost Place Deletion"
msgid "Delete lost place"
msgstr "Lost Place löschen"
#: templates/place/place_delete.html:15
msgid "Are you sure you want to delete"
msgstr "Willst Du den Ort wirklich löschen: "
#, python-format
msgid "Are you sure you want to delete %(place_name)s?"
msgstr "Bist Du sicher, dass Du %(place_name)s löschen möchtest?"
#: templates/place/place_delete.html:19
msgid "Delete"
@@ -293,17 +311,13 @@ msgid "Images"
msgstr "Bilder"
#: templates/place/place_list.html:10
msgid "Lost Places"
msgid "All Places"
msgstr "Alle Places"
#: templates/place/place_list.html:16
msgid "Listing our places"
msgid "Our lost places"
msgstr "Unsere Lost Places"
#: templates/place/place_update.html:5 templates/place/place_update.html:10
msgid "Update place"
msgstr "Place bearbeiten"
#: templates/place/place_update.html:42
msgid "Update"
msgstr "Aktualisieren"
@@ -313,13 +327,9 @@ msgid "Submit images to a place"
msgstr "Bilder zu einem Place hinzufügen"
#: templates/registration/login.html:29
msgid "Have No Account Yet?"
msgid "No account, yet?"
msgstr "Noch kein Konto?"
#: templates/signup.html:6
msgid "Sign up"
msgstr "Registrieren"
#: views/base_views.py:25
msgid "Please login to proceed"
msgstr "Bitte log Dich ein um fortzufahren"
@@ -329,49 +339,49 @@ 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"
msgid "Image deleted successfully"
msgstr "Bild 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"
msgstr "Place erfolgreich aktualisiert"
#: 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"
msgid "You are not allowed to edit this place"
msgstr "Du darfst diesen Place nicht bearbeiten"
#: views/place_views.py:97
#, fuzzy
#| msgid "Successfully deleted place"
msgid "Successfully created place"
msgstr "Place erfolgreich gelöscht"
msgstr "Place erfolgreich erstellt"
#: views/place_views.py:105
msgid "Please fill in all required fields."
msgstr "Bitte füll alle benötigten Felder aus."
#: 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"
msgid "You are not allowed to delete this place"
msgstr "Du darfst diesen Place nicht löschen"
#: views/views.py:29
msgid "User created"
msgstr "User erstellt"
msgstr "Benutzer erstellt"
#: views/views.py:54
msgid "Photo Album submitted"
msgstr "Fotoalbum hinzugefügt"
msgid "Photo album link submitted"
msgstr "Fotoalbum-Link hinzugefügt"
#: views/views.py:59
msgid "Photo Album deleted"
msgstr "Fotoalbum gelöscht"
msgid "Photo album link deleted"
msgstr "Fotoalbum-Link 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"
msgid "You are not allowed to edit this photo album link"
msgstr "Du darfst diesen Fotoalbum-Link nicht bearbeiten"

View File

@@ -19,4 +19,4 @@ class Migration(migrations.Migration):
migrations.DeleteModel(
name='Expireable'
)
]
]

View File

@@ -1,25 +1,25 @@
# Generated by Django 3.1.1 on 2020-10-04 19:52
# Generated by Django 3.1.1 on 2020-10-04 19:52
from django.db import migrations, models
from django.db import migrations, models
class Migration(migrations.Migration):
class Migration(migrations.Migration):
dependencies = [
('lostplaces', '0002_remove_vouchers'),
]
dependencies = [
('lostplaces', '0002_reomve_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,
},
),
]
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,
},
),
]

View File

@@ -53,13 +53,18 @@ class Submittable(models.Model):
class Meta:
abstract = True
submitted_when = models.DateTimeField(auto_now_add=True, null=True)
submitted_when = models.DateTimeField(
auto_now_add=True,
null=True,
verbose_name=_('Submission date')
)
submitted_by = models.ForeignKey(
'Explorer',
on_delete=models.SET_NULL,
null=True,
blank=True,
related_name='%(class)ss'
related_name='%(class)ss',
verbose_name=_('Submitter')
)
class Expireable(models.Model):
@@ -69,8 +74,13 @@ class Expireable(models.Model):
class Meta:
abstract = True
created_when = models.DateTimeField(auto_now_add=True)
expires_when = models.DateTimeField()
created_when = models.DateTimeField(
auto_now_add=True,
verbose_name=_('Creation date')
)
expires_when = models.DateTimeField(
verbose_name=_('Expiration date')
)
@property
def is_expired(self):

View File

@@ -14,6 +14,7 @@ from django.db.models.signals import post_save
from django.dispatch import receiver
from lostplaces.models.abstract_models import Expireable
from lostplaces.models.place import Place
class Explorer(models.Model):
"""
@@ -27,6 +28,13 @@ class Explorer(models.Model):
related_name='explorer'
)
favorite_places = models.ManyToManyField(
Place,
related_name='favorite_places',
verbose_name='Explorers favorite places',
blank=True
)
def __str__(self):
return self.user.username

View File

@@ -72,7 +72,7 @@ class PlaceAsset(Submittable):
null=True
)
class PlaceImage (Submittable):
class PlaceImage (PlaceAsset):
"""
PlaceImage defines an image file object that points to a file in uploads/.
Intermediate image sizes are generated as defined in THUMBNAIL_ALIASES.
@@ -138,4 +138,4 @@ def auto_delete_file_on_change(sender, instance, **kwargs):
new_file = instance.filename
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
os.remove(old_file.path)

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@@ -862,10 +862,9 @@ body {
margin: 0 3px; }
.LP-PlaceTeaser {
width: 280px; }
width: 100%; }
.LP-PlaceTeaser .LP-PlaceTeaser__Image {
height: 165px;
width: 280px;
width: 100%;
overflow: hidden; }
.LP-PlaceTeaser .LP-PlaceTeaser__Image .LP-Image {
max-width: unset;
@@ -873,6 +872,8 @@ body {
object-fit: cover; }
.LP-PlaceTeaser .LP-PlaceTeaser__Meta {
display: flex;
flex-wrap: wrap;
gap: 10px;
align-items: center;
justify-content: space-between;
padding: 5px;
@@ -883,19 +884,30 @@ body {
padding: 0;
margin: 0;
margin-top: 5px;
font-size: 0.9rem; }
font-size: 1.3rem; }
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Headline {
font-family: "Montserrat", Helvetica, sans-serif;
color: #565656;
font-size: 1rem;
font-size: 2rem;
padding: 0px;
margin: 0px; }
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Icon {
height: 2em;
width: 2em; }
.LP-PlaceTeaser .LP-PlaceTeaser__Description {
font-family: "Montserrat", Helvetica, sans-serif;
color: #565656;
display: none; }
order: 3;
flex-basis: 100%; }
.LP-PlaceTeaser .LP-PlaceTeaser__Description .LP-Paragraph {
font-size: 22px; }
@media (min-width: 650px) {
.LP-PlaceTeaser {
width: 280px; }
.LP-PlaceTeaser__Image {
width: 280px;
height: 165px; }
.LP-PlaceTeaser--extended {
display: flex;
flex-direction: row;
@@ -904,12 +916,15 @@ body {
height: 165px; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta {
margin: 0;
padding: 5px;
padding-left: 25px;
display: flex;
flex-wrap: nowrap;
flex-direction: column;
justify-content: space-between;
align-items: flex-start; }
align-items: flex-start;
gap: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Headline, .LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Paragraph {
font-size: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Info .LP-Headline {
font-size: 28px; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons {
@@ -917,10 +932,16 @@ body {
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons ul {
padding: 0;
margin: 0; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Icon {
height: 20px;
width: 20px; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description {
display: block;
max-height: 55px;
overflow: hidden; }
overflow: hidden;
order: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description .LP-Paragraph {
font-size: unset; }
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Image {
height: 165px;
width: 280px;
@@ -1006,6 +1027,31 @@ body {
.LP-MessageList .LP-MessageList__Item {
margin: 5px 0; }
.LP-UserInfo {
display: flex;
flex-direction: column;
background-color: #D7CEC7;
max-width: 400px;
width: 100%;
min-width: 300px; }
.LP-UserInfo__UserName {
background-color: #C09F80; }
.LP-UserInfo__UserName .LP-Headline {
color: black;
padding: 0;
margin: 0;
text-align: center;
padding: 5px;
font-size: 25px; }
.LP-UserInfo__Meta {
padding: 5px; }
.LP-UserInfo__Meta * {
font-family: "Montserrat", Helvetica, sans-serif;
font-size: 18px; }
.LP-UserInfo__Meta .LP-UserInfo__Key {
padding-right: 25px;
font-weight: bold; }
.LP-Header {
display: flex;
align-items: center;
@@ -1069,7 +1115,9 @@ body {
box-shadow: 0 0 2px #565656; }
.LP-PlaceList .LP-PlaceList__List {
list-style-type: none; }
list-style-type: none;
padding: 0;
margin: 0; }
.LP-PlaceList .LP-PlaceList__List .LP-Link .LP-Place:hover {
color: #565656;
background-color: #f9f9f9;
@@ -1080,6 +1128,10 @@ body {
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
max-width: 900px;
margin: 18px 0; }
@media (max-width: 750px) {
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
width: 100%;
margin-bottom: 35px; } }
.LP-PlaceList .LP-Pagination {
margin-top: 50px; }
@@ -1661,6 +1713,18 @@ body {
padding: .5em;
border-radius: 2px; }
.LP-UserProfile {
display: flex;
flex-direction: row; }
.LP-UserProfile__Bio {
flex-grow: 5;
flex-shrink: 10;
padding-right: 35px; }
.LP-UserProfile__Info {
flex-grow: 10;
flex-shrink: 1;
flex-basis: max-content; }
.LP-MainContainer {
margin: 0 auto;
max-width: 1280px; }
@@ -1673,8 +1737,9 @@ body {
width: 100%; } }
.LP-PlaceDetail .LP-PlaceDetail__Image {
width: 700px;
max-width: 700px;
max-height: 500px;
width: 50%;
box-shadow: 0 0 10px #565656;
box-shadow: 0 0 10px #565656;
object-fit: cover;
@@ -1682,15 +1747,16 @@ body {
margin: 0;
padding: 0;
float: right;
margin-left: 35px;
margin-bottom: 35px;
margin-right: 35px;
margin-left: 25px;
margin-bottom: 25px;
margin-right: 25px;
overflow: hidden; }
@media (max-width: 1000px) {
@media (max-width: 750px) {
.LP-PlaceDetail .LP-PlaceDetail__Header .LP-PlaceDetail__Image {
float: none;
width: 100%;
max-width: unset;
height: auto;
margin: 0;
padding: 0;

View File

@@ -0,0 +1,107 @@
{% extends 'global.html'%}
{% load static %}
{% load i18n %}
{% load svg_icon %}
{% block maincontent %}
<div class="LP-UserProfile">
<div class="LP-UserProfile__Info">
<div class="LP-UserInfo">
<div class="LP-UserInfo__UserName">
<h1 class="LP-Headline">{{explorer.user.username}}</h1>
</div>
<div class="LP-UserInfo__Meta">
<table>
<tr>
<td class="LP-UserInfo__Key">
<span class="LP-Paragraph">{% trans 'Joined' %}</span>
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">{{explorer.user.date_joined|date:'d.m.Y'}}</span>
</td>
</tr>
<tr>
<td class="LP-UserInfo__Key">
<span class="LP-Paragraph">{% trans 'Places'%}</span>
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">{{place_count}}</span>
</td>
</tr>
<tr>
<td class="LP-UserInfo__Key">
<span class="LP-Paragraph">{% trans 'Place Assets'%}</span>
</td>
<td class="LP-UserInfo__Value">
<span class="LP-Paragraph">{{asset_count}}</span>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<section class="LP-Section">
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Places submitted by' %} {{explorer.user.username}}</h1>
<ul class="LP-PlaceList__List">
{% for place in place_list %}
<li class="LP-PlaceList__Item">
{% include 'partials/place_teaser.html' with place=place extended=True %}
</li>
{% endfor %}
</ul>
{% include 'partials/nav/pagination.html' %}
</div>
</section>
<section class="LP-Section">
<h1 class="LP-Headline">{% trans 'Images submitted by' %} {{explorer.user.username}}</h1>
<div class="LP-ImageGrid">
<ul class="LP-ImageGrid__Container">
{% for place_image in assets.placeimages.all %}
<li class="LP-ImageGrid__Item">
<a href="{{ place_image.filename.large.url }}" class="LP-Link">
<img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}">
</a>
{% if user.explorer == place_image.submitted_by%}
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
<a href="{% url 'place_image_delete' pk=place_image.id %}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}" />
</a>
</span>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</section>
<section class=" LP-Section">
<h1 class="LP-Headline">{% trans 'Photo albums submitted by' %} {{explorer.user.username}}</h1>
<div class="LP-LinkList">
<ul class="LP-LinkList__Container">
{% for photo_album in assets.photoalbums.all %}
<li class="LP-LinkList__Item">
<a target="_blank" href="{{photo_album.url}}" class="LP-Link">
<span class="LP-Text">{{photo_album.label}}</span>
</a>
{% if user.explorer == photo_album.submitted_by%}
<a href="{% url 'photo_album_delete' pk=photo_album.pk%}" class="LP-Link LP-LinkList__ItemHover" title="Delete Photo Album">
<div class="RV-Iconized__Container RV-Iconized__Container--small">
{% icon 'trash' className="RV-Iconized__Icon" %}
</div>
</a>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
</section>
{% endblock maincontent %}

View File

@@ -29,15 +29,16 @@
<span class="LP-Paragraph">
{% if user.is_authenticated %}
Hi {{ user.username }}!
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">{% trans 'Logout' %}</span></a>
<a class="LP-Link" href="{% url 'logout' %}"><span class="LP-Link__Text">{% trans 'Logout' %}</span></a> |
<a class="LP-Link" href="{% url 'explorer_profile' explorer_id=user.pk%}"><span class="LP-Link__Text">{% trans 'Profile' %}</span></a>
{% if user.is_superuser %}
<a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">{% trans 'Admin' %}</span></a>
| <a class="LP-Link" href="{% url 'admin:index' %}" target="_blank"><span class="LP-Link__Text">{% trans 'Admin' %}</span></a>
{% endif %}
{% else %}
You are not logged in.
<a class="LP-Link" href="{% url 'login' %}"><span class="LP-Link__Text">{% trans 'Login' %}</span></a> |
<a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign Up' %}</span></a>
<a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign up' %}</span></a>
{% endif %}
</span>
</div>
@@ -53,8 +54,8 @@
{% block additional_menu_items %}
{% endblock additional_menu_items %}
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_create'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Create Place' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_list'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'All Places' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_create'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'Create place' %}</span></a></li>
<li class="LP-Menu__Item LP-Menu__Item--additional"><a href="{% url 'place_list'%}" class="LP-Link"><span class="LP-Link__Text">{% trans 'All places' %}</span></a></li>
</ul>
</nav>
</aside>

View File

@@ -21,30 +21,7 @@
<ul class="LP-PlaceGrid__Grid">
{% for place in place_list %}
<li class="LP-PlaceGrid__Item">
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
<article class="LP-PlaceTeaser">
<div class="LP-PlaceTeaser__Image">
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
</div>
<div class="LP-PlaceTeaser__Meta">
<div class="LP-PlaceTeaser__Info">
<span class="LP-PlaceTeaser__Title">
<h1 class="LP-Headline LP-Headline--teaser">{{place.name|truncatechars:19}}</h1>
</span>
<span class="LP-PlaceTeaser__Detail">
<p class="LP-Paragraph">{{place.location|truncatechars:25}}</p>
</span>
</div>
<div class="LP-PlaceTeaser__Icons">
<ul class="LP-Icon__List">
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/favourite.svg' %}" /></li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/location.svg' %}" /></li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li>
</ul>
</div>
</div>
</article>
</a>
{% include 'partials/place_teaser.html' with place=place%}
</li>
{% endfor %}
</ul>

View File

@@ -0,0 +1,14 @@
{%load static %}
{% load i18n %}
{% if request.user %}
{% if place in request.user.explorer.favorite_places.all %}
<a href="{% url 'place_unfavorite' place_id=place.id %}" class="LP-Link" title="{% trans 'Remove from favorites' %}">
<img class="LP-Icon" src="{% static '/icons/favourite_filled.svg' %}" />
</a>
{%else%}
<a href="{% url 'place_favorite' place_id=place.id %}" class="LP-Link" title="{% trans 'Save as favorite' %}">
<img class="LP-Icon" src="{% static '/icons/favourite.svg' %}" />
</a>
{% endif %}
{% endif %}

View File

@@ -0,0 +1,39 @@
{%load static %}
<article class="LP-PlaceTeaser {% if extended %} LP-PlaceTeaser--extended{% endif %}">
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
<div class="LP-PlaceTeaser__Image">
{% if place.placeimages.all|length > 0 %}
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url}}" />
{% else %}
<img class="LP-Image" src="{% static 'images/missing_image.png' %}" />
{% endif %}
</div>
</a>
<div class="LP-PlaceTeaser__Meta">
<div class="LP-PlaceTeaser__Info">
<span class="LP-PlaceTeaser__Title">
<h1 class="LP-Headline LP-Headline--teaser">{{place.name|truncatechars:19}}</h1>
</span>
<span class="LP-PlaceTeaser__Detail">
<p class="LP-Paragraph">{{place.location|truncatechars:25}}</p>
</span>
</div>
<div class="LP-PlaceTeaser__Description">
<p class="LP-Paragraph">
{% if place.description|length > 210 %}
{{place.description|truncatechars:210|truncatewords:-1}}
{% else %}
{{place.description}}
{% endif %}
</p>
</div>
<div class="LP-PlaceTeaser__Icons">
<ul class="LP-Icon__List">
<li class="LP-Icon__Item">{% include 'partials/icons/place_favorite.html' with place=place%}</li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/location.svg' %}" /></li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li>
</ul>
</div>
</div>
</article>

View File

@@ -2,12 +2,12 @@
{% load static %}
{% load i18n %}
# {% block title %}{% trans 'Create Place' %}{% endblock %}
# {% block title %}{% trans 'Create place' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Create Place' %}</legend>
<legend class="LP-Form__Legend">{% trans 'Create place' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">

View File

@@ -2,7 +2,7 @@
{% load static %}
{% load i18n %}
{% block title %}{% trans 'Lost Place Deletion' %}{% endblock %}
{% block title %}{% trans 'Delete lost place' %}{% endblock %}
{% block maincontent %}
@@ -12,7 +12,7 @@
{% csrf_token %}
<div class="LP-Form__Composition">
<div class="LP-Form__Field LP-Form__InfoText">
<p class="LP-Paragraph">{% trans 'Are you sure you want to delete' %} "{{place.name}}"?</p>
<p class="LP-Paragraph">{% blocktrans with place_name=place.name%}Are you sure you want to delete {{place_name}}?{% endblocktrans %}</p>
</div>
</div>

View File

@@ -4,7 +4,6 @@
{% load thumbnail %}
{% load svg_icon %}
{% load lostplaces %}
{% block additional_head %}
<link rel="stylesheet" href="{% static 'maps/ol.css' %}" type="text/css">
@@ -24,7 +23,7 @@
<article class="LP-PlaceDetail">
<header class="LP-PlaceDetail__Header">
<h1 class="LP-Headline">{{ place.name }}</h1>
<h1 class="LP-Headline">{{ place.name }} {% include 'partials/icons/place_favorite.html' %}</h1>
{% if place.placeimages.first.filename.hero.url %}
<figure class="LP-PlaceDetail__Image">
<img src="{{ place.placeimages.first.filename.hero.url }}" class="LP-Image" />
@@ -37,8 +36,10 @@
</div>
<section class="LP-Section">
{% url 'place_tag_submit' place_id=place.id as tag_submit_url%}
{% include 'partials/tagging.html' with config=tagging_config %}
</section>
<section class="LP-Section">
@@ -62,8 +63,7 @@
<a target="_blank" href="{{photo_album.url}}" class="LP-Link">
<span class="LP-Text">{{photo_album.label}}</span>
</a>
{% can_modify_place_asset photo_album request as authorized %}
{% if authorized %}
{% if user.explorer == photo_album.submitted_by or user.explorer == place.submitted_by %}
<a href="{% url 'photo_album_delete' pk=photo_album.pk%}" class="LP-Link LP-LinkList__ItemHover" title="Delete Photo Album">
<div class="RV-Iconized__Container RV-Iconized__Container--small">
{% icon 'trash' className="RV-Iconized__Icon" %}
@@ -98,8 +98,7 @@
<a href="{{ place_image.filename.large.url }}" class="LP-Link">
<img class="LP-Image" src="{{ place_image.filename.thumbnail.url }}">
</a>
{% can_modify_place_asset place_image request as authorized %}
{% if authorized %}
{% if user.explorer == place_image.submitted_by or user.explorer == place.submitted_by %}
<span class="LP-ImageGrid__DeleteItem" title="Bild löschen">
<a href="{% url 'place_image_delete' pk=place_image.id %}" class="LP-Link">
<img class="LP-Icon" src="{% static 'icons/cancel.svg' %}" />

View File

@@ -7,49 +7,17 @@
<script src="{% static 'maps/ol.js' %}"></script>
{% endblock additional_head %}
{% block title %}{% trans 'Lost Places' %}{% endblock %}
{% block title %}{% trans 'All Places' %}{% endblock %}
{% block maincontent %}
{% include 'partials/osm_map.html' with config=mapping_config %}
<div class="LP-PlaceList">
<h1 class="LP-Headline">{% trans 'Listing our places' %}</h1>
<h1 class="LP-Headline">{% trans 'Our lost places' %}</h1>
<ul class="LP-PlaceList__List">
{% for place in place_list %}
<li class="LP-PlaceList__Item">
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
<article class="LP-PlaceTeaser LP-PlaceTeaser--extended">
<div class="LP-PlaceTeaser__Image">
<img class="LP-Image" src="{{ place.placeimages.first.filename.thumbnail.url }}" />
</div>
<div class="LP-PlaceTeaser__Meta">
<div class="LP-PlaceTeaser__Info">
<span class="LP-PlaceTeaser__Title">
<h2 class="LP-Headline LP-Headline--teaser">{{place.name}}</h2>
</span>
<span class="LP-PlaceTeaser__Detail">
<p class="LP-Paragraph">{{place.location}}</p>
</span>
</div>
<div class="LP-PlaceTeaser__Description">
<p class="LP-Paragraph">
{% if place.description|length > 210 %}
{{place.description|truncatechars:210|truncatewords:-1}}
{% else %}
{{place.description}}
{% endif %}
</p>
</div>
<div class="LP-PlaceTeaser__Icons">
<ul class="LP-Icon__List">
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/favourite.svg' %}" /></li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/location.svg' %}" /></li>
<li class="LP-Icon__Item"><img class="LP-Icon" src="{% static '/icons/flag.svg' %}" /></li>
</ul>
</div>
</div>
</article>
</a>
{% include 'partials/place_teaser.html' with place=place extended=True %}
</li>
{% endfor %}
</ul>

View File

@@ -2,12 +2,12 @@
{% load static %}
{% load i18n %}
# {% block title %}{% trans 'Update place' %}{% endblock %}
# {% block title %}{% trans 'Edit place' %}{% endblock %}
{% block maincontent %}
<form class="LP-Form" method="POST" enctype="multipart/form-data">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Update place' %}</legend>
<legend class="LP-Form__Legend">{% trans 'Edit place' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">

View File

@@ -26,6 +26,6 @@
</fieldset>
</form>
<p class="LP-Headline">{% trans 'Have No Account Yet?' %} <a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign Up' %}</span></a></p>
<p class="LP-Headline">{% trans 'No account, yet?' %} <a class="LP-Link" href="{% url 'signup' %}"><span class="LP-Link__Text">{% trans 'Sign up' %}</span></a></p>
{% endblock maincontent %}

View File

@@ -9,7 +9,7 @@
<form class="LP-Form" method="POST">
<fieldset class="LP-Form__Fieldset">
<legend class="LP-Form__Legend">{% trans 'Sign Up' %}</legend>
<legend class="LP-Form__Legend">{% trans 'Sign up' %}</legend>
{% csrf_token %}
<div class="LP-Form__Composition LP-Form__Composition--breakable">
<div class="LP-Form__Field">
@@ -38,7 +38,7 @@
<div class="LP-Form__Composition LP-Form__Composition--buttons">
<div class="LP-Form__Field LP-Form__Button LP-Input">
<button class="LP-Button">{% trans 'Sign Up' %}</button>
<button class="LP-Button">{% trans 'Sign up' %}</button>
</div>
</div>
</fieldset>

View File

@@ -24,13 +24,3 @@ def proper_paginate(paginator, current_page, neighbors=2):
page_list = [f for f in range(start_index, end_index+1)]
return page_list[:(2*neighbors + 1)]
return paginator.page_range
@register.simple_tag
def can_modify_place_asset(place_asset, request, *args, **kwargs):
print(place_asset.place.submitted_by, place_asset.submitted_by, request.user)
if request.user.is_superuser:
return True
if request.user.explorer == place_asset.place.submitted_by or request.user.explorer == place_asset.submitted_by:
return True
else:
return False

View File

@@ -11,11 +11,14 @@ from lostplaces.views import (
PlaceDeleteView,
PlaceTagDeleteView,
PlaceTagSubmitView,
PlaceFavoriteView,
PlaceUnfavoriteView,
PhotoAlbumCreateView,
PhotoAlbumDeleteView,
PlaceImageCreateView,
PlaceImageDeleteView,
FlatView
FlatView,
ExplorerProfileView
)
urlpatterns = [
@@ -33,5 +36,12 @@ urlpatterns = [
# POST-only URLs for tag submission
path('place/tag/<int:tagged_id>', PlaceTagSubmitView.as_view(), name='place_tag_submit'),
path('place/tag/delete/<int:tagged_id>/<int:tag_id>', PlaceTagDeleteView.as_view(), name='place_tag_delete')
path('place/tag/delete/<int:tagged_id>/<int:tag_id>', PlaceTagDeleteView.as_view(), name='place_tag_delete'),
path('explorer/<int:explorer_id>/', ExplorerProfileView.as_view(), name='explorer_profile'),
path('explorer/favorite/<int:place_id>/', PlaceFavoriteView.as_view(), name='place_favorite'),
path('explorer/unfavorite/<int:place_id>/', PlaceUnfavoriteView.as_view(), name='place_unfavorite')
]

View File

@@ -4,4 +4,5 @@
from lostplaces.views.base_views import *
from lostplaces.views.views import *
from lostplaces.views.place_views import *
from lostplaces.views.place_image_views import *
from lostplaces.views.place_image_views import *
from lostplaces.views.explorer_views import *

View File

@@ -0,0 +1,45 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from django.views import View
from django.utils.translation import ugettext_lazy as _
from django.shortcuts import render, redirect, get_object_or_404
from django.urls import reverse_lazy
from lostplaces.common import get_all_subclasses
from lostplaces.views.base_views import IsAuthenticatedMixin
from lostplaces.models.models import Explorer
from lostplaces.models.place import Place, PlaceAsset
class ExplorerProfileView(IsAuthenticatedMixin, View):
def get(self, request, explorer_id):
explorer = get_object_or_404(Explorer, pk=explorer_id)
place_list = Place.objects.filter(submitted_by=explorer)
place_count = place_list.count()
context={
'explorer': explorer,
'place_count': place_count,
'place_list': place_list,
'assets': {}
}
asset_count = 0
for subclass in get_all_subclasses(PlaceAsset): # kinda ugly, but PlaceAsset cannot be abstract according to django ORM
objects = subclass.objects.filter(submitted_by=explorer)
context['assets'][subclass.__name__.lower()+'s'] = objects
asset_count += objects.count()
context['asset_count'] = asset_count
print(context['assets'])
return render(
request=request,
template_name='explorer/profile.html',
context=context
)

View File

@@ -38,5 +38,5 @@ class PlaceImageCreateView(MultiplePlaceImageUploadMixin, PlaceAssetCreateView):
class PlaceImageDeleteView(PlaceAssetDeleteView):
model = PlaceImage
success_message = _('Image(s) deleted successfully')
success_message = _('Image deleted successfully')
permission_denied_message = _('You are not allowed to delete this image')

View File

@@ -60,7 +60,7 @@ class PlaceUpdateView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, SuccessMessag
model = Place
form_class = PlaceForm
success_message = _('Successfully updated place')
place_submitter_error_message = _('You do no have permissions to alter this place')
place_submitter_error_message = _('You are not allowed to edit this place')
def get_success_url(self):
return reverse_lazy('place_detail', kwargs={'pk':self.get_object().pk})
@@ -102,7 +102,7 @@ class PlaceCreateView(MultiplePlaceImageUploadMixin, IsAuthenticatedMixin, View)
# Usually the browser should have checked the form before sending.
messages.error(
self.request,
'Please fill in all required fields.'
_('Please fill in all required fields.')
)
return render(request, 'place/place_create.html', context={'form': place_form})
@@ -111,7 +111,7 @@ class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView):
model = Place
success_message = _('Successfully deleted place')
success_url = reverse_lazy('place_list')
place_submitter_error_message = _('You do no have permission to delete this place')
place_submitter_error_message = _('You are not allowed to delete this place')
def delete(self, request, *args, **kwargs):
messages.success(self.request, self.success_message)
@@ -119,3 +119,35 @@ class PlaceDeleteView(IsAuthenticatedMixin, IsPlaceSubmitterMixin, DeleteView):
def get_place(self):
return self.get_object()
class PlaceFavoriteView(IsAuthenticatedMixin, View):
def get(self, request, place_id):
place = get_object_or_404(Place, id=place_id)
if request.user is not None:
request.user.explorer.favorite_places.add(place)
request.user.explorer.save()
referer = request.META.get('HTTP_REFERER')
if referer is not None:
return redirect(referer)
else:
return redirect(
reverse_lazy('place_detail', kwargs={'pk': place.pk})
)
class PlaceUnfavoriteView(IsAuthenticatedMixin, View):
def get(self, request, place_id):
place = get_object_or_404(Place, id=place_id)
if request.user is not None:
request.user.explorer.favorite_places.remove(place)
request.user.explorer.save()
referer = request.META.get('HTTP_REFERER')
if referer is not None:
return redirect(referer)
else:
return redirect(
reverse_lazy('place_detail', kwargs={'pk': place.pk})
)

View File

@@ -51,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 link 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 link deleted')
permission_denied_messsage = _('You are not allowed to edit this photo album link')
class PlaceTagSubmitView(IsAuthenticatedMixin, View):
def post(self, request, tagged_id, *args, **kwargs):

View File

@@ -1,8 +0,0 @@
# Config options for coverage
# Docs: https://coverage.readthedocs.io/en/latest/config.html
[coverage:run]
source = .
[coverage:report]
show_missing = True

9
setup.py → django_lostplaces/setup.py Normal file → Executable file
View File

@@ -1,9 +1,9 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from setuptools import setup, find_packages
with open('Readme.md') as f:
with open('../Readme.md') as f:
readme = f.read()
setup(
@@ -13,7 +13,7 @@ setup(
author='Reverend',
author_email='reverend@reverend2048.de',
url='https://git.mowoe.com/reverend/lostplaces-backend',
packages=find_packages(exclude=['lostplaces']),
packages=find_packages(exclude=['django_lostplaces']),
long_description=readme,
long_description_content_type='text/markdown',
classifiers=[
@@ -31,5 +31,6 @@ setup(
'django-widget-tweaks',
'django-taggit'
],
include_package_data=True
include_package_data=True,
license='MIT'
)