summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/posts/admin.py2
-rw-r--r--app/posts/models.py2
-rw-r--r--app/posts/templates/posts/friends_detail.html175
-rw-r--r--app/posts/templates/posts/friends_list.html29
-rw-r--r--app/posts/urls/friends_urls.py20
-rw-r--r--app/posts/views/friends_views.py39
6 files changed, 266 insertions, 1 deletions
diff --git a/app/posts/admin.py b/app/posts/admin.py
index 7819ac5..661075b 100644
--- a/app/posts/admin.py
+++ b/app/posts/admin.py
@@ -45,7 +45,7 @@ class PostAdmin(OSMGeoAdmin):
('title', 'short_title'),
'subtitle',
'body_markdown',
- ('pub_date', 'status', 'post_type'),
+ ('pub_date', 'status', 'post_type', 'issue'),
('slug', 'enable_comments',),
'point',
'dek',
diff --git a/app/posts/models.py b/app/posts/models.py
index efe1904..cc6e1d5 100644
--- a/app/posts/models.py
+++ b/app/posts/models.py
@@ -47,6 +47,7 @@ class PostType(models.IntegerChoices):
JRNL = 4, ('jrnl')
FIELD_NOTE = 5, ('field note')
GUIDE = 6, ('guide')
+ FRIENDS = 7, ('friends')
class Post(models.Model):
@@ -95,6 +96,7 @@ class Post(models.Model):
originally_published_by_url = models.CharField(max_length=400, null=True, blank=True)
field_notes = models.ManyToManyField('self', blank=True, symmetrical=False, limit_choices_to = {'post_type': PostType.FIELD_NOTE})
books = models.ManyToManyField(Book, blank=True)
+ issue = models.PositiveIntegerField(null=True)
class Meta:
ordering = ('-pub_date',)
diff --git a/app/posts/templates/posts/friends_detail.html b/app/posts/templates/posts/friends_detail.html
new file mode 100644
index 0000000..5a8c92d
--- /dev/null
+++ b/app/posts/templates/posts/friends_detail.html
@@ -0,0 +1,175 @@
+{% 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="/friends/" itemprop="name">Friends of a Long Year</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 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%}
+ </figure>
+ <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">Transmission {{object.get_issue_str}} &ndash; {{object.pub_date|date:"F, 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%}
+ </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/friends_list.html b/app/posts/templates/posts/friends_list.html
new file mode 100644
index 0000000..3318a08
--- /dev/null
+++ b/app/posts/templates/posts/friends_list.html
@@ -0,0 +1,29 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+
+{% block pagetitle %}Luxagraf | Friends of a Long Year {% endblock %}
+{% block metadescription %}An infrequesnt mailing list about living outdoors, travel, literature, music, vintage vehicles, and other ephemera.{% endblock %}
+{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %}
+{% block primary %}
+ <main role="main" class="archive-wrapper">
+ <div class="archive-intro">
+ <h1 class="list-hed">Join the <em>Friends of a Long Year</em>.</h1>
+ <iframe target='_parent' style="border:none; background:white; width:100%;" title="embedded form for subscribing the the Friends of a Long Year newsletter" src="{% url 'lttr:subscribe' slug='friends' %}"></iframe>
+ <h2 class="list-subhed">Say what? </h2>
+ <p><em>Friends of a Long Year</em> is a monthly letter about living outdoors, travel, literature, music, vintage vehicles, and other ephemera. It's written in the spirit of Mary Austin. And Mike’s emails. A more detailed explaination can be found <a href="/jrnl/2020/11/invitation">here</a>.</p>
+ <p>Unsubscribing is easy. It's all <a href="/src/building-your-own-mailing-list-software">self-hosted</a> and designed to <a href="/privacy" title="My privacy policy">respect your privacy</a>.</p>
+ <p>There's also the <em><a href="/range/">Range</a></em> newsletter if you'd like a photo in your inbox once a week.</p>
+ </div>
+ <h3 class="archive-sans">Letters</h3>
+ <ul class="archive-list">{% for object in object_list %}
+ <li class="h-entry hentry archive-list-card" itemscope itemType="http://schema.org/Article">
+ <a href="{{object.get_absolute_url}}" class="u-url">
+ {% if object.featured_image %}<div class="circle-img-wrapper"><img src="{{object.featured_image.get_thumbnail_url}}" alt="{{object.featured_image.alt}}" class="u-photo" /></div>{%endif%}
+ <span class="date dt-published card-smcaps">issue {{object.get_issue_str}} &ndash; {{object.pub_date|date:"M y"}}</span>
+ <h2 class="card-hed">{{object.title|safe|smartypants|widont}}</h2>
+ {% if object.subtitle %}<h3 class="p-summary card-lede">{{object.subtitle|safe|smartypants|widont}}</h3>{%endif%}
+ </a>
+ </li>
+ {%endfor%}</ul>
+ </main>
+{%endblock%}
diff --git a/app/posts/urls/friends_urls.py b/app/posts/urls/friends_urls.py
new file mode 100644
index 0000000..2e2d220
--- /dev/null
+++ b/app/posts/urls/friends_urls.py
@@ -0,0 +1,20 @@
+from django.urls import path, re_path, include
+from django.views.generic.base import RedirectView
+
+from ..views import friends_views as views
+
+app_name = "range"
+
+urlpatterns = [
+ path(
+ r'<str:slug>',
+ views.FriendsDetailView.as_view(),
+ name="friends-detail"
+ ),
+ path(
+ r'',
+ views.FriendsListView.as_view(),
+ {'page':1},
+ name="friends-base"
+ ),
+]
diff --git a/app/posts/views/friends_views.py b/app/posts/views/friends_views.py
new file mode 100644
index 0000000..dd4dac2
--- /dev/null
+++ b/app/posts/views/friends_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 FriendsDetailView(LuxDetailView):
+ model = Post
+ slug_field = "slug"
+ template_name = "posts/friends_detail.html"
+
+
+class FriendsListView(PaginatedListView):
+ """
+ Return a list of Newsletter posts in reverse chronological order
+ """
+ model = Post
+ template_name = "posts/friends_list.html"
+ queryset = Post.objects.filter(post_type=PostType.FRIENDS,status=1).order_by('-pub_date')
+
+ def get_context_data(self, **kwargs):
+ context = super(FriendsListView, self).get_context_data(**kwargs)
+ context['breadcrumbs'] = ['friends of a long year',]
+ return context
+
+