diff options
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 - |