summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf>2021-03-23 21:32:16 -0400
committerluxagraf <sng@luxagraf>2021-03-23 21:32:16 -0400
commitcb7c6ae216ecd4eab95b48af8d8cc0ca15c84379 (patch)
treebd77e0313922adeda92b6a698c7a190d42c15962
parent30869b14bcd9186f6bc359ea4e55a64e326f1496 (diff)
added RANGE to post types
-rw-r--r--app/posts/models.py13
-rw-r--r--app/posts/templates/posts/range_detail.html184
-rw-r--r--app/posts/templates/posts/range_list.html44
-rw-r--r--app/posts/urls/range_urls.py20
-rw-r--r--app/posts/views/range_views.py39
5 files changed, 299 insertions, 1 deletions
diff --git a/app/posts/models.py b/app/posts/models.py
index c6365f5..efe1904 100644
--- a/app/posts/models.py
+++ b/app/posts/models.py
@@ -32,13 +32,15 @@ from books.models import Book
from taxonomy.models import TaggedItems, Category
from utils.util import render_images, render_products, parse_video, markdown_to_html, extract_main_image
+from lttr.models import Newsletter
+
def get_upload_path(self, filename):
return "images/post-images/%s/%s" % (datetime.datetime.today().strftime("%Y"), filename)
class PostType(models.IntegerChoices):
- FIELD_TEST = 0, ('field test')
+ RANGE = 0, ('range')
REVIEW = 1, ('review')
ESSAY = 2, ('essay')
SRC = 3, ('src')
@@ -110,6 +112,8 @@ class Post(models.Model):
return reverse('fieldnote:detail', kwargs={"year": self.pub_date.year, "month": self.pub_date.strftime("%m"), "slug": self.slug})
if self.post_type == PostType.JRNL:
return reverse('jrnl:detail', kwargs={"year": self.pub_date.year, "month": self.pub_date.strftime("%m"), "slug": self.slug})
+ if self.post_type == PostType.RANGE:
+ return reverse('range:detail', kwargs={"slug": self.slug})
def comment_period_open(self):
return self.enable_comments and datetime.datetime.today() - datetime.timedelta(30) <= self.pub_date
@@ -225,6 +229,13 @@ class PostModerator(CommentModerator):
return True
moderator.register(Post, PostModerator)
+#class PostMailing(models.Model):
+# newsletter = models.ForeignKey(Newsletter, null=True, on_delete=models.SET_NULL)
+# post = models.ForeignKey(Post, null=True, on_delete=models.SET_NULL)
+# body_email_html = models.TextField(blank=True)
+# issue = models.PositiveIntegerField()
+# date_sent = models.DateTimeField(blank=True, auto_now_add=True, editable=False)
+
@receiver(comment_was_posted, sender=Comment)
def cache_gravatar(sender, comment, **kwargs):
diff --git a/app/posts/templates/posts/range_detail.html b/app/posts/templates/posts/range_detail.html
new file mode 100644
index 0000000..008a572
--- /dev/null
+++ b/app/posts/templates/posts/range_detail.html
@@ -0,0 +1,184 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% load get_image_by_size %}
+{%block htmlclass%}{%endblock%}
+{% block sitename %}
+<head itemscope itemtype="http://schema.org/WebSite">
+ <title itemprop='name'>{{object.title|safe}} by Scott Gilbertson</title>
+ <link rel="canonical" href="https://luxagraf.net{{object.get_absolute_url}}">{%endblock%}
+
+ {%block extrahead%}
+ <link rel="canonical" href="https://luxagraf.net{{object.get_absolute_url}}" />
+ <meta property="og:type" content="article" />
+ <meta property="og:title" content="{{object.title|safe}}" />
+ <meta property="og:url" content="https://luxagraf.net{{object.get_absolute_url}}" />
+ <meta property="og:description" content="{{object.meta_description}}" />
+ <meta property="article:published_time" content="{{object.pub_date|date:'c'}}" />
+ <meta property="article:author" content="Scott Gilbertson" />
+ <meta property="og:site_name" content="Luxagraf" />
+ <meta property="og:image" content="{{object.get_featured_image}}" />
+ <meta property="og:locale" content="en_US" />
+ <meta name="twitter:card" content="summary_large_image"/>
+ <meta name="twitter:description" content="{{object.meta_description}}"/>
+ <meta name="twitter:title" content="{{object.title|safe}}"/>
+ <meta name="twitter:site" content="@luxagraf"/>
+ <meta name="twitter:domain" content="luxagraf"/>
+ <meta name="twitter:image:src" content="{{object.get_featured_image}}"/>
+ <meta name="twitter:creator" content="@luxagraf"/>
+<script type="application/ld+json">
+{
+ "@context": "https://schema.org",
+ "@type": "Article",
+ "mainEntityOfPage": {
+ "@type": "WebPage",
+ "@id": "https://luxagraf.net{{object.get_absolute_url}}"
+ },
+ "headline": "{{object.title}}",
+ "datePublished": "{{object.pub_date|date:'c'}}+04:00",
+ "dateModified": "{{object.pub_date|date:'c'}}+04:00",
+ "author": {
+ "@type": "Person",
+ "name": "Scott Gilbertson"
+ },
+ "publisher": {
+ "@type": "Organization",
+ "name": "Luxagraf",
+ "logo": {
+ "@type": "ImageObject",
+ "url": "https://luxagraf.net/media/img/logo-white.jpg"
+ }
+ },
+ "description": "{{object.meta_description}}"
+}
+</script>
+{%endblock%}
+{%block bodyid%}id="home" class="friends"{%endblock%}
+{% block breadcrumbs %}<nav class="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">
+ <span class="nav-item" itemprop="item">
+ <a href="/" itemprop="name">Home</a>
+ <meta itemprop="position" content="1" />
+ </span>
+ <span class="nav-item" itemprop="item">
+ <a href="/range/" itemprop="name">Range</a>
+ <meta itemprop="position" content="2" />
+ </span>
+ <span class="nav-item" itemprop="item">
+ <span itemprop="name">{{object.get_issue_str}}</span>
+ <meta itemprop="position" content="3" />
+ </span>
+ </nav>
+{% endblock %}
+{% block primary %}
+ <main>
+ <figure class="large-top-image">
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">{%with image=object.featured_image%}
+ <img style="margin:0;" class="u-photo" itemprop="image" sizes="(max-width: 960px) 100vw"
+ srcset="{{image.get_srcset}}"
+ src="{{image.get_src}}"
+ alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}">
+ </a>
+ <figcaption class="exif-caption">
+ {{image.exif_make}} {{image.exif_model}} {%if image.exif_lens %} with a {{image.exif_lens}} lens, {%endif%} f/{{image.exif_aperture}} for {{image.exif_exposure}} sec at {{image.exif_iso}} ISO.
+ </figcaption>
+ </figure>{%endwith%}
+ <article class="h-entry hentry content" itemscope itemType="http://schema.org/BlogPosting">
+ <header id="header" class="post-header">
+ <h1 class="p-name post-title" itemprop="headline">{{object.title|smartypants|safe}}</h1>
+ <div class="post-dateline">
+ <time class="dt-published published dt-updated post-date lttr-box" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">Image {{object.get_issue_str}} &ndash; {{object.pub_date|date:"F j, Y"}}</span></time>
+ <span class="hide" itemprop="author" itemscope itemtype="http://schema.org/Person">by <a class="p-author h-card" href="/about"><span itemprop="name">Scott Gilbertson</span></a></span>
+ </div>
+ </header>
+ <div id="article" class="e-content entry-content post-body" itemprop="articleBody">
+ {{object.body_html|safe|smartypants}}
+ </div>
+ {%if object.books.all %}<div class="entry-footer">
+ <aside id="recommended-reading" class="" >
+ <h3>Recommended Reading</h3>{% for obj in object.books.all %}
+ <div itemprop="mainEntity" itemscope itemtype="http://schema.org/Book">
+ <div class="book-cover-wrapper">
+ <img src="{{obj.get_image_url}}" alt="{{obj.title}} cover" class="lttr-cover" />
+ </div>
+ <div class="meta-cover">
+ <h5 class="post-title book-title" itemprop="name">{{obj.title|smartypants|widont|safe}}</h6>
+ <h6 class="post-subtitle" itemprop="author" itemscope itemtype="http://schema.org/Person">
+ <meta itemprop="name" content="{{obj.author_name}}"/>by {{obj.author_name}}</h5>
+ <dl class="book-metadata">
+ {% if obj.rating %}<dt>Rating</dt><dd class="book-stars">
+ {% for i in obj.ratings_range %}{% if i <= obj.get_rating%}&#9733;{%else%}&#9734;{%endif%}{%endfor%}</span></dd>{%endif%}
+ {% if obj.read_in %}<dt>Read</dt>
+ <dd>{{obj.read_in}}</dd>{%endif%}
+ {% if obj.pages %}<dt>Pages</dt>
+ <dd itemprop="numberOfPages">{{obj.pages}}</dd>{%endif%}
+ {% if obj.publish_date %}<dt>Published</dt>
+ <dd>{%if obj.publish_place%}{{obj.publish_place}}, {%endif%}{{obj.publish_date}}</dd>{%endif%}
+ {% if obj.isbn %}<dt>ISBN</dt>
+ <dd>{{obj.isbn}}</dd>{%endif%}
+ </dl>
+ <div class="buy-btn-wrapper">
+ {% if obj.isbn %}<a class="buy-btn" href="http://worldcat.org/isbn/{{obj.isbn}}" title="find {{obj.title}} in your local library">Borrow</a>{%endif%}
+ {% if obj.afflink %}<a class="buy-btn" href="{{obj.afflink}}" title="buy {{obj.title}} at Amazon">Buy</a>{%endif%}
+ </div>
+ </div>{%if obj.body_html%}
+ <div class="thoughts" itemprop="review" itemscope itemtype="http://schema.org/Review">
+ <h5>Notes</h5>
+ <span class="hide" itemprop="reviewRating">{{obj.rating}}</span>
+ <meta itemprop="author" content="Scott Gilbertson" />
+ <meta itemprop="datePublished" content="{{obj.read_date|date:"c"}}">
+ <div itemprop="reviewBody">{{obj.body_html|safe|smartypants|widont}}</div>
+ </div>{%endif%}
+ </div>
+ {% endfor %}
+ </aside>{%endif%}
+ </article>
+
+ {% with object.get_next_published as next %}
+ {% with object.get_previous_published as prev %}
+ <nav class="page-navigation">
+ <div>{% if prev%}
+ <span class="label">Previous:</span>
+ <a href="{{ prev.get_absolute_url }}" rel="prev" title=" {{prev.title}}">{{prev.title|safe}}</a>
+ </div>{%endif%}{% if next %}
+ <div>
+ <span class="label">Next:</span>
+ <a href="{{ next.get_absolute_url }}" rel="next" title=" {{next.title}}">{{next.title|safe}}</a>
+ </div>{%endif%}
+ </nav>{%endwith%}{%endwith%}
+ <aside class="narrow donate join">
+ <p>You're reading <em>Range</em>, a weekly mailing of a single photograph, along with a few notes, and video of the processing. If you'd like to join us, drop your email in the form below: </p>
+ <iframe target='_parent' style="border:none !important; background:white; width:100% !important;" title="embedded form for subscribing the the Friends of a Long Year newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe>
+ </aside>
+ </div>
+ {% if object.related.all %}<div class="article-afterward related">
+ <div class="related-bottom">
+ <h6 class="hedtinycaps">You might also enjoy</h6>
+ <ul class="article-card-list">{% for object in related %}
+ <li class="article-card-mini"><a href="{{object.get_absolute_url}}" title="{{object.title}}">
+ <div class="post-image post-mini-image">
+ {% if object.featured_image %}
+ {% include "lib/img_archive.html" with image=object.featured_image nolightbox=True %}
+ {% elif object.image %}
+ {% include "lib/img_archive.html" with image=object.image nolightbox=True %}
+ {% else %}
+ <img src="{{object.get_image_url}}" alt="{{ object.title }}" class="u-photo post-image" itemprop="image" />{%endif%}
+ </div>
+ <h4 class="p-name entry-title post-title" itemprop="headline">{% if object.title %}{{object.title|safe|smartypants|widont}}{% else %}{{object.common_name}}{%endif%}</h4>
+ <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p>
+ <p class="post-summary">
+ <span class="p-location h-adr adr post-location" itemprop="contentLocation" itemscope itemtype="http://schema.org/Place">
+ {% if object.location.country_name == "United States" %}{{object.location.state_name}}{%else%}{{object.location.country_name}}{%endif%}
+ </span>
+ &ndash;
+ <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}"><span>{{object.pub_date|date:" Y"}}</span></time>
+ </p>
+ </a>
+ </li>
+ {% endfor %}</ul>
+ </div>
+ </div>{%endif%}
+ </main>
+{% endblock %}
+
+{% block js %}{% comment %} <script async src="/media/js/hyphenate.min.js" type="text/javascript"></script>{% endcomment%}{% endblock%}
+
+
diff --git a/app/posts/templates/posts/range_list.html b/app/posts/templates/posts/range_list.html
new file mode 100644
index 0000000..c6875e9
--- /dev/null
+++ b/app/posts/templates/posts/range_list.html
@@ -0,0 +1,44 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% block pagetitle %}Luxagraf | Range {% endblock %}
+{% block metadescription %}A weekly photo, developed.{% endblock %}
+{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %}
+{% block primary %}
+<main role="main" class="archive-wrapper">{% for object in object_list %}{% if forloop.first %}
+ <figure class="large-top-image">
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">{%with image=object.featured_image%}
+ <img style="margin:0;" class="u-photo" itemprop="image" sizes="(max-width: 960px) 100vw"
+ srcset="{{image.get_srcset}}"
+ src="{{image.get_src}}"
+ alt="{{image.alt}} photographed by {% if image.photo_credit_source %}{{image.photo_credit_source}}{%else%}luxagraf{%endif%}">
+ </a>{%endwith%}{%endif%}{%endfor%}
+ </figure>
+ <div class="archive-intro">
+ <h1 class="list-hed">Range</h1>
+ <h2 class="list-subhed">A weekly photo, developed.</h2>
+ <p>Please join us by dropping your email in the form below: </p>
+ <iframe target='_parent' style="border:none !important; background:white; width:100% !important;" title="embedded form for subscribing the the Friends of a Long Year newsletter" src="{% url 'lttr:subscribe' slug='range' %}"></iframe>
+ <p><em>Range</em> is a weekly mailing of a single photograph. </p>
+ <p>If you're interested there is also a link to a video of the RAW image processing in <a href="https://www.darktable.org/">darktable</a>, and sometimes a few words about the process. But the primary purpose is to deliver a single photo to your inbox. Simple and fun.</p>
+ <p>Yes, I know about Instagram. This is an attempt to reclaim that space, sharing photos with friends, but without all the distractions of the corporate social web, without the endless scroll of photos, likes, stories, comments, whatever. This is just an image delivered once a week to your inbox. I've been trying to think of a way to make it reciprocal, so you can send a picture to my inbox. If you have ideas, <a href="mailto:comments@luxagraf.net">email me</a>.</p>
+ <p>Unsubscribing is easy. It's <a href="/src/building-your-own-mailing-list-software">self-hosted</a> and <a href="/privacy" title="My privacy policy">respects your privacy</a>. If you don't want an email, there's also <a href="/range/feed.xml">an RSS feed</a>, and it's all archived below.</p>
+ <p>There's also the <em><a href="/friends/">Friends of a Long Year</a></em> newsletter if you want some stories in your inbox.</p>
+ </div>
+ <h3 class="archive-sans">Images</h3>
+ <div class="archive-grid">{% for object in object_list %}
+ <article class="h-entry hentry archive-grid-card" itemscope itemType="http://schema.org/Article">
+ <div class="card-image">
+ <a href="{{object.get_absolute_url}}" title="{{object.title}}">
+ {% include "lib/img_archive.html" with image=object.featured_image %}
+ </a>
+ </div>
+ <h2 class="p-name card-hed-it" itemprop="headline"><a href="{{object.get_absolute_url}}" class="u-url" title="{{object.title}}">{{object.title|safe|smartypants|widont}}</a></h2>
+ <p class="p-author author hide" itemprop="author"><span class="byline-author" itemscope itemtype="http://schema.org/Person"><span itemprop="name">Scott Gilbertson</span></span></p>
+ <time class="dt-published published dt-updated card-smcaps" datetime="{{object.pub_date|date:'c'}}">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"j, Y"}}</span></time>
+ </article> {% endfor %}
+ </div>
+ </main>
+{%endblock%}
+
+ <p>If you're not familiar, darktable is open source raw image developer. It's free, you can download a copy for Linux, macOS, or Windows. The <a href="https://www.darktable.org/usermanual/en/">darktable user manual</a> is very helpful if you're brand new. I also recommend <a href="https://www.youtube.com/user/audio2u">Bruce Williams' darktable videos</a>, and <a href="https://www.youtube.com/user/s7habo/videos">Boris Hajdukovic's videos</a>, which were the inspiration for what you see here.</p>
+ <p>I'm no expert either, so feel free to hit reply and let me know if I get something wrong.</p>
diff --git a/app/posts/urls/range_urls.py b/app/posts/urls/range_urls.py
new file mode 100644
index 0000000..7b29569
--- /dev/null
+++ b/app/posts/urls/range_urls.py
@@ -0,0 +1,20 @@
+from django.urls import path, re_path, include
+from django.views.generic.base import RedirectView
+
+from ..views import range_views as views
+
+app_name = "range"
+
+urlpatterns = [
+ path(
+ r'<str:slug>',
+ views.RangeDetailView.as_view(),
+ name="detail"
+ ),
+ path(
+ r'',
+ views.RangeListView.as_view(),
+ {'page':1},
+ name="range-base"
+ ),
+]
diff --git a/app/posts/views/range_views.py b/app/posts/views/range_views.py
new file mode 100644
index 0000000..989134d
--- /dev/null
+++ b/app/posts/views/range_views.py
@@ -0,0 +1,39 @@
+from django.views.generic import ListView
+from django.views.generic.detail import DetailView
+from django.views.generic.dates import DateDetailView
+from django.urls import reverse
+from django.views.generic.dates import YearArchiveView, MonthArchiveView
+from django.contrib.syndication.views import Feed
+from django.apps import apps
+from django.shortcuts import get_object_or_404
+from django.conf import settings
+from django.db.models import Q
+
+from utils.views import PaginatedListView, LuxDetailView
+
+#from ..models import Entry, HomepageCurrator, Home
+from ..models import Post, PostType
+from locations.models import LuxCheckIn, Country, Region, Location
+from sightings.models import Sighting
+
+
+class RangeDetailView(LuxDetailView):
+ model = Post
+ slug_field = "slug"
+ template_name = "posts/range_detail.html"
+
+
+class RangeListView(PaginatedListView):
+ """
+ Return a list of Newsletter posts in reverse chronological order
+ """
+ model = Post
+ template_name = "posts/range_list.html"
+ queryset = Post.objects.filter(post_type=PostType.RANGE,status=1).order_by('-pub_date')
+
+ def get_context_data(self, **kwargs):
+ context = super(RangeListView, self).get_context_data(**kwargs)
+ context['breadcrumbs'] = ['range',]
+ return context
+
+