summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/books/models.py7
-rw-r--r--app/figments/models.py2
-rw-r--r--app/jrnl/build.py5
-rw-r--r--app/jrnl/migrations/0001_initial.py1
-rw-r--r--app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py86
-rw-r--r--app/jrnl/migrations/0022_auto_20180707_0958.py19
-rw-r--r--app/jrnl/models.py92
-rw-r--r--app/links/models.py2
-rw-r--r--app/locations/admin.py56
-rw-r--r--app/locations/migrations/0007_campsite.py37
-rw-r--r--app/locations/migrations/0008_campsite_name.py19
-rw-r--r--app/locations/migrations/0009_auto_20180707_1403.py19
-rw-r--r--app/locations/models.py65
-rw-r--r--app/notes/models.py3
-rw-r--r--app/pages/models.py7
-rw-r--r--app/people/models.py2
-rw-r--r--app/photos/models.py17
-rw-r--r--app/photos/utils.py9
-rw-r--r--app/projects/models/base.py2
-rw-r--r--app/resume/models.py2
-rw-r--r--app/sightings/migrations/0006_auto_20180707_0958.py24
-rw-r--r--app/sightings/models.py5
-rw-r--r--app/sketches/models.py5
-rw-r--r--app/src/migrations/0003_auto_20180707_0958.py17
-rw-r--r--app/src/models.py3
-rw-r--r--app/utils/util.py93
-rw-r--r--app/utils/widgets.py79
27 files changed, 485 insertions, 193 deletions
diff --git a/app/books/models.py b/app/books/models.py
index 2aecaef..8e381ef 100644
--- a/app/books/models.py
+++ b/app/books/models.py
@@ -1,5 +1,4 @@
import os
-import datetime
from PIL import Image
from django.db import models
from django.db.models.signals import post_save
@@ -11,7 +10,7 @@ from django.conf import settings
from django.template.defaultfilters import slugify
from photos.utils import resize_image
-from utils.widgets import markdown_to_html
+from utils.util import markdown_to_html
def get_upload_path(self, filename):
@@ -115,7 +114,3 @@ class BookHighlight(models.Model):
def body_html(self):
return markdown_to_html(self.body_markdown)
-
-
-class BookNote(BookHighlight):
- pass
diff --git a/app/figments/models.py b/app/figments/models.py
index 69cf9a0..d871f4d 100644
--- a/app/figments/models.py
+++ b/app/figments/models.py
@@ -7,7 +7,7 @@ from django.contrib.syndication.views import Feed
from django.db.models.signals import post_save
from django.dispatch import receiver
-from utils.widgets import markdown_to_html
+from utils.util import markdown_to_html
from .ebook import generate_epub_file
diff --git a/app/jrnl/build.py b/app/jrnl/build.py
index 5b5d929..0b3826a 100644
--- a/app/jrnl/build.py
+++ b/app/jrnl/build.py
@@ -5,6 +5,7 @@ from itertools import chain
from django.conf import settings
+
class BuildJrnl(BuildNew):
def build(self):
@@ -58,7 +59,7 @@ class BuildJrnl(BuildNew):
def build_homepage(self):
response = self.client.get('/')
self.write_file('', response.content)
-
+
def build_latest(self):
response = self.client.get('/jrnl/latest/')
self.write_file(reverse("jrnl:latest"), response.content)
@@ -72,7 +73,6 @@ class BuildJrnl(BuildNew):
self.write_file("media/js/mainmap", response.content, 'js', '')
-
def archive_builder():
j = BuildJrnl("jrnl", "entry")
j.build_arc()
@@ -93,6 +93,7 @@ def rss_builder():
j = BuildJrnl("jrnl", "entry")
j.build_feed("jrnl:feed")
+
def map_builder():
j = BuildJrnl("jrnl", "entry")
j.build_map()
diff --git a/app/jrnl/migrations/0001_initial.py b/app/jrnl/migrations/0001_initial.py
index 7938b94..a3660ab 100644
--- a/app/jrnl/migrations/0001_initial.py
+++ b/app/jrnl/migrations/0001_initial.py
@@ -32,7 +32,6 @@ class Migration(migrations.Migration):
('point', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)),
('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Published')], default=0)),
('image', models.FileField(blank=True, help_text='should be 205px high', null=True, upload_to=jrnl.models.get_upload_path)),
- ('thumbnail', models.FileField(blank=True, help_text='should be 160 wide', null=True, upload_to=jrnl.models.get_tn_path)),
('meta_description', models.CharField(blank=True, max_length=256, null=True)),
('template_name', models.IntegerField(choices=[(0, 'single'), (1, 'double'), (2, 'single-dark'), (3, 'double-dark'), (4, 'bigimg'), (5, 'bigimg-dark')], default=0)),
('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='locations.Location')),
diff --git a/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py b/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py
new file mode 100644
index 0000000..1a16b24
--- /dev/null
+++ b/app/jrnl/migrations/0001_squashed_0019_remove_entry_thumbnail.py
@@ -0,0 +1,86 @@
+# Generated by Django 2.0.1 on 2018-07-07 15:30
+
+import django.contrib.gis.db.models.fields
+from django.db import migrations, models
+import django.db.models.deletion
+import jrnl.models
+
+
+class Migration(migrations.Migration):
+
+ replaces = [('jrnl', '0001_initial'), ('jrnl', '0002_entrytitlesong'), ('jrnl', '0003_auto_20160309_1018'), ('jrnl', '0004_auto_20160309_1031'), ('jrnl', '0005_auto_20160514_2151'), ('jrnl', '0006_auto_20160715_0703'), ('jrnl', '0007_delete_postimage'), ('jrnl', '0008_auto_20160906_0845'), ('jrnl', '0009_homepagecurrator_image_offset_vertical'), ('jrnl', '0010_auto_20161102_0916'), ('jrnl', '0011_auto_20161102_0925'), ('jrnl', '0012_auto_20161102_0930'), ('jrnl', '0013_entry_featured_image'), ('jrnl', '0014_homepagecurrator'), ('jrnl', '0015_entry_has_video'), ('jrnl', '0016_auto_20161219_1058'), ('jrnl', '0017_entry_field_notes'), ('jrnl', '0018_auto_20180303_1037'), ('jrnl', '0019_remove_entry_thumbnail')]
+
+ initial = True
+
+ dependencies = [
+ ('photos', '0016_auto_20161022_1411'),
+ ('sketches', '0002_auto_20180208_0743'),
+ ('books', '0005_auto_20171214_2239'),
+ ('photos', '0010_auto_20160517_0906'),
+ ('photos', '0003_luxgallery_caption_style'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Entry',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=200)),
+ ('slug', models.SlugField(unique_for_date='pub_date')),
+ ('body_html', models.TextField(blank=True)),
+ ('body_markdown', models.TextField()),
+ ('dek', models.TextField(blank=True, null=True)),
+ ('pub_date', models.DateTimeField(verbose_name='Date published')),
+ ('enable_comments', models.BooleanField(default=False)),
+ ('point', django.contrib.gis.db.models.fields.PointField(blank=True, null=True, srid=4326)),
+ ('status', models.IntegerField(choices=[(0, 'Draft'), (1, 'Published')], default=0)),
+ ('image', models.FileField(blank=True, help_text='should be 205px high by 364px wide', null=True, upload_to=jrnl.models.get_upload_path)),
+ ('meta_description', models.CharField(blank=True, max_length=256, null=True)),
+ ('template_name', models.IntegerField(choices=[(0, 'single'), (1, 'double'), (2, 'single-dark'), (3, 'double-dark'), (4, 'single-black'), (5, 'double-black')], default=0)),
+ ('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='locations.Location')),
+ ('photo_gallery', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='photos.PhotoGallery', verbose_name='photo set')),
+ ('featured_image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='photos.LuxImage')),
+ ],
+ options={
+ 'verbose_name_plural': 'entries',
+ 'get_latest_by': 'pub_date',
+ 'ordering': ('-pub_date',),
+ },
+ ),
+ migrations.CreateModel(
+ name='HomepageCurrator',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('image_offset_vertical', models.CharField(help_text='add negative top margin to shift image (include css unit)', max_length=20)),
+ ('tag_line', models.CharField(max_length=200)),
+ ('template_name', models.CharField(help_text='full path', max_length=200)),
+ ('featured', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='banner', to='jrnl.Entry')),
+ ('images', models.ManyToManyField(to='photos.LuxImage')),
+ ('popular', models.ManyToManyField(to='jrnl.Entry')),
+ ],
+ ),
+ migrations.AddField(
+ model_name='entry',
+ name='has_video',
+ field=models.BooleanField(default=False),
+ ),
+ migrations.AlterField(
+ model_name='entry',
+ name='image',
+ field=models.FileField(blank=True, help_text='should be 520 by 290', null=True, upload_to=jrnl.models.get_upload_path),
+ ),
+ migrations.AddField(
+ model_name='entry',
+ name='field_notes',
+ field=models.ManyToManyField(blank=True, to='sketches.Sketch'),
+ ),
+ migrations.AddField(
+ model_name='entry',
+ name='books',
+ field=models.ManyToManyField(blank=True, to='books.Book'),
+ ),
+ migrations.RemoveField(
+ model_name='entry',
+ name='thumbnail',
+ ),
+ ]
diff --git a/app/jrnl/migrations/0022_auto_20180707_0958.py b/app/jrnl/migrations/0022_auto_20180707_0958.py
new file mode 100644
index 0000000..809f562
--- /dev/null
+++ b/app/jrnl/migrations/0022_auto_20180707_0958.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.0.1 on 2018-07-07 09:58
+
+from django.db import migrations, models
+import jrnl.models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('jrnl', '0021_auto_20180606_1058'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='entry',
+ name='image',
+ field=models.FileField(blank=True, help_text='should be 520 by 290', upload_to=jrnl.models.get_upload_path),
+ ),
+ ]
diff --git a/app/jrnl/models.py b/app/jrnl/models.py
index 174b391..522764d 100644
--- a/app/jrnl/models.py
+++ b/app/jrnl/models.py
@@ -1,65 +1,39 @@
import datetime
import os
-import re
-from PIL import Image
-from django.db.models.signals import post_save
-from django.dispatch import receiver
+from django.dispatch import receiver
from django.contrib.gis.db import models
-from django.utils.html import format_html
from django.urls import reverse
from django.apps import apps
-from django.template.loader import render_to_string
from django.conf import settings
-from django.template import Context
-from django.contrib.syndication.views import Feed
from django.contrib.sitemaps import Sitemap
from django import forms
-from django.template.defaultfilters import slugify
-# http://freewisdom.org/projects/python-markdown/
-import markdown
-from bs4 import BeautifulSoup
+import urllib.request
+import urllib.parse
+import urllib.error
+from django_gravatar.helpers import get_gravatar_url, has_gravatar, calculate_gravatar_hash
+from django_comments.signals import comment_was_posted
+from django_comments.models import Comment
+from django_comments.moderation import CommentModerator, moderator
from photos.models import PhotoGallery, LuxImage, LuxImageSize
-from photos.utils import resize_image
from locations.models import Location
from sketches.models import Sketch
from books.models import Book
-from utils.widgets import parse_image, parse_video
-from utils.widgets import markdown_to_html
+from utils.util import render_images, parse_video, markdown_to_html
def get_upload_path(self, filename):
return "images/post-images/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename)
-def get_tn_path(self, filename):
- return "images/post-thumbnail/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename)
-
-
def image_url_replace(s):
s = s.replace('[[base_url]]', settings.IMAGES_URL)
return s
-def render_images(s):
- s = re.sub('<img(.*)/>', parse_image, s)
- return s
-
-
-def extract_images(s):
- soup = BeautifulSoup(s, "lxml")
- imgs = []
- for img in soup.find_all('img'):
- try:
- imgs.append(img['src'])
- except:
- pass
- return imgs
-
-
class Entry(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique_for_date='pub_date')
@@ -77,7 +51,6 @@ class Entry(models.Model):
status = models.IntegerField(choices=PUB_STATUS, default=0)
photo_gallery = models.ForeignKey(PhotoGallery, on_delete=models.CASCADE, blank=True, null=True, verbose_name='photo set')
image = models.FileField(upload_to=get_upload_path, blank=True, help_text="should be 520 by 290")
- #thumbnail = models.FileField(upload_to=get_tn_path, null=True, blank=True, help_text="should be 160 wide")
meta_description = models.CharField(max_length=256, null=True, blank=True)
TEMPLATES = (
(0, 'single'),
@@ -136,8 +109,11 @@ class Entry(models.Model):
img = os.path.splitext(img)[0]
return '/media/images/home-images/hero%s_sm.jpg' % (img)
- def get_images(self):
- return extract_images(self.body_html)
+ def get_featured_image(self):
+ if self.featured_image:
+ return self.featured_image.image.url
+ else:
+ return self.image.url
@property
def state(self):
@@ -164,7 +140,7 @@ class Entry(models.Model):
@property
def get_previous_published(self):
return self.get_previous_by_pub_date(status__exact=1)
-
+
@property
def get_previous_admin_url(self):
n = self.get_previous_by_pub_date()
@@ -207,6 +183,10 @@ class Entry(models.Model):
class HomepageCurrator(models.Model):
+ """
+ simple model to control the featured article on the homepage
+ also allows me to fudge the "popular" section to be what I want
+ """
image_offset_vertical = models.CharField(max_length=20, help_text="add negative top margin to shift image (include css unit)")
images = models.ManyToManyField(LuxImage)
tag_line = models.CharField(max_length=200)
@@ -227,16 +207,6 @@ class BlogSitemap(Sitemap):
return obj.pub_date
-import urllib.request
-import urllib.parse
-import urllib.error
-from django_gravatar.helpers import get_gravatar_url, has_gravatar, calculate_gravatar_hash
-from django.dispatch import receiver
-from django_comments.signals import comment_was_posted
-from django_comments.models import Comment
-from django_comments.moderation import CommentModerator, moderator
-
-
class EntryModerator(CommentModerator):
'''
Moderate everything except people with multiple approvals
@@ -255,6 +225,18 @@ class EntryModerator(CommentModerator):
moderator.register(Entry, EntryModerator)
+
+@receiver(comment_was_posted, sender=Comment)
+def cache_gravatar(sender, comment, **kwargs):
+ gravatar_exists = has_gravatar(comment.email)
+ grav_dir = settings.IMAGES_ROOT + '/gravcache/'
+ if gravatar_exists:
+ url = get_gravatar_url(comment.email, size=60)
+ if not os.path.isdir(grav_dir):
+ os.makedirs(grav_dir)
+ local_grav = '%s/%s.jpg' % (grav_dir, calculate_gravatar_hash(comment.email))
+ urllib.request.urlretrieve(url, local_grav)
+
# from django_comments.signals import comment_will_be_posted
# from django_comments import akismet
@@ -274,15 +256,3 @@ moderator.register(Entry, EntryModerator)
# print('Something went wrong, allowing comment')
# print(e.response, e.statuscode)
# return True
-
-
-@receiver(comment_was_posted, sender=Comment)
-def cache_gravatar(sender, comment, **kwargs):
- gravatar_exists = has_gravatar(comment.email)
- grav_dir = settings.IMAGES_ROOT + '/gravcache/'
- if gravatar_exists:
- url = get_gravatar_url(comment.email, size=60)
- if not os.path.isdir(grav_dir):
- os.makedirs(grav_dir)
- local_grav = '%s/%s.jpg' % (grav_dir, calculate_gravatar_hash(comment.email))
- urllib.request.urlretrieve(url, local_grav)
diff --git a/app/links/models.py b/app/links/models.py
index 52d6e2b..ecea2d9 100644
--- a/app/links/models.py
+++ b/app/links/models.py
@@ -13,7 +13,7 @@ from django.db.models.signals import post_save
from django.dispatch import receiver
from taggit.managers import TaggableManager
-from utils.widgets import markdown_to_html
+from utils.util import markdown_to_html
def random_link():
diff --git a/app/locations/admin.py b/app/locations/admin.py
index 4adb836..f970130 100644
--- a/app/locations/admin.py
+++ b/app/locations/admin.py
@@ -1,10 +1,14 @@
from django.contrib import admin
from django.contrib.gis.admin import OSMGeoAdmin
-from locations.models import Region, Country, Location, State, Route, CheckIn
-from utils.widgets import OLAdminBase
+from .models import Region, Country, Location, State, Route, CheckIn, Campsite
+
+from utils.widgets import OLAdminBase
from utils.util import get_latlon
+from utils.widgets import LGEntryForm
+
+@admin.register(Region)
class RegionAdmin(OSMGeoAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
@@ -45,9 +49,8 @@ class RegionAdmin(OSMGeoAdmin):
map_template = 'gis/admin/osm.html'
openlayers_url = '/static/admin/js/OpenLayers.js'
-admin.site.register(Region, RegionAdmin)
-
+@admin.register(Country)
class CountryAdmin(OSMGeoAdmin):
list_display = ('name', 'pop2005', 'region', 'subregion')
search_fields = ('name',)
@@ -112,9 +115,7 @@ class CountryAdmin(OSMGeoAdmin):
openlayers_url = '/static/admin/js/OpenLayers.js'
-admin.site.register(Country, CountryAdmin)
-
-
+@admin.register(State)
class StateAdmin(OSMGeoAdmin):
list_display = ('name', 'code', 'slug', 'country')
prepopulated_fields = {'slug': ('name',)}
@@ -157,9 +158,8 @@ class StateAdmin(OSMGeoAdmin):
map_template = 'gis/admin/osm.html'
openlayers_url = '/static/admin/js/OpenLayers.js'
-admin.site.register(State, StateAdmin)
-
+@admin.register(Location)
class LocationAdmin(OSMGeoAdmin):
list_display = ('name', 'pub_date', 'parent', 'state', 'slug')
prepopulated_fields = {'slug': ('name',)}
@@ -198,9 +198,8 @@ class LocationAdmin(OSMGeoAdmin):
class Media:
js = ('next-prev-links.js',)
-admin.site.register(Location, LocationAdmin)
-
+@admin.register(Route)
class RouteAdmin(OSMGeoAdmin):
list_display = ('name', 'slug')
prepopulated_fields = {'slug': ('name',)}
@@ -237,8 +236,6 @@ class RouteAdmin(OSMGeoAdmin):
map_template = 'gis/admin/osm.html'
openlayers_url = '/static/admin/js/OpenLayers.js'
-admin.site.register(Route, RouteAdmin)
-
@admin.register(CheckIn)
class CheckInAdmin(OLAdminBase):
@@ -246,3 +243,36 @@ class CheckInAdmin(OLAdminBase):
# options for OSM map Using custom ESRI topo map
default_lat, default_lon = get_latlon()
default_zoom = 9
+
+
+@admin.register(Campsite)
+class CampsiteAdmin(OLAdminBase):
+ form = LGEntryForm
+ list_display = ('name', 'location', 'date_arrived', 'campsite_type',)
+ list_filter = ('date_arrived', 'campsite_type')
+ search_fields = ['location__name', ]
+ fieldsets = (
+ ('Campsite', {
+ 'fields': (
+ 'name',
+ ('date_arrived', 'date_left'),
+ 'point',
+ 'campsite_type',
+ 'campsite_number',
+ 'campsite_we_wish_we_had',
+ 'body_markdown'
+ ),
+ 'classes': (
+ 'show',
+ 'extrapretty',
+ 'wide'
+ )
+ }
+ ),
+ )
+
+ default_lat, default_lon = get_latlon()
+ default_zoom = 9
+
+ class Media:
+ js = ('image-loader.js', 'next-prev-links.js')
diff --git a/app/locations/migrations/0007_campsite.py b/app/locations/migrations/0007_campsite.py
new file mode 100644
index 0000000..116b5ed
--- /dev/null
+++ b/app/locations/migrations/0007_campsite.py
@@ -0,0 +1,37 @@
+# Generated by Django 2.0.1 on 2018-07-07 09:58
+
+import django.contrib.gis.db.models.fields
+from django.db import migrations, models
+import django.db.models.deletion
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('photos', '0018_auto_20161130_1218'),
+ ('locations', '0006_auto_20180629_1739'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Campsite',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('point', django.contrib.gis.db.models.fields.PointField(blank=True, srid=4326)),
+ ('date_arrived', models.DateField(default=django.utils.timezone.now)),
+ ('date_left', models.DateField(default=django.utils.timezone.now)),
+ ('campsite_type', models.IntegerField(choices=[(0, 'National Park'), (1, 'National Forest'), (2, 'National Other'), (3, 'State Park'), (4, 'State Forest'), (5, 'County Park'), (6, 'City Park'), (7, 'Boondocking'), (8, 'Other')], default=0)),
+ ('campsite_number', models.IntegerField(blank=True, null=True)),
+ ('campsite_we_wish_we_had', models.IntegerField(blank=True, null=True)),
+ ('body_markdown', models.TextField(blank=True, null=True)),
+ ('body_html', models.TextField(blank=True, null=True)),
+ ('image', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='photos.LuxImage')),
+ ('location', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='locations.Location')),
+ ],
+ options={
+ 'ordering': ('-date_arrived',),
+ 'get_latest_by': 'date_arrived',
+ },
+ ),
+ ]
diff --git a/app/locations/migrations/0008_campsite_name.py b/app/locations/migrations/0008_campsite_name.py
new file mode 100644
index 0000000..7b5c513
--- /dev/null
+++ b/app/locations/migrations/0008_campsite_name.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.0.1 on 2018-07-07 13:56
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('locations', '0007_campsite'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='campsite',
+ name='name',
+ field=models.CharField(default='st louis', max_length=200),
+ preserve_default=False,
+ ),
+ ]
diff --git a/app/locations/migrations/0009_auto_20180707_1403.py b/app/locations/migrations/0009_auto_20180707_1403.py
new file mode 100644
index 0000000..3561e4e
--- /dev/null
+++ b/app/locations/migrations/0009_auto_20180707_1403.py
@@ -0,0 +1,19 @@
+# Generated by Django 2.0.1 on 2018-07-07 14:03
+
+from django.db import migrations, models
+import django.utils.timezone
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('locations', '0008_campsite_name'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='campsite',
+ name='date_left',
+ field=models.DateField(blank=True, default=django.utils.timezone.now, null=True),
+ ),
+ ]
diff --git a/app/locations/models.py b/app/locations/models.py
index b4ee6f7..5efab23 100644
--- a/app/locations/models.py
+++ b/app/locations/models.py
@@ -1,5 +1,6 @@
import json
import requests
+from django import forms
from django.urls import reverse
from django.apps import apps
from django.contrib.gis.geos import GEOSGeometry, fromstr, MultiPolygon
@@ -7,6 +8,9 @@ from django.contrib.gis.db import models
from django.contrib.sitemaps import Sitemap
from django.utils.safestring import mark_safe
from django.utils import timezone
+from django.conf import settings
+
+from utils.util import render_images, extract_main_image, markdown_to_html
"http://staticmap.openstreetmap.de/staticmap.php?center=object.location.geometry.centroid.y,object.location.geometry.centroid.x&zoom=14&size=1140x300&maptype=osmarenderer&markers=40.702147,-74.015794,lightblue1"
@@ -115,7 +119,9 @@ class State(models.Model):
class Location(models.Model):
- """Model to hold location shapes as arbitrarily defined by me"""
+ """
+ Model to hold location shapes as arbitrarily defined by me
+ """
state = models.ForeignKey(State, on_delete=models.CASCADE)
name = models.CharField(max_length=50, )
slug = models.SlugField()
@@ -198,6 +204,63 @@ class CheckIn(models.Model):
super(CheckIn, self).save()
+class Campsite(models.Model):
+ name = models.CharField(max_length=200)
+ point = models.PointField(blank=True)
+ location = models.ForeignKey(Location, on_delete=models.CASCADE, blank=True, null=True)
+ date_arrived = models.DateField(default=timezone.now)
+ date_left = models.DateField(default=timezone.now, null=True, blank=True)
+ CAMPSITE_TYPE = (
+ (0, 'National Park'),
+ (1, 'National Forest'),
+ (2, 'National Other'),
+ (3, 'State Park'),
+ (4, 'State Forest'),
+ (5, 'County Park'),
+ (6, 'City Park'),
+ (7, 'Boondocking'),
+ (8, 'Other'),
+ )
+ campsite_type = models.IntegerField(choices=CAMPSITE_TYPE, default=0)
+ campsite_number = models.IntegerField(blank=True, null=True)
+ campsite_we_wish_we_had = models.IntegerField(blank=True, null=True)
+ body_markdown = models.TextField(blank=True, null=True)
+ body_html = models.TextField(blank=True, null=True)
+ image = models.ForeignKey("photos.LuxImage", on_delete=models.CASCADE, null=True, blank=True)
+
+ class Meta:
+ ordering = ('-date_arrived',)
+ get_latest_by = 'date_arrived'
+
+ def __str__(self):
+ return "%s - %s" % (self.name, self.location)
+
+ @property
+ def lon(self):
+ '''Get the site's longitude.'''
+ return self.point.x
+
+ @property
+ def lat(self):
+ '''Get the site's latitude.'''
+ return self.point.y
+
+ def save(self, *args, **kwargs):
+ created = self.pk is None
+ if not created:
+ md = render_images(self.body_markdown)
+ self.body_html = markdown_to_html(md)
+ try:
+ self.location = Location.objects.filter(geometry__contains=self.point).get()
+ except Location.DoesNotExist:
+ raise forms.ValidationError("There is no location associated with that point, add it: %sadmin/locations/location/add/" % (settings.BASE_URL))
+
+ main_image = extract_main_image(self.body_markdown)
+ if main_image:
+ self.image = main_image
+ super(Campsite, self).save(*args, **kwargs)
+
+
class WritingbyCountrySitemap(Sitemap):
changefreq = "weekly"
priority = 0.6
diff --git a/app/notes/models.py b/app/notes/models.py
index 86b2918..8735056 100644
--- a/app/notes/models.py
+++ b/app/notes/models.py
@@ -5,9 +5,8 @@ from django.conf import settings
from django.urls import reverse
from locations.models import Location
-from utils.widgets import markdown_to_html
from locations.models import CheckIn
-from jrnl.models import render_images
+from utils.util import markdown_to_html, render_images
class Note(models.Model):
diff --git a/app/pages/models.py b/app/pages/models.py
index dacb25f..707892c 100644
--- a/app/pages/models.py
+++ b/app/pages/models.py
@@ -2,12 +2,7 @@ import re
from django.db import models
from django.contrib.sitemaps import Sitemap
-from utils.widgets import markdown_to_html
-from utils.widgets import parse_image
-
-def render_images(s):
- s = re.sub('<img(.*)/>', parse_image, s)
- return s
+from utils.util import markdown_to_html, render_images
class Page(models.Model):
diff --git a/app/people/models.py b/app/people/models.py
index b4bc2cc..1a07b16 100644
--- a/app/people/models.py
+++ b/app/people/models.py
@@ -3,7 +3,7 @@ from django.template.defaultfilters import slugify
from taggit.managers import TaggableManager
from locations.models import Location
-from utils.widgets import markdown_to_html
+from utils.util import markdown_to_html
class Person(models.Model):
diff --git a/app/photos/models.py b/app/photos/models.py
index 5a7bff1..5a41182 100644
--- a/app/photos/models.py
+++ b/app/photos/models.py
@@ -15,7 +15,6 @@ from django.conf import settings
from django import forms
from taggit.managers import TaggableManager
-from locations.models import Location, Region
from resizeimage.imageexceptions import ImageSizeError
@@ -69,7 +68,7 @@ class LuxImage(models.Model):
height = models.CharField(max_length=6, blank=True, null=True)
width = models.CharField(max_length=6, blank=True, null=True)
point = models.PointField(null=True, blank=True)
- location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True, blank=True)
+ location = models.ForeignKey("locations.Location", on_delete=models.CASCADE, null=True, blank=True)
is_public = models.BooleanField(default=True)
sizes = models.ManyToManyField(LuxImageSize, blank=True)
flickr_id = models.CharField(null=True, blank=True, max_length=80)
@@ -177,10 +176,10 @@ class LuxImage(models.Model):
if not self.point:
self.point = LuxImage.objects.latest().point
try:
- self.location = Location.objects.filter(
+ self.location = apps.get_model('locations', 'Location').objects.filter(
geometry__contains=self.point
).get()
- except Location.DoesNotExist:
+ except DoesNotExist:
raise forms.ValidationError("There is no location associated with that point, add it: %sadmin/locations/location/add/" % (settings.BASE_URL))
super(LuxImage, self).save()
@@ -239,7 +238,7 @@ class LuxGallery(models.Model):
images = models.ManyToManyField(LuxImage)
pub_date = models.DateTimeField(null=True)
point = models.PointField(null=True, blank=True)
- location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True, blank=True)
+ location = models.ForeignKey("locations.Location", on_delete=models.CASCADE, null=True, blank=True)
is_public = models.BooleanField(default=True)
caption_style = models.CharField(blank=True, null=True, max_length=400)
@@ -318,8 +317,8 @@ class Photo(models.Model):
flickr_originalsecret = models.CharField(max_length=50)
lon = models.FloatField('Longitude', help_text="Longitude of centerpoint", null=True)
lat = models.FloatField('Latitude', help_text="Latitude of centerpoint", null=True)
- location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True)
- region = models.ForeignKey(Region, on_delete=models.CASCADE, null=True)
+ location = models.ForeignKey("locations.Location", on_delete=models.CASCADE, null=True)
+ region = models.ForeignKey("locations.Region", on_delete=models.CASCADE, null=True)
slideshowimage_width = models.CharField(max_length=4, blank=True, null=True)
slideshowimage_height = models.CharField(max_length=4, blank=True, null=True)
slideshowimage_margintop = models.CharField(max_length=4, blank=True, null=True)
@@ -462,8 +461,8 @@ class PhotoGallery(models.Model):
set_slug = models.CharField(blank=True, max_length=300)
primary = models.CharField(blank=True, max_length=300)
photos = models.ManyToManyField(Photo)
- location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True)
- region = models.ForeignKey(Region, on_delete=models.CASCADE, null=True)
+ location = models.ForeignKey("locations.Location", on_delete=models.CASCADE, null=True)
+ region = models.ForeignKey("locations.Region", on_delete=models.CASCADE, null=True)
pub_date = models.DateTimeField(null=True)
class Meta:
diff --git a/app/photos/utils.py b/app/photos/utils.py
index 28047d4..84e72f5 100644
--- a/app/photos/utils.py
+++ b/app/photos/utils.py
@@ -1,7 +1,12 @@
import os
+import re
import subprocess
-from PIL import ImageFile
+from django.apps import apps
+from django.conf import settings
+
+from PIL import ImageFile
+from bs4 import BeautifulSoup
# pip install python-resize-image
from resizeimage import resizeimage
@@ -19,3 +24,5 @@ def resize_image(img, width=None, height=None, quality=72, base_path="", filenam
ImageFile.MAXBLOCK = img.size[0] * img.size[1] * 4
newimg.save(path, newimg.format, quality=quality)
subprocess.call(["jpegoptim", "%s" % path])
+
+
diff --git a/app/projects/models/base.py b/app/projects/models/base.py
index a45fe04..aa795d2 100644
--- a/app/projects/models/base.py
+++ b/app/projects/models/base.py
@@ -3,8 +3,6 @@ from django.contrib.gis.db import models
from django.contrib.sitemaps import Sitemap
from django.conf import settings
-from utils.widgets import markdown_to_html
-
def get_upload_path(self, filename):
return "images/project-thumbs/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename)
diff --git a/app/resume/models.py b/app/resume/models.py
index 0dcc160..68f9a7e 100644
--- a/app/resume/models.py
+++ b/app/resume/models.py
@@ -2,7 +2,7 @@ from django.db import models
from django.utils.encoding import force_text
from django.urls import reverse
-from utils.widgets import markdown_to_html
+from utils.util import markdown_to_html
class Publisher(models.Model):
diff --git a/app/sightings/migrations/0006_auto_20180707_0958.py b/app/sightings/migrations/0006_auto_20180707_0958.py
new file mode 100644
index 0000000..1db6cc8
--- /dev/null
+++ b/app/sightings/migrations/0006_auto_20180707_0958.py
@@ -0,0 +1,24 @@
+# Generated by Django 2.0.1 on 2018-07-07 09:58
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('sightings', '0005_auto_20180516_1759'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='sighting',
+ old_name='date',
+ new_name='pub_date',
+ ),
+ migrations.AlterField(
+ model_name='ap',
+ name='image',
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='photos.LuxImage'),
+ ),
+ ]
diff --git a/app/sightings/models.py b/app/sightings/models.py
index 7368bd4..fd5cba6 100644
--- a/app/sightings/models.py
+++ b/app/sightings/models.py
@@ -10,12 +10,11 @@ from django import forms
from django.conf import settings
from bs4 import BeautifulSoup
-# from photos.models import LuxImage
from locations.models import Location
from photos.models import LuxImage
-from utils.widgets import parse_image
-from utils.widgets import markdown_to_html
+
+from utils.util import parse_image, markdown_to_html
from utils.next_prev import next_in_order, prev_in_order
diff --git a/app/sketches/models.py b/app/sketches/models.py
index 9a3a8af..702b490 100644
--- a/app/sketches/models.py
+++ b/app/sketches/models.py
@@ -6,10 +6,8 @@ from django import forms
from locations.models import Location
from django.urls import reverse
-from utils.widgets import markdown_to_html
+from utils.util import render_images, parse_image
from locations.models import CheckIn
-from utils.widgets import parse_image, parse_video
-
def render_images(s):
s = re.sub('<img(.*)/>', parse_image, s)
@@ -88,4 +86,3 @@ class Sketch(models.Model):
self.pub_date= timezone.now()
self.date_last_updated = timezone.now()
super(Sketch, self).save()
-
diff --git a/app/src/migrations/0003_auto_20180707_0958.py b/app/src/migrations/0003_auto_20180707_0958.py
new file mode 100644
index 0000000..f619888
--- /dev/null
+++ b/app/src/migrations/0003_auto_20180707_0958.py
@@ -0,0 +1,17 @@
+# Generated by Django 2.0.1 on 2018-07-07 09:58
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('src', '0002_auto_20160329_2107'),
+ ]
+
+ operations = [
+ migrations.AlterModelOptions(
+ name='post',
+ options={'get_latest_by': 'pub_date', 'ordering': ('-pub_date',), 'verbose_name_plural': 'posts'},
+ ),
+ ]
diff --git a/app/src/models.py b/app/src/models.py
index 5b0fdcd..ff829e1 100644
--- a/app/src/models.py
+++ b/app/src/models.py
@@ -6,8 +6,7 @@ from django.conf import settings
import datetime
from itertools import chain
-from utils.widgets import parse_image
-from utils.widgets import markdown_to_html
+from utils.util import parse_image, markdown_to_html
def render_images(s):
diff --git a/app/utils/util.py b/app/utils/util.py
index 7ef244c..4cc7d31 100644
--- a/app/utils/util.py
+++ b/app/utils/util.py
@@ -1,5 +1,25 @@
-from locations.models import CheckIn
+import re
from django.contrib.gis.geos import GEOSGeometry
+from django.apps import apps
+from django.template.loader import render_to_string
+from django.conf import settings
+from bs4 import BeautifulSoup
+import markdown
+
+
+def markdown_to_html(txt):
+ md = markdown.Markdown(
+ extensions=[
+ 'markdown.extensions.fenced_code',
+ 'markdown.extensions.codehilite(css_class=highlight,linenums=False)',
+ 'markdown.extensions.attr_list',
+ 'footnotes',
+ 'extra'
+ ],
+ output_format='html5',
+ safe_mode=False
+ )
+ return md.convert(txt)
def convertll(lat, lon):
@@ -9,7 +29,76 @@ def convertll(lat, lon):
def get_latlon():
- loc = CheckIn.objects.latest()
+ loc = apps.get_model('locations', 'CheckIn').objects.latest()
lat_converted, lon_converted = convertll(loc.lat, loc.lon)
return lat_converted, lon_converted
+
+def extract_main_image(markdown):
+ soup = BeautifulSoup(markdown, 'html.parser')
+ try:
+ image = soup.find_all('img')[0]['id']
+ img_pk = image.split('image-')[1]
+ return apps.get_model('photos', 'LuxImage').objects.get(pk=img_pk)
+ except IndexError:
+ return None
+
+
+def parse_image(s):
+ soup = BeautifulSoup(s.group(), "lxml")
+ for img in soup.find_all('img'):
+ cl = img['class']
+ if cl[0] == 'postpic' or cl[0] == 'postpicright':
+ s = str(img).replace('[[base_url]]', settings.IMAGES_URL)
+ return s
+ else:
+ image_id = img['id'].split("image-")[1]
+ i = apps.get_model('photos', 'LuxImage').objects.get(pk=image_id)
+ caption = False
+ exif = False
+ cluster_class = None
+ extra = None
+ if cl[0] == 'cluster':
+ css_class = cl[0]
+ cluster_class = cl[1]
+ try:
+ if cl[2] == 'caption':
+ caption = True
+ elif cl[2] == 'exif':
+ exif = True
+ else:
+ extra = cl[2]
+
+ if len(cl) > 3:
+ if cl[3] == 'exif':
+ exif = True
+ except:
+ pass
+ elif cl[0] != 'cluster' and len(cl) > 1:
+ css_class = cl[0]
+ if cl[1] == 'caption':
+ caption = True
+ if cl[1] == 'exif':
+ exif = True
+ elif cl[0] != 'cluster' and len(cl) > 2:
+ css_class = cl[0]
+ if cl[1] == 'caption':
+ caption = True
+ if cl[2] == 'exif':
+ exif = True
+ print('caption'+str(caption))
+ else:
+ css_class = cl[0]
+ return render_to_string("lib/img_%s.html" % css_class, {'image': i, 'caption': caption, 'exif': exif, 'cluster_class': cluster_class, 'extra':extra})
+
+
+def render_images(s):
+ s = re.sub('<img(.*)/>', parse_image, s)
+ return s
+
+
+def parse_video(s):
+ soup = BeautifulSoup(s, "lxml")
+ if soup.find('video'):
+ return True
+ return False
diff --git a/app/utils/widgets.py b/app/utils/widgets.py
index 2b76f6b..c038252 100644
--- a/app/utils/widgets.py
+++ b/app/utils/widgets.py
@@ -5,24 +5,15 @@ from django.contrib.admin.widgets import AdminFileWidget
from django.contrib.gis.admin import OSMGeoAdmin
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
+from django.template.loader import render_to_string
+from django.template import Context
from django.forms.widgets import SelectMultiple
from django.conf import settings
-import markdown
+import markdown
-def markdown_to_html(txt):
- md = markdown.Markdown(
- extensions=[
- 'markdown.extensions.fenced_code',
- 'markdown.extensions.codehilite(css_class=highlight,linenums=False)',
- 'markdown.extensions.attr_list',
- 'footnotes',
- 'extra'
- ],
- output_format='html5',
- safe_mode=False
- )
- return md.convert(txt)
+from bs4 import BeautifulSoup
+from django.utils.module_loading import import_string
class CustomSelectMultiple(SelectMultiple):
@@ -152,63 +143,3 @@ class OLAdminBase(OSMGeoAdmin):
openlayers_url = '/static/admin/js/OpenLayers.js'
-from bs4 import BeautifulSoup
-from photos.models import LuxImage
-from django.template.loader import render_to_string
-from django.template import Context
-
-
-def parse_image(s):
- soup = BeautifulSoup(s.group(), "lxml")
- for img in soup.find_all('img'):
- cl = img['class']
- if cl[0] == 'postpic' or cl[0] == 'postpicright':
- s = str(img).replace('[[base_url]]', settings.IMAGES_URL)
- return s
- else:
- image_id = img['id'].split("image-")[1]
- i = LuxImage.objects.get(pk=image_id)
- caption = False
- exif = False
- cluster_class = None
- extra = None
- if cl[0] == 'cluster':
- css_class = cl[0]
- cluster_class = cl[1]
- try:
- if cl[2] == 'caption':
- caption = True
- elif cl[2] == 'exif':
- exif = True
- else:
- extra = cl[2]
-
- if len(cl) > 3:
- if cl[3] == 'exif':
- exif = True
- except:
- pass
- elif cl[0] != 'cluster' and len(cl) > 1:
- css_class = cl[0]
- if cl[1] == 'caption':
- caption = True
- if cl[1] == 'exif':
- exif = True
- elif cl[0] != 'cluster' and len(cl) > 2:
- css_class = cl[0]
- if cl[1] == 'caption':
- caption = True
- if cl[2] == 'exif':
- exif = True
- print('caption'+str(caption))
- else:
- css_class = cl[0]
- return render_to_string("lib/img_%s.html" % css_class, {'image': i, 'caption': caption, 'exif': exif, 'cluster_class': cluster_class, 'extra':extra})
-
-
-def parse_video(s):
- soup = BeautifulSoup(s, "lxml")
- if soup.find('video'):
- return True
- return False
-