diff options
-rw-r--r-- | app/posts/models.py | 50 | ||||
-rw-r--r-- | app/posts/templates/posts/guide_base.html | 41 | ||||
-rw-r--r-- | app/posts/templates/posts/src_detail.html | 111 | ||||
-rw-r--r-- | app/posts/templates/posts/src_list.html | 30 | ||||
-rw-r--r-- | app/posts/urls.py | 24 | ||||
-rw-r--r-- | app/posts/urls/__init__old.py | 4 | ||||
-rw-r--r-- | app/posts/urls/essay_urls.py (renamed from app/posts/essay_urls.py) | 2 | ||||
-rw-r--r-- | app/posts/urls/guide_urls.py | 30 | ||||
-rw-r--r-- | app/posts/urls/guide_urls_old.py (renamed from app/posts/guide_urls.py) | 0 | ||||
-rw-r--r-- | app/posts/urls/review_urls.py (renamed from app/posts/review_urls.py) | 6 | ||||
-rw-r--r-- | app/posts/urls/src_urls.py | 49 | ||||
-rw-r--r-- | app/posts/views.py | 14 | ||||
-rw-r--r-- | app/posts/views/__init__.py | 0 | ||||
-rw-r--r-- | app/posts/views/guide_views.py | 95 | ||||
-rw-r--r-- | app/posts/views/src_views.py | 96 | ||||
-rw-r--r-- | config/base_urls.py | 12 | ||||
-rw-r--r-- | design/sass/_header.scss | 3 |
17 files changed, 512 insertions, 55 deletions
diff --git a/app/posts/models.py b/app/posts/models.py index b92518c..8312040 100644 --- a/app/posts/models.py +++ b/app/posts/models.py @@ -33,6 +33,13 @@ from jrnl.models import Entry from utils.util import render_images, render_products, parse_video, markdown_to_html +class PostType(models.IntegerChoices): + FIELD_TEST = 0, ('field test') + REVIEW = 1, ('review') + ESSAY = 2, ('essay') + SRC = 3, ('src') + JRNL = 4, ('jrnl') + class Post(models.Model): old_id = models.IntegerField(blank=True, null=True) title = models.CharField(max_length=200) @@ -59,14 +66,7 @@ class Post(models.Model): TEMPLATES = ( (0, 'single'), ) - POST_TYPE = ( - (0, 'field test'), - (1, 'review'), - (2, 'essay'), - (3, 'src'), - (4, 'jrnl'), - ) - post_type = models.IntegerField(choices=POST_TYPE, default=0) + post_type = models.IntegerField(choices=PostType.choices, default=PostType.JRNL) template_name = models.IntegerField(choices=TEMPLATES, default=0) has_video = models.BooleanField(blank=True, default=False) has_code = models.BooleanField(blank=True, default=False) @@ -75,8 +75,8 @@ class Post(models.Model): field_notes = models.ManyToManyField(FieldNote, blank=True) related = models.ManyToManyField(RelatedPost, blank=True) point = models.PointField(null=True, blank=True) - topics = models.ManyToManyField(Category, blank=True) location = models.ForeignKey(Location, on_delete=models.CASCADE, null=True, blank=True) + topics = models.ManyToManyField(Category, blank=True) originally_published_by = models.CharField(max_length=400, null=True, blank=True) originally_published_by_url = models.CharField(max_length=400, null=True, blank=True) field_notes = models.ManyToManyField(FieldNote, blank=True) @@ -92,11 +92,13 @@ class Post(models.Model): def get_absolute_url(self): if self.post_type == 0: - return reverse('guides:detail', kwargs={"slug": self.slug}) + return reverse('guides:reviews:review-detail', kwargs={"slug": self.slug}) if self.post_type == 1: - return reverse('reviews:review-detail', kwargs={"slug": self.slug}) + return reverse('guides:reviews:review-detail', kwargs={"slug": self.slug}) if self.post_type == 2: return reverse('essays:detail', kwargs={"slug": self.slug}) + if self.post_type == 3: + return reverse('src:detail', kwargs={"slug": self.slug}) def comment_period_open(self): return self.enable_comments and datetime.datetime.today() - datetime.timedelta(30) <= self.pub_date @@ -166,6 +168,25 @@ class Post(models.Model): super(Post, self).save(*args, **kwargs) + 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)) + if created and not self.featured_image: + self.featured_image = LuxImage.objects.latest() + old = type(self).objects.get(pk=self.pk) if self.pk else None + if old and old.featured_image != self.featured_image: # Field has changed + s = LuxImageSize.objects.get(name="featured_jrnl") + ss = LuxImageSize.objects.get(name="picwide-med") + self.featured_image.sizes.add(s) + self.featured_image.sizes.add(ss) + self.featured_image.save() + if old.title != self.title or old.slug != self.slug: + related, c = RelatedPost.objects.get_or_create(model_name=self.get_content_type(), entry_id = self.id, pub_date=self.pub_date) + related.title = self.title + related.slug = self.slug + related.save() + class PostModerator(CommentModerator): ''' Moderate everything except people with multiple approvals @@ -219,6 +240,7 @@ class PostSitemap(Sitemap): """ for p in src: s, created = Post.objects.get_or_create( + old_id=p.id, title=p.title, slug=p.slug, body_markdown=p.body_markdown, @@ -231,6 +253,10 @@ for p in src: ) print(p) for t in p.topics.all(): - c = Category.objects.get(slug=t.slug) + c,created = Category.objects.get_or_create( + slug=t.slug, + name=t.name, + pluralized_name=t.pluralized_name + ) s.topics.add(c) """ diff --git a/app/posts/templates/posts/guide_base.html b/app/posts/templates/posts/guide_base.html new file mode 100644 index 0000000..e7764db --- /dev/null +++ b/app/posts/templates/posts/guide_base.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% load html5_datetime %} +{% load pagination_tags %} +{% block pagetitle %}Advice, Tools, Tips, and Tricks for Full Time Van or RV Life.{% endblock %} +{% block metadescription %}Guides for fellow travelers: tools, tips, and tricks to make life on the road in an RV or Van easier and more enjoyable.{% endblock %} + +{% block primary %}<ul class="bl" id="breadcrumbs" itemscope itemtype="http://data-vocabulary.org/Breadcrumb"> + <li><a href="/" title="luxagraf homepage" itemprop="url"><span itemprop="title">Home</span></a> → </li> + <li itemprop="title">guide</li> + </ul> + <main role="main" id="guide-archive" class="essay-archive guide-archive archive-list"> + <div class="essay-intro"> + <h2>Roaming Guide</h2> + <h3>Advice, Tools, Tips, and Tricks for Full Time Van or RV Life.</h3> + <p>I don't want to tell you how to travel. Everyone is different. Besides, even after twenty some odd years of travel, I am still learning. </p> + <p>I've always been most inspired by wandering monks and nuns, those who walked or sailed with next to nothing and survived. Mostly. Today most of us are not that skilled or strong of will, but keeping that example in mind is helpful. The less stuff you travel with the better off you are. Up to a point. Having the right tools is important. The right tools make life easier and more fun.</p> + <p>I put this together to help you find the tools you need. These aren't casual reviews. These are things I have spent years seeking out, using, and refining. In the end what you need are not things, but strategies and tools that allow you to create solutions to problems. </p> + </div> + <h1 class="topic-hed">Reviews</h1> + {% autopaginate object_list 30 %} + <ul class="fancy-archive-list">{% for object in object_list %} + <li class="h-entry hentry" itemscope itemType="http://schema.org/Article"> + <a href="{{object.get_absolute_url}}" class="u-url"> + <div class="circle-img-wrapper"><img src="{{object.featured_image.get_thumbnail_url}}" alt="{{object.featured_image.alt}}" class="u-photo" /></div> + <span class="date dt-published">{{object.pub_date|date:"F d, Y"}}</span> + <a href="{{object.get_absolute_url}}"> + <h2>{{object.title|safe|smartypants|widont}}</h2> + {% if object.subtitle %}<h3 class="p-summary">{{object.subtitle|safe|smartypants|widont}}</h3>{%endif%} + </a> + {% if object.location %}<h4 class="p-location h-adr post-location" itemprop="geo" itemscope itemtype="http://data-vocabulary.org/Geo"> + <span class="p-locality">{{object.location.name|smartypants|safe}}</span>, + <span class="p-region">{{object.location.state_name}}</span>, + <span class="p-country-name">{{object.location.country_name}}</span> + <data class="p-latitude" value="{{object.latitude}}"></data> + <data class="p-longitude" value="{{object.longitude}}"></data> + </h4>{% endif %} + </li> + {%endfor%}</ul> + </main> +{%endblock%} diff --git a/app/posts/templates/posts/src_detail.html b/app/posts/templates/posts/src_detail.html new file mode 100644 index 0000000..7f87f5c --- /dev/null +++ b/app/posts/templates/posts/src_detail.html @@ -0,0 +1,111 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% load comments %} +{% block pagetitle %}{{object.title|striptags}} - by Scott Gilbertson{% endblock %} +{% block metadescription %}{% autoescape on %}{{object.meta_description|striptags|safe}}{% endautoescape %}{% endblock %} +{%block extrahead%} + <meta property="og:type" content="article" /> + <meta property="og:site_name" content="luxagraf:src"/> + <meta property="og:title" content="{{object.title|safe}}" /> + <meta property="og:url" content="https://luxagraf.net{{object.get_absolute_url}}" /> + <meta property="og:image" content=""> + <meta property="og:description" content="{{object.meta_description}}" /> + <meta property="article:published_time" content="{{object.pub_date|date:'c'}}" /> + <meta property="article:author" content="Luxagraf" /> + <meta property="og:site_name" content="Luxagraf:src" /> + <meta property="og:locale" content="en_US" /> + <meta name="twitter:card" content="summary_large_image"/> + <meta name="twitter:site" content="@luxagraf"/> + <meta name="twitter:creator" content="@luxagraf"/> + <link rel="stylesheet" href="/media/src/solarized.css" type="text/css" media="screen"/> +{%endblock%} + +{% block bodyid %}class="src detail single"{% endblock %} +{%block sitesubtitle %}Code Slowly{% endblock%} +{% block breadcrumbs %}<ol class="bl" id="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList"> + <li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"> + <a itemprop="item" href="/"> + <span itemprop="name">Home</span> + </a> → + <meta itemprop="position" content="1" /> + </li> + <li itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"> + <a href="/src/" itemprop="item"> + <span itemprop="name">Src</span> + </a> + <meta itemprop="position" content="2" /> + </li> + </ol>{% endblock %} +{% block primary %}<main role="main"> + <article class="hentry post-article{% with object.get_template_name_display as t %}{%if t == "double" or t == "double-dark" %} post--article--double{%endif%}{%endwith%}" itemscope itemType="http://schema.org/Article"> + <header id="header" class="post-header {% with object.get_template_name_display as t %}{%if t == "double" or t == "double-dark" %}post--header--double{%endif%}{%endwith%}"> + <h1 class="p-name entry-title post--title" itemprop="headline">{%if object.template_name == 1 or object.template_name == 3 %}{{object.title|safe|smartypants}}{%else%}{{object.title|safe|smartypants|widont}}{%endif%}</h1> + <h2 class="post-subtitle">{{object.meta_description|smartypants|safe}}</h2> + <div class="post-linewrapper"> + {% if object.originally_published_by %}<h4 class="post-source">Originally Published By: <a href="{{object.originally_published_by_url}}" title="View {{object.title}} on {{object.originally_published_by}}">{{object.originally_published_by}}</a></h4>{%endif%} + {% for topic in object.topics.all%}{% if forloop.counter0 == 0 %}<h4 class="post-source">Topics: {%endif%} <a href="/src/topic/{{topic.slug}}">{{topic.name}}</a>{%if forloop.last%}{%else%}, {%endif%}{%endfor%}{% if forloop.counter0 == 0 %}</h4>{%endif%} + <time class="dt-published published dt-updated post-date" datetime="{{object.pub_date|date:'c'}}" itemprop="datePublished">{{object.pub_date|date:"F"}} <span>{{object.pub_date|date:"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 post-body-{% with object.template_name as t %}{%if t == 0 or t == 2 %}single{%endif%}{%if t == 1 or t == 3 %}double{%endif%}{%endwith%}" itemprop="articleBody"> + {{object.body_html|safe|smartypants|widont}} + </div> + </article> + {% if object.slug != 'about' %} + {% with object.get_next_published as next %} + {% with object.get_previous_published as prev %} + <nav id="page-navigation"> + <ul>{% if prev%} + <li id="prev"><span class="bl">Previous:</span> + <a href="{{ prev.get_absolute_url }}" rel="prev" title=" {{prev.title}}">{{prev.title|safe}}</a> + </li>{%endif%}{% if next%} + <li id="next"><span class="bl">Next:</span> + <a href="{{ next.get_absolute_url }}" rel="next" title=" {{next.title}}">{{next.title|safe}}</a> + </li>{%endif%} + </ul> + </nav>{%endwith%}{%endwith%} + {%endif%} + </main> + {% if object.slug != 'about' %} + {% if object.enable_comments %} +{% get_comment_count for object as comment_count %} +{%if comment_count > 0 %} +<p class="comments--header">{{comment_count}} Comment{{ comment_count|pluralize }}</p> +{% render_comment_list for object %} +{%endif%} +<div class="comment--form--wrapper {%if comment_count > 0%}comment-form-border{%endif%}"> +{% render_comment_form for object %} +</div> +{% else %} +<p class="comments--header" style="text-align: center">Sorry, comments have been disabled for this post.</p> +{%endif%} +{%endif%} +{% endblock %} +{% block js %} +<script type="text/javascript"> +window.onload = function() { + {% if object.enable_comments %} +{%if comment_count > 0 %} + //delay loading of gravatar images using noscript data-hash attribute + dataattr = document.getElementsByClassName("datahashloader"); + for(var i=0; i<dataattr.length; i++) { + var c = dataattr[i].parentNode; + var img = document.createElement("img"); + img.src = 'https://images.luxagraf.net/gravcache/' + dataattr[i].getAttribute('data-hash') + '.jpg'; + img.className += "gravatar"; + c.insertBefore(img, c.childNodes[3]); + } +{%endif%} +{%endif%} + {% with object.get_template_name_display as t %}{%if t == "single" or t == "single-dark" %} + createMap(); + var open = false; + {%endif%}{%endwith%} +} +</script> +{% if object.has_code %} +{%endif %} +{% endblock %} diff --git a/app/posts/templates/posts/src_list.html b/app/posts/templates/posts/src_list.html new file mode 100644 index 0000000..dd5d410 --- /dev/null +++ b/app/posts/templates/posts/src_list.html @@ -0,0 +1,30 @@ +{% extends 'base.html' %} +{% load typogrify_tags %} +{% load comments %} + +{% block pagetitle %}Tutorials and tools for building great things{% endblock %} +{% block metadescription %}Tutorials and tools for building great things on the web - by Scott Gilbertson.{% endblock %} +{%block sitesubtitle %}Code Slowly{% endblock%} +{% block breadcrumbs %}{% include "lib/breadcrumbs.html" with breadcrumbs=breadcrumbs %}{% endblock %} +{% block primary %}<main role="main" id="essay-archive" class="essay-archive archive-list"> + <div class="essay-intro"> + <h2>Tutorials and tools for building great things on the web.</h2> + <p>The indie web is an amazing democratic publishing platform unlike anything in history. The catch is, to avoid serving at the pleasure of the corporate king, you need to know <em>how</em> to publish. That's what these articles are here for, to help you learn how to use independent, community supported open source tools. The web won't last forever, let's build something cool while we can.</p> + <p>Topics include HTML, CSS, Django, Linux, Nginx, Python, Postgresql, free software, and, once, the evil that is Google AMP.</p> + <p>A few of the articles below were previously published in: <em><a href="https://arstechnica.com/">Ars Technica</a></em>, <em><a href="https://www.wired.com/author/scott-gilbertson/">Wired</a></em>, and <em><a href="https://www.theregister.co.uk/Author/Scott-Gilbertson/">The Register</a></em></p> + </div> + <h1 class="topic-hed">Articles</h1> + <ul class="fancy-archive-list">{% for object in object_list %}{% if object.slug != 'about' %} + <li class="h-entry hentry" itemscope itemType="http://schema.org/Article"> + <span class="date dt-published">{{object.pub_date|date:"F Y"}}</span> + <a href="{{object.get_absolute_url}}"> + <h2>{{object.title|safe|smartypants|widont}}</h2> + <p class="p-summary">{{object.meta_description|safe|smartypants|widont}}</p> + </a> + </li> + {%endif%}{%endfor%}</ul> + + + + </main> +{%endblock%} diff --git a/app/posts/urls.py b/app/posts/urls.py deleted file mode 100644 index 322e5ad..0000000 --- a/app/posts/urls.py +++ /dev/null @@ -1,24 +0,0 @@ -from django.urls import path, re_path -from django.views.generic.base import RedirectView - -from . import views - -app_name = "posts" - -urlpatterns = [ - path( - r'<str:slug>.txt', - views.EntryDetailViewTXT.as_view(), - name="detail-txt" - ), - path( - r'<str:slug>', - views.EntryDetailView.as_view(), - name="detail" - ), - re_path( - r'<int:page>/', - views.EntryList.as_view(), - name="list" - ), -] diff --git a/app/posts/urls/__init__old.py b/app/posts/urls/__init__old.py new file mode 100644 index 0000000..4993c34 --- /dev/null +++ b/app/posts/urls/__init__old.py @@ -0,0 +1,4 @@ +from .guide_urls import urlpatterns as guide_urlpatterns +from .reviews_urls import urlpatterns as review_urlpatterns + +urlpatterns = review_urlpatterns + guide_urlpatterns diff --git a/app/posts/essay_urls.py b/app/posts/urls/essay_urls.py index ea7777d..3f0d7d7 100644 --- a/app/posts/essay_urls.py +++ b/app/posts/urls/essay_urls.py @@ -1,6 +1,6 @@ from django.urls import path, re_path -from . import views +from ..views import guide_views as views app_name = "essays" diff --git a/app/posts/urls/guide_urls.py b/app/posts/urls/guide_urls.py new file mode 100644 index 0000000..e0a2210 --- /dev/null +++ b/app/posts/urls/guide_urls.py @@ -0,0 +1,30 @@ +from django.urls import path, re_path, include +from django.views.generic.base import RedirectView + +from ..views import guide_views as views + +app_name = "guides" + +urlpatterns = [ + path( + r'', + views.GuideListView.as_view(), + {'page':1}, + name="guide-base" + ), + path(r'field-test/', include('posts.urls.review_urls', namespace='reviews')), + re_path(r'^field-test/$', RedirectView.as_view(url='/field-tests/')), + #path(r'field-tests/', include('posts.urls', namespace='review-list')), + #path(r'review/', include('posts.review_urls')), + re_path(r'^review/$', RedirectView.as_view(url='/guides/')), + #path( + # r'<str:slug>', + # views.EntryDetailView.as_view(), + # name="detail" + #), + #re_path( + # r'<int:page>/', + # views.EntryList.as_view(), + # name="list" + #), +] diff --git a/app/posts/guide_urls.py b/app/posts/urls/guide_urls_old.py index d43d76a..d43d76a 100644 --- a/app/posts/guide_urls.py +++ b/app/posts/urls/guide_urls_old.py diff --git a/app/posts/review_urls.py b/app/posts/urls/review_urls.py index f6a3908..6b78e43 100644 --- a/app/posts/review_urls.py +++ b/app/posts/urls/review_urls.py @@ -1,6 +1,6 @@ from django.urls import path, re_path -from . import views +from ..views import guide_views as views app_name = "reviews" @@ -17,12 +17,12 @@ urlpatterns = [ ), path( r'<int:page>/', - views.GuidesListView.as_view(), + views.ReviewsListView.as_view(), name="review-list" ), path( r'', - views.GuidesListView.as_view(), + views.ReviewsListView.as_view(), {'page':1}, name="review-list" ), diff --git a/app/posts/urls/src_urls.py b/app/posts/urls/src_urls.py new file mode 100644 index 0000000..637d9a6 --- /dev/null +++ b/app/posts/urls/src_urls.py @@ -0,0 +1,49 @@ +from django.urls import path, re_path + +from ..views import src_views as views + +app_name = "src" + +urlpatterns = [ + path( + r'feed.xml', + views.SrcRSSFeedView(), + name="feed" + ), + path( + r'topic/<str:slug>', + views.TopicListView.as_view(), + name="list_topics" + ), + #path( + # r'books/<str:slug>', + # views.BookDetailView.as_view(), + # name='detail_book' + #), + #path( + # r'books/', + # views.BookListView.as_view(), + # name='list_books' + #), + path( + r'<str:slug>.txt', + views.SrcDetailViewTXT.as_view(), + name="detail-txt" + ), + path( + r'<str:slug>', + views.SrcDetailView.as_view(), + name="detail" + ), + re_path( + r'<int:page>', + views.SrcListView.as_view(), + name="list" + ), + path( + r'', + views.SrcListView.as_view(), + {'page':1}, + name="list" + ), +] diff --git a/app/posts/views.py b/app/posts/views.py index 2e5c95a..a3f1a1f 100644 --- a/app/posts/views.py +++ b/app/posts/views.py @@ -10,30 +10,32 @@ from .models import Post from taxonomy.models import Category -class PostList(PaginatedListView): +class GuideListView(PaginatedListView): """ Return a list of Entries in reverse chronological order """ model = Post + template_name = "posts/guide_base.html" def get_queryset(self): - queryset = super(PostList, self).get_queryset() + queryset = super(GuideListView, self).get_queryset() return queryset.filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') -class GuidesListView(PostList): +class ReviewsListView(GuideListView): + template_name = "posts/post.html" def get_queryset(self): - queryset = super(GuidesListView, self).get_queryset() + queryset = super(ReviewsListView, self).get_queryset() return queryset.filter(post_type__in=[0,1]).filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') def get_context_data(self, **kwargs): - context = super(GuidesListView, self).get_context_data(**kwargs) + context = super(ReviewsListView, self).get_context_data(**kwargs) context['archive_type'] = 'Field Tests' return context -class EssayListView(PostList): +class EssayListView(GuideListView): template_name = "posts/essay_list.html" def get_queryset(self): diff --git a/app/posts/views/__init__.py b/app/posts/views/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/app/posts/views/__init__.py diff --git a/app/posts/views/guide_views.py b/app/posts/views/guide_views.py new file mode 100644 index 0000000..767a262 --- /dev/null +++ b/app/posts/views/guide_views.py @@ -0,0 +1,95 @@ +from django.views.generic import ListView +from django.views.generic.detail import DetailView +from django.contrib.syndication.views import Feed +from django.apps import apps +from django.conf import settings + +from utils.views import PaginatedListView, LuxDetailView + +from ..models import Post, PostType +from taxonomy.models import Category + + +class GuideListView(PaginatedListView): + """ + Return a list of Entries in reverse chronological order + """ + model = Post + template_name = "posts/guide_base.html" + + def get_queryset(self): + queryset = super(GuideListView, self).get_queryset() + return queryset.filter(status__exact=1).filter(post_type__in=[PostType.REVIEW,PostType.FIELD_TEST]).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') + + +class ReviewsListView(GuideListView): + template_name = "posts/post.html" + + def get_queryset(self): + queryset = super(ReviewsListView, self).get_queryset() + return queryset.filter(post_type__in=[0,1]).filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') + + def get_context_data(self, **kwargs): + context = super(ReviewsListView, self).get_context_data(**kwargs) + context['archive_type'] = 'Field Tests' + return context + + +class EssayListView(GuideListView): + template_name = "posts/essay_list.html" + + def get_queryset(self): + queryset = super(EssayListView, self).get_queryset() + return queryset.filter(post_type__in=[2,]).filter(status__exact=1).order_by('-pub_date').prefetch_related('location').prefetch_related('featured_image') + + def get_context_data(self, **kwargs): + ''' + override for custom breadcrumb path + ''' + # Call the base implementation first to get a context + context = super(EssayListView, self).get_context_data(**kwargs) + context['breadcrumbs'] = ('Essays',) + return context + + +class PostDetailView(LuxDetailView): + model = Post + slug_field = "slug" + + def get_queryset(self): + queryset = super(PostDetailView, self).get_queryset() + return queryset.select_related('location').prefetch_related('field_notes') + + def get_context_data(self, **kwargs): + context = super(PostDetailView, self).get_context_data(**kwargs) + related = [] + for obj in self.object.related.all(): + model = apps.get_model(obj.post_model.app_label, obj.post_model.model) + related.append(model.objects.get(slug=obj.slug)) + context['related'] = related + return context + + def get_template_names(self): + obj = self.get_object() + return ["posts/%s_detail.html" % obj.get_post_type_display(), 'posts/post_detail.html'] + + +class PostDetailViewTXT(PostDetailView): + template_name = "posts/entry_detail.txt" + + +class PostsRSSFeedView(Feed): + title = "VanLifeReviews.com: " + link = "/" + description = "Latest reviews, stories and guides" + description_template = 'feeds/blog_description.html' + + def items(self): + return Post.objects.filter(status__exact=1).order_by('-pub_date')[:10] + + def item_pubdate(self, item): + """ + Takes an item, as returned by items(), and returns the item's + pubdate. + """ + return item.pub_date diff --git a/app/posts/views/src_views.py b/app/posts/views/src_views.py new file mode 100644 index 0000000..afb6a6d --- /dev/null +++ b/app/posts/views/src_views.py @@ -0,0 +1,96 @@ +from django.views.generic import ListView +from django.views.generic.detail import DetailView +from django.contrib.syndication.views import Feed +from django.urls import reverse +from django.conf import settings + +#from paypal.standard.forms import PayPalPaymentsForm +from utils.views import PaginatedListView +from ..models import Post, PostType + + +class SrcListView(PaginatedListView): + model = Post + template_name="posts/src_list.html" + + def get_queryset(self): + queryset = super(SrcListView, self).get_queryset() + return queryset.filter(post_type=PostType.SRC).filter(status__exact=1).order_by('-pub_date') + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = super(SrcListView, self).get_context_data(**kwargs) + #context['topics'] = Topic.objects.all() + context['breadcrumbs'] = ['src',] + return context + + +class SrcDetailView(DetailView): + model = Post + slug_field = "slug" + template_name="posts/src_detail.html" + + +class SrcDetailViewTXT(SrcDetailView): + template_name = "jrnl/entry_detail.txt" + + +class TopicListView(ListView): + template_name = 'src/topic_list.html' + + def get_queryset(self): + return SrcPost.objects.filter(topics__slug=self.kwargs['slug']) + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = super(TopicListView, self).get_context_data(**kwargs) + context['topic'] = Topic.objects.get(slug__exact=self.kwargs['slug']) + return context + + +class SrcRSSFeedView(Feed): + title = "luxagraf:src Code and Technology" + link = "/src/" + description = "Latest postings to luxagraf.net/src" + description_template = 'feeds/blog_description.html' + + def items(self): + return SrcPost.objects.filter(status__exact=1).order_by('-pub_date')[:10] + + +""" +class BookListView(ListView): + template_name = "archives/src_books.html" + + def queryset(self): + return Book.objects.filter(status__exact=1) + + +class BookDetailView(DetailView): + model = Book + + def get_template_names(self): + book = self.get_object() + return [book.template_name] + + def get_context_data(self, **kwargs): + # Call the base implementation first to get a context + context = super(BookDetailView, self).get_context_data(**kwargs) + book = self.get_object() + if book.price_sale < book.price: + price = book.price_sale + else: + price = book.price + #paypal_dict = { + # "business": settings.PAYPAL_RECEIVER_EMAIL, + # "amount": price, + # "item_name": book.title, + # "invoice": "unique-invoice-id", + # "notify_url": "https://luxagraf.net/src/paypal/" + reverse('src:paypal-ipn'), + # "return_url": "https://luxagraf.net/src/thank-you", + # "cancel_return": "https://luxagraf.net/src/books/", + #} + #context['paypal_form'] = PayPalPaymentsForm(initial=paypal_dict) + return context + +""" diff --git a/config/base_urls.py b/config/base_urls.py index 4c4e356..1196142 100644 --- a/config/base_urls.py +++ b/config/base_urls.py @@ -52,19 +52,15 @@ urlpatterns = [ path(r'locations/', include('locations.urls')), path(r'expenses/', include('expenses.urls', namespace='expenses')), path(r'photos/', include('photos.urls')), - path(r'field-test/', include('posts.guide_urls')), - re_path(r'^field-test/$', RedirectView.as_view(url='/field-tests/')), - path(r'field-tests/', include('posts.guide_urls', namespace='guide-list')), - path(r'review/', include('posts.review_urls')), - re_path(r'^review/$', RedirectView.as_view(url='/guides/')), - path(r'essay/', include('posts.essay_urls')), + path(r'guide/', include('posts.urls.guide_urls', namespace='guide')), + path(r'essay/', include('posts.urls.essay_urls')), re_path(r'^essay/$', RedirectView.as_view(url='/essays/')), - path(r'essays/', include('posts.essay_urls', namespace='essay-list')), + path(r'essays/', include('posts.urls.essay_urls', namespace='essay-list')), path(r'book-notes/', include('books.urls')), path(r'people/', include('people.urls')), path(r'dialogues/', include('sightings.urls', namespace='sightings')), path(r'field-notes/', include('fieldnotes.urls', namespace='fieldnotes')), - path(r'src/', include('src.urls', namespace='src')), + path(r'src/', include('posts.urls.src_urls', namespace='src')), #path(r'essays/', include('essays.urls', namespace='essays')), path(r'work/', include('resume.urls', namespace='resume')), path(r'map', include('locations.urls', namespace='map')), diff --git a/design/sass/_header.scss b/design/sass/_header.scss index f819d54..9eb9b1b 100644 --- a/design/sass/_header.scss +++ b/design/sass/_header.scss @@ -53,7 +53,7 @@ padding: 0.25em 0.5em; a { text-decoration: none; - color: lighten(#505050, 20); + color: lighten(#505050, 15); &:visited { color: lighten(#505050, 20); } @@ -72,6 +72,7 @@ li { display: inline; margin: 0 0.25em; + color: lighten(#505050, 30); &:after { content: "\00b7"; color: #999999; |