diff options
author | luxagraf <sng@luxagraf.net> | 2018-07-07 20:41:09 -0400 |
---|---|---|
committer | luxagraf <sng@luxagraf.net> | 2018-07-07 20:41:09 -0400 |
commit | 6a2393e6819ea09aeb559354a69746750aa8cbdf (patch) | |
tree | 0ac9890740f9afcd9720ea9b550a3895d95ecb50 /app | |
parent | fe13c3830c6b36fb8f78009a788650a992cb3070 (diff) |
added campsite model, refactored some code to avoid circular imports,
reorganized some auxilary functions and fixed broken build JS.
Diffstat (limited to 'app')
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 - |