Compare commits
6 Commits
cd20e730ba
...
3c5b447d4c
Author | SHA1 | Date | |
---|---|---|---|
3c5b447d4c | |||
cfbb876d2c | |||
4e0bfef483 | |||
ccdb49c8ea | |||
90dd281f7c | |||
d9df6e67a8 |
11
django_lostplaces/lostplaces/common.py
Normal file
11
django_lostplaces/lostplaces/common.py
Normal 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
|
@ -1,4 +1,4 @@
|
|||||||
# Generated by Django 3.1.1 on 2020-09-28 18:39
|
# Generated by Django 3.1.1 on 2020-11-29 17:46
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
@ -14,19 +14,11 @@ class Migration(migrations.Migration):
|
|||||||
initial = True
|
initial = True
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
|
||||||
('taggit', '0003_taggeditem_add_unique_index'),
|
('taggit', '0003_taggeditem_add_unique_index'),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.CreateModel(
|
|
||||||
name='Expireable',
|
|
||||||
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()),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Explorer',
|
name='Explorer',
|
||||||
fields=[
|
fields=[
|
||||||
@ -38,13 +30,13 @@ class Migration(migrations.Migration):
|
|||||||
name='Place',
|
name='Place',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('name', models.CharField(max_length=50)),
|
('name', models.CharField(max_length=50, verbose_name='Name')),
|
||||||
('latitude', models.FloatField(validators=[django.core.validators.MinValueValidator(-90), django.core.validators.MaxValueValidator(90)])),
|
('latitude', 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')),
|
||||||
('longitude', models.FloatField(validators=[django.core.validators.MinValueValidator(-180), django.core.validators.MaxValueValidator(180)])),
|
('longitude', 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')),
|
||||||
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
|
('submitted_when', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date')),
|
||||||
('location', models.CharField(max_length=50)),
|
('location', models.CharField(max_length=50, verbose_name='Location')),
|
||||||
('description', models.TextField()),
|
('description', 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')),
|
||||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='places', to='lostplaces.explorer')),
|
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='places', to='lostplaces.explorer', verbose_name='Submitter')),
|
||||||
('tags', taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
|
('tags', taggit.managers.TaggableManager(blank=True, help_text='A comma-separated list of tags.', through='taggit.TaggedItem', to='taggit.Tag', verbose_name='Tags')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
@ -54,20 +46,24 @@ class Migration(migrations.Migration):
|
|||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='Voucher',
|
name='Voucher',
|
||||||
fields=[
|
fields=[
|
||||||
('expireable_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='lostplaces.expireable')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
('created_when', models.DateTimeField(auto_now_add=True, verbose_name='Creation date')),
|
||||||
|
('expires_when', models.DateTimeField(verbose_name='Expiration date')),
|
||||||
('code', models.CharField(max_length=30, unique=True)),
|
('code', models.CharField(max_length=30, unique=True)),
|
||||||
],
|
],
|
||||||
bases=('lostplaces.expireable',),
|
options={
|
||||||
|
'abstract': False,
|
||||||
|
},
|
||||||
),
|
),
|
||||||
migrations.CreateModel(
|
migrations.CreateModel(
|
||||||
name='PlaceImage',
|
name='PlaceImage',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
|
('submitted_when', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date')),
|
||||||
('description', models.TextField(blank=True)),
|
('description', models.TextField(blank=True, verbose_name='Description')),
|
||||||
('filename', easy_thumbnails.fields.ThumbnailerImageField(upload_to=lostplaces.models.place.generate_image_upload_path)),
|
('filename', easy_thumbnails.fields.ThumbnailerImageField(help_text='Optional: One or more images to upload', upload_to=lostplaces.models.place.generate_image_upload_path, verbose_name='Filename(s)')),
|
||||||
('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='placeimages', to='lostplaces.place')),
|
('place', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='placeimages', to='lostplaces.place')),
|
||||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer')),
|
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='placeimages', to='lostplaces.explorer', verbose_name='Submitter')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'abstract': False,
|
'abstract': False,
|
||||||
@ -77,11 +73,11 @@ class Migration(migrations.Migration):
|
|||||||
name='PhotoAlbum',
|
name='PhotoAlbum',
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
('submitted_when', models.DateTimeField(auto_now_add=True, null=True)),
|
('submitted_when', models.DateTimeField(auto_now_add=True, null=True, verbose_name='Submission date')),
|
||||||
('url', models.URLField()),
|
('url', models.URLField(verbose_name='URL')),
|
||||||
('label', models.CharField(max_length=100)),
|
('label', models.CharField(max_length=100, verbose_name='link text')),
|
||||||
('place', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='photoalbums', to='lostplaces.place')),
|
('place', models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, related_name='photoalbums', to='lostplaces.place')),
|
||||||
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='photoalbums', to='lostplaces.explorer')),
|
('submitted_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='photoalbums', to='lostplaces.explorer', verbose_name='Submitter')),
|
||||||
],
|
],
|
||||||
options={
|
options={
|
||||||
'abstract': False,
|
'abstract': False,
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
# 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'
|
|
||||||
)
|
|
||||||
]
|
|
@ -1,25 +0,0 @@
|
|||||||
# 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,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
]
|
|
@ -72,7 +72,7 @@ class PlaceAsset(Submittable):
|
|||||||
null=True
|
null=True
|
||||||
)
|
)
|
||||||
|
|
||||||
class PlaceImage (Submittable):
|
class PlaceImage (PlaceAsset):
|
||||||
"""
|
"""
|
||||||
PlaceImage defines an image file object that points to a file in uploads/.
|
PlaceImage defines an image file object that points to a file in uploads/.
|
||||||
Intermediate image sizes are generated as defined in THUMBNAIL_ALIASES.
|
Intermediate image sizes are generated as defined in THUMBNAIL_ALIASES.
|
||||||
|
@ -862,10 +862,9 @@ body {
|
|||||||
margin: 0 3px; }
|
margin: 0 3px; }
|
||||||
|
|
||||||
.LP-PlaceTeaser {
|
.LP-PlaceTeaser {
|
||||||
width: 280px; }
|
width: 100%; }
|
||||||
.LP-PlaceTeaser .LP-PlaceTeaser__Image {
|
.LP-PlaceTeaser .LP-PlaceTeaser__Image {
|
||||||
height: 165px;
|
width: 100%;
|
||||||
width: 280px;
|
|
||||||
overflow: hidden; }
|
overflow: hidden; }
|
||||||
.LP-PlaceTeaser .LP-PlaceTeaser__Image .LP-Image {
|
.LP-PlaceTeaser .LP-PlaceTeaser__Image .LP-Image {
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
@ -873,6 +872,8 @@ body {
|
|||||||
object-fit: cover; }
|
object-fit: cover; }
|
||||||
.LP-PlaceTeaser .LP-PlaceTeaser__Meta {
|
.LP-PlaceTeaser .LP-PlaceTeaser__Meta {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
@ -883,19 +884,30 @@ body {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
font-size: 0.9rem; }
|
font-size: 1.3rem; }
|
||||||
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Headline {
|
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Headline {
|
||||||
font-family: "Montserrat", Helvetica, sans-serif;
|
font-family: "Montserrat", Helvetica, sans-serif;
|
||||||
color: #565656;
|
color: #565656;
|
||||||
font-size: 1rem;
|
font-size: 2rem;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
margin: 0px; }
|
margin: 0px; }
|
||||||
|
.LP-PlaceTeaser .LP-PlaceTeaser__Meta .LP-Icon {
|
||||||
|
height: 2em;
|
||||||
|
width: 2em; }
|
||||||
.LP-PlaceTeaser .LP-PlaceTeaser__Description {
|
.LP-PlaceTeaser .LP-PlaceTeaser__Description {
|
||||||
font-family: "Montserrat", Helvetica, sans-serif;
|
font-family: "Montserrat", Helvetica, sans-serif;
|
||||||
color: #565656;
|
color: #565656;
|
||||||
display: none; }
|
order: 3;
|
||||||
|
flex-basis: 100%; }
|
||||||
|
.LP-PlaceTeaser .LP-PlaceTeaser__Description .LP-Paragraph {
|
||||||
|
font-size: 22px; }
|
||||||
|
|
||||||
@media (min-width: 650px) {
|
@media (min-width: 650px) {
|
||||||
|
.LP-PlaceTeaser {
|
||||||
|
width: 280px; }
|
||||||
|
.LP-PlaceTeaser__Image {
|
||||||
|
width: 280px;
|
||||||
|
height: 165px; }
|
||||||
.LP-PlaceTeaser--extended {
|
.LP-PlaceTeaser--extended {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -904,12 +916,15 @@ body {
|
|||||||
height: 165px; }
|
height: 165px; }
|
||||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta {
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 5px;
|
|
||||||
padding-left: 25px;
|
padding-left: 25px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: space-between;
|
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 {
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Info .LP-Headline {
|
||||||
font-size: 28px; }
|
font-size: 28px; }
|
||||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons {
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons {
|
||||||
@ -917,10 +932,16 @@ body {
|
|||||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons ul {
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-PlaceTeaser__Icons ul {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0; }
|
margin: 0; }
|
||||||
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Meta .LP-Icon {
|
||||||
|
height: 20px;
|
||||||
|
width: 20px; }
|
||||||
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description {
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Description {
|
||||||
display: block;
|
display: block;
|
||||||
max-height: 55px;
|
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 {
|
.LP-PlaceTeaser--extended .LP-PlaceTeaser__Image {
|
||||||
height: 165px;
|
height: 165px;
|
||||||
width: 280px;
|
width: 280px;
|
||||||
@ -1006,6 +1027,31 @@ body {
|
|||||||
.LP-MessageList .LP-MessageList__Item {
|
.LP-MessageList .LP-MessageList__Item {
|
||||||
margin: 5px 0; }
|
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 {
|
.LP-Header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -1069,7 +1115,9 @@ body {
|
|||||||
box-shadow: 0 0 2px #565656; }
|
box-shadow: 0 0 2px #565656; }
|
||||||
|
|
||||||
.LP-PlaceList .LP-PlaceList__List {
|
.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 {
|
.LP-PlaceList .LP-PlaceList__List .LP-Link .LP-Place:hover {
|
||||||
color: #565656;
|
color: #565656;
|
||||||
background-color: #f9f9f9;
|
background-color: #f9f9f9;
|
||||||
@ -1080,6 +1128,10 @@ body {
|
|||||||
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
||||||
max-width: 900px;
|
max-width: 900px;
|
||||||
margin: 18px 0; }
|
margin: 18px 0; }
|
||||||
|
@media (max-width: 750px) {
|
||||||
|
.LP-PlaceList .LP-PlaceList__List .LP-PlaceList__Item {
|
||||||
|
width: 100%;
|
||||||
|
margin-bottom: 35px; } }
|
||||||
|
|
||||||
.LP-PlaceList .LP-Pagination {
|
.LP-PlaceList .LP-Pagination {
|
||||||
margin-top: 50px; }
|
margin-top: 50px; }
|
||||||
@ -1661,6 +1713,18 @@ body {
|
|||||||
padding: .5em;
|
padding: .5em;
|
||||||
border-radius: 2px; }
|
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 {
|
.LP-MainContainer {
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
max-width: 1280px; }
|
max-width: 1280px; }
|
||||||
@ -1673,8 +1737,9 @@ body {
|
|||||||
width: 100%; } }
|
width: 100%; } }
|
||||||
|
|
||||||
.LP-PlaceDetail .LP-PlaceDetail__Image {
|
.LP-PlaceDetail .LP-PlaceDetail__Image {
|
||||||
width: 700px;
|
max-width: 700px;
|
||||||
max-height: 500px;
|
max-height: 500px;
|
||||||
|
width: 50%;
|
||||||
box-shadow: 0 0 10px #565656;
|
box-shadow: 0 0 10px #565656;
|
||||||
box-shadow: 0 0 10px #565656;
|
box-shadow: 0 0 10px #565656;
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
@ -1682,15 +1747,16 @@ body {
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
float: right;
|
float: right;
|
||||||
margin-left: 35px;
|
margin-left: 25px;
|
||||||
margin-bottom: 35px;
|
margin-bottom: 25px;
|
||||||
margin-right: 35px;
|
margin-right: 25px;
|
||||||
overflow: hidden; }
|
overflow: hidden; }
|
||||||
|
|
||||||
@media (max-width: 1000px) {
|
@media (max-width: 750px) {
|
||||||
.LP-PlaceDetail .LP-PlaceDetail__Header .LP-PlaceDetail__Image {
|
.LP-PlaceDetail .LP-PlaceDetail__Header .LP-PlaceDetail__Image {
|
||||||
float: none;
|
float: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
max-width: unset;
|
||||||
height: auto;
|
height: auto;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
109
django_lostplaces/lostplaces/templates/explorer/profile.html
Normal file
109
django_lostplaces/lostplaces/templates/explorer/profile.html
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
{% 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">
|
||||||
|
<a href="{% url 'place_detail' pk=place.pk %}" class="LP-Link">
|
||||||
|
{% include 'partials/place_teaser.html' with place=place extended=True %}
|
||||||
|
</a>
|
||||||
|
</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 %}
|
@ -29,9 +29,10 @@
|
|||||||
<span class="LP-Paragraph">
|
<span class="LP-Paragraph">
|
||||||
{% if user.is_authenticated %}
|
{% if user.is_authenticated %}
|
||||||
Hi {{ user.username }}!
|
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 %}
|
{% 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 %}
|
{% endif %}
|
||||||
|
|
||||||
{% else %}
|
{% else %}
|
||||||
|
@ -15,7 +15,8 @@ from lostplaces.views import (
|
|||||||
PhotoAlbumDeleteView,
|
PhotoAlbumDeleteView,
|
||||||
PlaceImageCreateView,
|
PlaceImageCreateView,
|
||||||
PlaceImageDeleteView,
|
PlaceImageDeleteView,
|
||||||
FlatView
|
FlatView,
|
||||||
|
ExplorerProfileView
|
||||||
)
|
)
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
@ -33,5 +34,7 @@ urlpatterns = [
|
|||||||
|
|
||||||
# POST-only URLs for tag submission
|
# POST-only URLs for tag submission
|
||||||
path('place/tag/<int:tagged_id>', PlaceTagSubmitView.as_view(), name='place_tag_submit'),
|
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')
|
||||||
]
|
]
|
||||||
|
@ -4,4 +4,5 @@
|
|||||||
from lostplaces.views.base_views import *
|
from lostplaces.views.base_views import *
|
||||||
from lostplaces.views.views import *
|
from lostplaces.views.views import *
|
||||||
from lostplaces.views.place_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 *
|
45
django_lostplaces/lostplaces/views/explorer_views.py
Normal file
45
django_lostplaces/lostplaces/views/explorer_views.py
Normal 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
|
||||||
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user