Changeset - 956f8c6fdaad
[Not reviewed]
3 14 6
Ben Sturmfels (bsturmfels) - 12 days ago 2024-04-25 05:32:24
ben@sturm.com.au
podjango: Add "Podcast" model to support multiple podcasts

Each Cast (episode) can belong to one or more Podcast, allowing episodes to be
shared between podcasts. This enables us introductory episodes to be delivered
in their own feed, but also included in the main "The Corresponding Source"
feed.

This required adding an additional `podcast_slug` argument to most views. The
date archive views were dropped because they're not linked to from anywhere.

Added a `podcasts` view as an index of all available Podcasts.
23 files changed with 277 insertions and 202 deletions:
0 comments (0 inline, 0 general)
conservancy/podjango/admin.py
Show inline comments
...
 
@@ -18,7 +18,12 @@
 
#
 
from django.contrib import admin
 

	
 
from .models import Cast, CastTag
 
from .models import Cast, CastTag, Podcast
 

	
 

	
 
@admin.register(Podcast)
 
class PodcastAdmin(admin.ModelAdmin):
 
    prepopulated_fields = {'slug': ('title',)}
 

	
 

	
 
@admin.register(CastTag)
...
 
@@ -26,12 +31,10 @@ class CastTagAdmin(admin.ModelAdmin):
 
    prepopulated_fields = {'slug': ('label',)}
 

	
 

	
 

	
 

	
 
@admin.register(Cast)
 
class CastAdmin(admin.ModelAdmin):
 
    list_display = ('pub_date', 'title')
 
    list_filter = ['pub_date']
 
    list_filter = ['pub_date', 'podcast']
 
    date_hierarchy = 'pub_date'
 
    search_fields = ['title', 'summary', 'body']
 
    prepopulated_fields = {'slug': ("title",)}
conservancy/podjango/feeds.py
Show inline comments
...
 
@@ -21,10 +21,12 @@ from datetime import datetime
 

	
 
from django.contrib.sites.shortcuts import get_current_site
 
from django.contrib.syndication.views import Feed, add_domain
 
from django.shortcuts import render
 
from django.shortcuts import get_object_or_404, render
 
from django.urls import reverse
 
from django.utils.feedgenerator import Rss201rev2Feed
 

	
 
from .models import Cast
 
from .models import Cast, Podcast
 
from .templatetags.podjango import episode_url
 

	
 
# FIXME: Settings here should not be hard-coded for given casts, but
 
# should instead have settings from the main screen.
...
 
@@ -103,7 +105,7 @@ def podcast_helper_add_root_elements(self, handler):
 
#    handler.addQuickElement('dc:creator', self.feed['dcCreator'])
 
    handler.addQuickElement('itunes:explicit', self.feed['iTunesExplicit'])
 
    handler.addQuickElement('itunes:block', self.feed['iTunesBlock'])
 
    handler.addQuickElement('generator', 'http://www.faif.us/code')
 
    handler.addQuickElement('generator', 'https://sfconservancy.org/')
 

	
 
    handler.addQuickElement('media:thumbnail', '' , { 'url' : self.feed['rssImage']['url'] })
 
    handler.addQuickElement('itunes:image', '' , { 'href' : self.feed['iTunesImage']['url']})
...
 
@@ -188,7 +190,7 @@ class CastFeed(CastFeedBase):
 
    link = "/cast/"
 
    description = "A bi-weekly discussion of legal, policy, and other issues in the open source and software freedom community (including occasional interviews) from Brooklyn, New York, USA.  Presented by Karen Sandler and Bradley M. Kuhn."
 
    author_email = "podcast@faif.us"
 
    author_link = "http://www.faif.us/"
 
    author_link = "https://sfconservancy.org/"
 
    author_name = "Software Freedom Conservancy"
 
    title_template = "feeds/podcast_title.html"
 
    description_template = "feeds/podcast_description.html"
...
 
@@ -202,14 +204,18 @@ class CastFeed(CastFeedBase):
 
        self.is_secure = request.is_secure()
 
        return super().get_feed(obj, request)
 

	
 
    def items(self):
 
        return Cast.objects.filter(pub_date__lte=datetime.now()).order_by('-pub_date')
 
    def get_object(self, request, podcast_slug):
 
        self.podcast = Podcast.objects.get(slug=podcast_slug)
 
        return self.podcast
 

	
 
    def items(self, obj):
 
        return Cast.objects.filter(podcast=obj, pub_date__lte=datetime.now()).order_by('-pub_date')
 

	
 
    def item_pubdate(self, item):
 
        return item.pub_date
 

	
 
    def item_link(self, item):
 
        return item.get_absolute_url()
 
        return episode_url(self.podcast, item)
 

	
 
    def item_author_email(self, obj):
 
        return "oggcast@faif.us"
...
 
@@ -218,7 +224,7 @@ class CastFeed(CastFeedBase):
 
        return "Software Freedom Conservancy"
 

	
 
    def item_author_link(self, obj):
 
        return "http://faif.us"
 
        return "https://sfconservancy.org"
 

	
 
    def item_categories(self, item):
 
        return ('Technology',)
...
 
@@ -264,19 +270,17 @@ class OggCastFeed(CastFeed):
 
        return item.ogg_length
 

	
 

	
 
feed_dict = {
 
    'cast-ogg': OggCastFeed,
 
    'cast-mp3': Mp3CastFeed,
 
}
 

	
 
# make each feed know its canonical url
 
for k, v in feed_dict.items():
 
    v.get_absolute_url = '/feeds/%s/' % k
 

	
 

	
 
def view(request):
 
def view(request, podcast_slug):
 
    """Listing of all available feeds
 
    """
 

	
 
    feed_dict = {
 
        'feed-ogg': OggCastFeed,
 
        'feed-mp3': Mp3CastFeed,
 
    }
 
    podcast = get_object_or_404(Podcast, slug=podcast_slug)
 
    # make each feed know its canonical url
 
    for k, v in feed_dict.items():
 
        v.get_absolute_url = reverse(f'podjango:{k}', kwargs={'podcast_slug': podcast.slug})
 
    feeds = feed_dict.values()
 
    return render(request, "feeds.html", {'feeds': feeds})
 
    return render(request, "feeds.html", {'podcast': podcast,
 
                                          'feeds': feeds})
conservancy/podjango/frontpage.py
Show inline comments
...
 
@@ -19,19 +19,19 @@
 

	
 
from datetime import datetime
 

	
 
from django.shortcuts import render
 
from django.shortcuts import get_object_or_404, render
 

	
 
from .models import Cast
 
from .models import Cast, Podcast
 

	
 

	
 
def view(request):
 
def view(request, podcast_slug):
 
    """Cast front page view
 
    Performs all object queries necessary to render the front page.
 
    """
 

	
 
    cast = Cast.objects.all().filter(pub_date__lte=datetime.now())[:3]
 

	
 
    podcast = get_object_or_404(Podcast, slug=podcast_slug)
 
    cast = Cast.objects.filter(podcast=podcast, pub_date__lte=datetime.now())[:3]
 
    c = {
 
        'cast': cast,
 
        'podcast': podcast,
 
    }
 
    return render(request, "podjango/frontpage.html", c)
conservancy/podjango/migrations/0003_podcast_cast_podcast.py
Show inline comments
 
new file 100644
 
# Generated by Django 4.2.11 on 2024-04-24 04:03
 

	
 
from django.db import migrations, models
 

	
 

	
 
class Migration(migrations.Migration):
 

	
 
    dependencies = [
 
        ('podjango', '0002_alter_cast_tags'),
 
    ]
 

	
 
    operations = [
 
        migrations.CreateModel(
 
            name='Podcast',
 
            fields=[
 
                (
 
                    'id',
 
                    models.AutoField(
 
                        auto_created=True,
 
                        primary_key=True,
 
                        serialize=False,
 
                        verbose_name='ID',
 
                    ),
 
                ),
 
                ('title', models.CharField(max_length=50)),
 
            ],
 
        ),
 
        migrations.AddField(
 
            model_name='cast',
 
            name='podcast',
 
            field=models.ManyToManyField(to='podjango.podcast'),
 
        ),
 
    ]
conservancy/podjango/migrations/0004_alter_cast_options_alter_casttag_options_and_more.py
Show inline comments
 
new file 100644
 
# Generated by Django 4.2.11 on 2024-04-24 04:10
 

	
 
from django.db import migrations, models
 

	
 

	
 
class Migration(migrations.Migration):
 

	
 
    dependencies = [
 
        ('podjango', '0003_podcast_cast_podcast'),
 
    ]
 

	
 
    operations = [
 
        migrations.AlterModelOptions(
 
            name='cast',
 
            options={
 
                'get_latest_by': 'pub_date',
 
                'ordering': ('-pub_date',),
 
                'verbose_name': 'episode',
 
                'verbose_name_plural': 'episodes',
 
            },
 
        ),
 
        migrations.AlterModelOptions(
 
            name='casttag',
 
            options={
 
                'verbose_name': 'episode tag',
 
                'verbose_name_plural': 'episode tags',
 
            },
 
        ),
 
        migrations.AddField(
 
            model_name='podcast',
 
            name='slug',
 
            field=models.SlugField(default='', unique=True),
 
            preserve_default=False,
 
        ),
 
    ]
conservancy/podjango/migrations/0005_podcast_long_description.py
Show inline comments
 
new file 100644
 
# Generated by Django 4.2.11 on 2024-04-25 01:21
 

	
 
from django.db import migrations, models
 

	
 

	
 
class Migration(migrations.Migration):
 

	
 
    dependencies = [
 
        ('podjango', '0004_alter_cast_options_alter_casttag_options_and_more'),
 
    ]
 

	
 
    operations = [
 
        migrations.AddField(
 
            model_name='podcast',
 
            name='long_description',
 
            field=models.TextField(blank=True),
 
        ),
 
    ]
conservancy/podjango/models.py
Show inline comments
...
 
@@ -22,6 +22,16 @@ from django.db import models
 
from django.urls import reverse
 

	
 

	
 
class Podcast(models.Model):
 
    """An ongoing series of episodes."""
 
    title = models.CharField(max_length=50)
 
    slug = models.SlugField(unique=True)
 
    long_description = models.TextField(blank=True)
 

	
 
    def __str__(self):
 
        return self.title
 

	
 

	
 
class CastTag(models.Model):
 
    """Tagging for casts"""
 

	
...
 
@@ -30,13 +40,13 @@ class CastTag(models.Model):
 

	
 
    class Meta:
 
        db_table = 'cast_tags'  # legacy
 
        verbose_name = 'episode tag'
 
        verbose_name_plural = 'episode tags'
 

	
 

	
 
    def __str__(self):
 
        return self.label
 

	
 
    def get_absolute_url(self):
 
        return reverse('podjango:cast') + "?tag=%s" % self.slug
 

	
 

	
 
class CastManager(models.Manager):
 
    def get_queryset(self):
...
 
@@ -45,13 +55,14 @@ class CastManager(models.Manager):
 

	
 

	
 
class Cast(models.Model):
 
    """Cast"""
 
    """A podcast episode."""
 

	
 
    title = models.CharField(max_length=200)
 
    slug = models.SlugField(unique=True)
 
    summary = models.TextField(help_text="Use raw HTML.  This summary is not included at the beginning of the body when the entry is displayed.  It used only for the material on the front page.")
 
    body = models.TextField(help_text="Use raw HTML.  Include the full body of any show notes or other information about this episode.  It will be labelled on the site as Show Notes.  It is included on the detail entry, and in the description data on the cast RSS feed.")
 
    pub_date = models.DateTimeField()
 
    podcast = models.ManyToManyField(Podcast)
 
    tags = models.ManyToManyField(CastTag, blank=True)
 
    ogg_path = models.CharField(
 
        max_length=300, blank=True,
...
 
@@ -69,23 +80,16 @@ class Cast(models.Model):
 

	
 
    class Meta:
 
        db_table = 'casts_entries'  # legacy
 
        verbose_name_plural = 'casts'
 
        verbose_name = 'episode'
 
        verbose_name_plural = 'episodes'
 
        ordering = ('-pub_date',)
 
        get_latest_by = 'pub_date'
 

	
 
    def __str__(self):
 
        return self.title
 

	
 
    def get_absolute_url(self):
 
        return reverse(
 
            'podjango:detail',
 
            kwargs={
 
                'year': self.pub_date.year,
 
                'month': self.pub_date.strftime("%b").lower(),
 
                'day': self.pub_date.day,
 
                'slug': self.slug,
 
            }
 
        )
 
    def month_str(self):
 
        return self.pub_date.strftime("%b").lower()
 

	
 
    def is_recent(self):
 
        return self.pub_date > (datetime.now() - timedelta(days=14))
conservancy/podjango/templates/podjango/base_podcast.html
Show inline comments
...
 
@@ -17,19 +17,4 @@
 
 }
 
 a.feedlink img { margin-left: 0.5rem }
 
</style>
 
<link rel="alternate" type="application/rss+xml" title="MP3 Audio Feed" href="{% url 'podjango:feed-mp3' %}" />
 
<link rel="alternate" type="application/rss+xml" title="Ogg/Vorbis Audio Feed" href="{% url 'podjango:feed-ogg' %}" />
 
{% endblock %}
 

	
 
{% comment %}
 
{% block internal_navigate %}
 
<h3>Tags</h3>
 
<ul>
 
{% for tag in all_tags %}
 
<li><a href="{{ tag.get_absolute_url }}">{{ tag.label }}</a></li>
 
{% endfor %}
 
</ul>
 

	
 
<p><a href="{% url 'podjango:cast' %}">All oggcasts&hellip;</a></p>
 
{% endblock %}
 
{% endcomment %}
conservancy/podjango/templates/podjango/cast/cast_archive_day.html
Show inline comments
 
deleted file
conservancy/podjango/templates/podjango/cast/cast_archive_month.html
Show inline comments
 
deleted file
conservancy/podjango/templates/podjango/cast/cast_archive_year.html
Show inline comments
 
deleted file
conservancy/podjango/templates/podjango/cast_detail.html
Show inline comments
...
 
@@ -4,11 +4,13 @@
 
<!-- and/or convey this template in any form. -->
 
{% extends "podjango/base_podcast.html" %}
 

	
 
{% block subtitle %}{{ object.title|striptags }} - The Corresponding Source  - {% endblock %}
 
{% load podjango %}
 

	
 
{% block subtitle %}{{ object.title|striptags }} - {{ podcast.title }} - {% endblock %}
 

	
 
{% block content %}
 

	
 
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' %}">The Corresponding Source</h1>
 
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' podcast_slug=podcast.slug %}">{{ podcast.title }}</h1>
 

	
 
<h2><a class="feedlink" href="{{ object.ogg_path }}">{% include 'podjango/audio_ogg_button.inc.html' %}</a>
 
<a class="feedlink" href="{{ object.mp3_path }}">{% include 'podjango/audio_mp3_button.inc.html' %}</a>
...
 
@@ -41,8 +43,8 @@ running time is {{ object.duration}}.</p>
 
{% include "podjango/license.inc.html" %}
 
</div>
 

	
 
{% if object.tags.all %}<p class="blog-tags">Tags: {% for tag in object.tags.all %}<a href="{{ tag.get_absolute_url }}">{{ tag.label }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</p>{% endif %}
 
{% if object.tags.all %}<p class="blog-tags">Tags: {% for tag in object.tags.all %}<a href="{% tag_url podcast tag %}">{{ tag.label }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</p>{% endif %}
 

	
 
<p><span class="continued"><a href="{% url 'podjango:cast' %}">Other episodes&hellip;</a></span></p>
 
<p><span class="continued"><a href="{% url 'podjango:cast' podcast_slug=podcast.slug %}">Other episodes&hellip;</a></span></p>
 

	
 
{% endblock %}
conservancy/podjango/templates/podjango/cast_list.html
Show inline comments
...
 
@@ -4,15 +4,23 @@
 
<!-- and/or convey this template in any form. -->
 
{% extends "podjango/base_podcast.html" %}
 

	
 
{% block subtitle %}The Corresponding Source - {% endblock %}
 
{% load podjango %}
 

	
 
{% block header %}
 
  {{ block.super }}
 
  <link rel="alternate" type="application/rss+xml" title="MP3 Audio Feed" href="{% url 'podjango:feed-mp3' podcast_slug=podcast.slug %}" />
 
  <link rel="alternate" type="application/rss+xml" title="Ogg/Vorbis Audio Feed" href="{% url 'podjango:feed-ogg' podcast_slug=podcast.slug %}" />
 
{% endblock %}
 

	
 
{% block subtitle %}{{ podcast.title }} - {% endblock %}
 

	
 
{% block content %}
 

	
 
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' %}">The Corresponding Source</h1>
 
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' podcast_slug=podcast.slug %}">{{ podcast.title }}</a></h1>
 

	
 
{% if tags %}
 
<p>Displaying casts
 
tagged {% for tag in tags %}{% if not forloop.last %}{% if not forloop.first %}, {% endif %}{% endif %}<a href="{{ tag.get_absolute_url }}">{{ tag.label }}</a>{% if forloop.revcounter == 2 %} or {% endif %}{% endfor %}
 
tagged: {% for tag in tags %}{% if not forloop.last %}{% if not forloop.first %}, {% endif %}{% endif %}<a href="{% tag_url podcast tag %}">{{ tag.label }}</a>{% if forloop.revcounter == 2 %} or {% endif %}{% endfor %}
 
</p>
 
{% endif %}
 

	
...
 
@@ -22,7 +30,7 @@ tagged {% for tag in tags %}{% if not forloop.last %}{% if not forloop.first %},
 
<a class="feedlink" href="{{ object.ogg_path }}">{% include 'podjango/audio_ogg_button.inc.html' %}</a>
 
<a class="feedlink" href="{{ object.mp3_path }}">{% include 'podjango/audio_mp3_button.inc.html' %}</a>
 

	
 
<a href="{{ object.get_absolute_url }}">{{ object.title|safe }}</a></h3>
 
<a href="{% episode_url podcast object %}">{{ object.title|safe }}</a></h3>
 
    <p class="date">{{ object.pub_date|date:"F j, Y" }}</p>
 
    <h4>Summary</h4>
 

	
...
 
@@ -36,7 +44,7 @@ tagged {% for tag in tags %}{% if not forloop.last %}{% if not forloop.first %},
 
      {{ object.body|safe }}
 
    </div>
 

	
 
    {% if object.tags.all %}<p class="cast-tags small">Tags: {% for tag in object.tags.all %}<a href="{{ tag.get_absolute_url }}">{{ tag.label }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</p>{% endif %}
 
    {% if object.tags.all %}<p class="cast-tags small">Tags: {% for tag in object.tags.all %}<a href="{% tag_url podcast tag %}">{{ tag.label }}</a>{% if not forloop.last %}, {% endif %}{% endfor %}</p>{% endif %}
 
    </div>
 
{% endfor %}
 

	
conservancy/podjango/templates/podjango/feed_links.inc.html
Show inline comments
 
{% load static %}
 

	
 
<a href="{% url 'podjango:feed-ogg' %}" class="feedlink">
 
<a href="{% url 'podjango:feed-ogg' podcast_slug=podcast.slug %}" class="feedlink">
 
  <img src="{% static 'podjango/img/cast/rss-audioogg.png' %}" alt="[Ogg/Vorbis Audio RSS]"/>
 
</a>
 
<a href="{% url 'podjango:feed-mp3' %}" class="feedlink">
 
<a href="{% url 'podjango:feed-mp3' podcast_slug=podcast.slug %}" class="feedlink">
 
  <img src="{% static 'podjango/img/cast/rss-audiomp3.png' %}" alt="[MP3 Audio RSS]"/>
 
</a>
conservancy/podjango/templates/podjango/frontpage.html
Show inline comments
 
{% extends "podjango/base_podcast.html" %}
 

	
 
{% block content %}
 
{% block header %}
 
  {{ block.super }}
 
  <link rel="alternate" type="application/rss+xml" title="MP3 Audio Feed" href="{% url 'podjango:feed-mp3' podcast_slug=podcast.slug %}" />
 
  <link rel="alternate" type="application/rss+xml" title="Ogg/Vorbis Audio Feed" href="{% url 'podjango:feed-ogg' podcast_slug=podcast.slug %}" />
 
{% endblock %}
 

	
 
{% block content %}
 
<div class="singleColumn">
 

	
 
<h1>The Corresponding Source</h1>
 

	
 
<p>The Corresponding Source (formerly Free as in Freedom) is a bi-weekly oggcast, hosted and presented by
 
<a href="http://ebb.org/bkuhn">Bradley M. Kuhn</a> and <a href="http://gnomg.org">Karen Sandler</a>.
 
The discussion includes legal, policy, and many other issues in the Free, Libre,
 
and Open Source Software (FLOSS) world.  Occasionally, guests join
 
Bradley and Karen to discuss various topics regarding FLOSS.</p>
 
<h1>{{ podcast.title }}</h1>
 

	
 
{% include "podjango/credits.inc.html" %}
 
{% include "podjango/feedback.inc.html" %}
 
{{ podcast.long_description|safe }}
 

	
 
<h2>Follow the RSS and Other Feeds</h2>
 

	
 
<p>There is RSS for both <a href="{% url 'podjango:feed-ogg' %}">ogg format</a>
 
  and  <a href="{% url 'podjango:feed-mp3' %}">mp3 format</a>.<!-- These links <em>might</em>
 
  work if you want to <a href="itpc://faif.us{% url 'podjango:feed-mp3' %}">subscribe to the show</a> <a href="https://itunes.apple.com/us/podcast/free-as-in-freedom/id450458894">with proprietary Apple devices.</a>--></p>
 
<p>There is RSS for both <a href="{% url 'podjango:feed-ogg' podcast_slug=podcast.slug %}">ogg format</a>
 
  and  <a href="{% url 'podjango:feed-mp3' podcast_slug=podcast.slug %}">mp3 format</a>.<!-- These links <em>might</em>
 
  work if you want to <a href="itpc://faif.us{% url 'podjango:feed-mp3' podcast_slug=podcast.slug %}">subscribe to the show</a> <a href="https://itunes.apple.com/us/podcast/free-as-in-freedom/id450458894">with proprietary Apple devices.</a>--></p>
 

	
 
<h2>{% include 'podjango/feed_links.inc.html' %}<a href="{% url 'podjango:cast' %}">Recent Shows</a></h2>
 
<h2>{% include 'podjango/feed_links.inc.html' %}<a href="{% url 'podjango:cast' podcast_slug=podcast.slug %}">Recent Shows</a></h2>
 

	
 
{% for cc in cast %}
 
<div class="pa2 mb2" style="background: #F0FFB8">
 
<a class="feedlink" href="{{ cc.ogg_path }}">{% include 'podjango/audio_ogg_button.inc.html' %}</a>
 
<a class="feedlink" href="{{ cc.mp3_path }}">{% include 'podjango/audio_mp3_button.inc.html' %}</a>
 
<h3><a href="{{ cc.get_absolute_url }}">{{ cc.title|safe }}</a></h3>
 
<h3><a href="{% url 'podjango:detail' podcast_slug=podcast.slug year=cc.pub_date.year month=cc.month_str day=cc.pub_date.day slug=cc.slug %}">{{ cc.title|safe }}</a></h3>
 
<p class="date">{{ cc.pub_date|date:"F j, Y" }}</p>
 
{{ cc.summary|safe }}
 
</div>
 
{% endfor %}
 
<p><a href="{% url 'podjango:cast' %}">All oggcasts&hellip;</a></p>
 
<p><a href="{% url 'podjango:cast' podcast_slug=podcast.slug %}">All oggcasts&hellip;</a></p>
 
</div>
 
{% endblock %}
conservancy/podjango/templates/podjango/podcasts.html
Show inline comments
 
new file 100644
 
<!-- FIXME: SFLC specific content -->
 
<!--  Copyright (C) 2008       Bradley M. Kuhn <bkuhn@ebb.org> -->
 
<!-- Permission is granted to copy, modify, redistribute, propagate,  -->
 
<!-- and/or convey this template in any form. -->
 
{% extends "podjango/base_podcast.html" %}
 

	
 
{% load podjango %}
 

	
 
{% block subtitle %}Casts - {% endblock %}
 

	
 
{% block content %}
 

	
 
<h1>Casts</h1>
 

	
 
{% for podcast in podcasts %}
 
  <p><a href="{% url 'podjango:cast-home' podcast_slug=podcast.slug %}">{{ podcast.title }}</a></p>
 
{% endfor %}
 
{% endblock %}
conservancy/podjango/templatetags/__init__.py
Show inline comments
 
new file 100644
conservancy/podjango/templatetags/podjango.py
Show inline comments
 
new file 100644
 
from django import template
 
from django.urls import reverse
 

	
 
register = template.Library()
 

	
 

	
 
@register.simple_tag
 
def tag_url(podcast, tag):
 
    return '{base_url}?tag={tag_slug}'.format(
 
        base_url=reverse('podjango:cast', kwargs={'podcast_slug': podcast.slug}),
 
        tag_slug=tag.slug
 
    )
 

	
 

	
 
@register.simple_tag
 
def episode_url(podcast, cast):
 
    return reverse(
 
        'podjango:detail',
 
        kwargs={
 
            'podcast_slug': podcast.slug,
 
            'year': cast.pub_date.year,
 
            'month': cast.pub_date.strftime('%b').lower(),
 
            'day': cast.pub_date.day,
 
            'slug': cast.slug,
 
        }
 
    )
conservancy/podjango/urls.py
Show inline comments
...
 
@@ -20,39 +20,54 @@
 
import datetime
 

	
 
from django.conf import settings
 
from django.shortcuts import get_object_or_404
 
from django.urls import path
 
from django.views.generic.dates import (
 
    DateDetailView,
 
    DayArchiveView,
 
    MonthArchiveView,
 
    YearArchiveView,
 
)
 
from django.views.generic.dates import DateDetailView
 

	
 
from . import frontpage
 
from .feeds import Mp3CastFeed, OggCastFeed, view
 
from .models import Cast, CastTag
 
from .views import custom_index, query
 
from .models import Cast, CastTag, Podcast
 
from . import views
 

	
 
app_name = 'podjango'
 

	
 
extra_context = {}
 
info_dict = {
 
    'queryset': Cast.objects.all(),
 
    'date_field': 'pub_date',
 
    'extra_context': extra_context,
 
    'template_name': 'podjango/cast/cast_detail.html',
 
}
 

	
 
class PodcastDateDetailView(DateDetailView):
 
    date_field = 'pub_date'
 
    model = Cast
 

	
 
    def get(self, request, podcast_slug, *args, **kwargs):
 
        self.podcast = get_object_or_404(Podcast, slug=podcast_slug)
 
        return super().get(request, *args, **kwargs)
 

	
 
    def get_queryset(self):
 
        return super().get_queryset().filter(podcast=self.podcast)
 

	
 
    def get_context_data(self, **kwargs):
 
        context = super().get_context_data(**kwargs)
 
        context['podcast'] = self.podcast
 
        return context
 

	
 

	
 
urlpatterns = [
 
    path('', frontpage.view, name='cast-home'),
 
    path('<int:year>/<month>/<int:day>/<slug:slug>/', DateDetailView.as_view(**info_dict), name='detail'),
 
    path('<int:year>/<month>/<int:day>/', DayArchiveView.as_view(**info_dict), name='day-archive'),
 
    path('<int:year>/<month>/', MonthArchiveView.as_view(**info_dict), name='month-archive'),
 
    path('<int:year>/', YearArchiveView.as_view(**info_dict), name='year-archive'),
 
    path('all/', custom_index, dict(info_dict, paginate_by=20), name='cast'),
 
    path('feeds/ogg/', OggCastFeed(), name='feed-ogg'),
 
    path('feeds/mp3/', Mp3CastFeed(), name='feed-mp3'),
 
    path('feeds/', view, name='feeds'),
 
    path('', views.podcasts, name='podcasts'),
 
    path('<slug:podcast_slug>/', frontpage.view, name='cast-home'),
 
    path(
 
        '<slug:podcast_slug>/<int:year>/<month>/<int:day>/<slug:slug>/',
 
        PodcastDateDetailView.as_view(
 
            template_name='podjango/cast_detail.html',
 
        ),
 
        name='detail'
 
    ),
 
    path('<slug:podcast_slug>/all/', views.custom_index, info_dict, name='cast'),
 
    path('<slug:podcast_slug>/feeds/ogg/', OggCastFeed(), name='feed-ogg'),
 
    path('<slug:podcast_slug>/feeds/mp3/', Mp3CastFeed(), name='feed-mp3'),
 
    path('<slug:podcast_slug>/feeds/', view, name='feeds'),
 
]
 

	
 
if settings.DEBUG:
conservancy/podjango/views.py
Show inline comments
...
 
@@ -22,7 +22,12 @@ from operator import or_
 

	
 
from django.shortcuts import get_object_or_404, render
 

	
 
from .models import CastTag
 
from .models import Cast, CastTag, Podcast
 

	
 

	
 
def podcasts(request):
 
    podcasts = Podcast.objects.all()
 
    return render(request, 'podjango/podcasts.html', {'podcasts': podcasts})
 

	
 

	
 
def OR_filter(field_name, objs):
...
 
@@ -35,11 +40,12 @@ def last_name(person):
 
    return person.formal_name.rpartition(' ')[2]
 

	
 

	
 
def custom_index(request, queryset, *args, **kwargs):
 
def custom_index(request, podcast_slug, *args, **kwargs):
 
    """Cast list view that allows scrolling and also shows an index by
 
    year.
 
    """
 

	
 
    podcast = get_object_or_404(Podcast, slug=podcast_slug)
 
    kwargs = kwargs.copy()
 
    kwargs['extra_context'] = kwargs.get('extra_context', {}).copy()
 
    extra_context = kwargs['extra_context']
...
 
@@ -48,30 +54,26 @@ def custom_index(request, queryset, *args, **kwargs):
 
    del kwargs['date_field']
 

	
 
    if not kwargs.get('allow_future', False):
 
        queryset = queryset.filter(**{'%s__lte' % date_field: datetime.now()})
 

	
 
    authors = []
 
    if 'author' in request.GET:
 
        authors = [get_object_or_404(Person, username=author)
 
                   for author in request.GET.getlist('author')]
 
        extra_context['authors'] = authors
 
        queryset = queryset.filter(OR_filter('author', authors))
 
        queryset = Cast.objects.filter(
 
            podcast=podcast,
 
            **{'%s__lte' % date_field: datetime.now()},
 
        )
 

	
 
    tags = []
 
    if 'tag' in request.GET:
 
        tags = [get_object_or_404(CastTag, slug=tag)
 
                for tag in request.GET.getlist('tag')]
 
        extra_context['tags'] = tags
 
        queryset = queryset.filter(OR_filter('tags', tags))
 
        queryset = queryset.filter(OR_filter('tags', tags), podcast=podcast)
 

	
 
    if authors or tags:
 
        query_string = '&'.join(['author=%s' % a.username for a in authors]
 
                                + ['tag=%s' % t.slug for t in tags])
 
    if tags:
 
        query_string = '&'.join('tag=%s' % t.slug for t in tags)
 
        extra_context['query_string'] = query_string
 

	
 
    else:
 
        date_list = queryset.dates(date_field, 'year')
 
        extra_context['date_list'] = date_list
 

	
 
    # TODO
 
    return render(request, 'podjango/cast/cast_list.html', {'object_list': queryset})
 
    return render(request, 'podjango/cast_list.html', {'podcast': podcast,
 
                                                       'object_list': queryset,
 
                                                       'tags': tags})
conservancy/templates/submenus/learn_partial.html
Show inline comments
 
<ul>
 
  <li><a href="{% url 'podjango:cast-home' %}">The Corresponding Source</a></li>
 
  <li><a href="{% url 'podjango:cast-home' podcast_slug='the-corresponding-source' %}">The Corresponding Source</a></li>
 
  <li><a href="/copyleft-compliance/glossary.html">Glossary of Terms</a></li>
 
  <li><a href="/copyleft-compliance/vizio.html">Vizio Lawsuit</a></li>
 
  <li><a href="/press/qanda.html">Q&amp;A</a></li>
conservancy/templates/submenus/what_we_do_partial.html
Show inline comments
 
<ul>
 
  <li><a href="{% url 'podjango:cast-home' %}">The Corresponding Source</a></li>
 
  <li><a href="{% url 'podjango:cast-home' podcast_slug='the-corresponding-source' %}">The Corresponding Source</a></li>
 
  <li class="CopyleftCompliance"><a href="/copyleft-compliance/">Copyleft Compliance</a></li>
 
  <li class="VizioTopBar"><a href="/copyleft-compliance/vizio.html">Vizio Lawsuit</a></li>
 
  <li class="FIXME"><a href="/projects/">Member Projects</a></li>
conservancy/urls.py
Show inline comments
...
 
@@ -29,7 +29,7 @@ urlpatterns = [
 
    path('admin/', admin.site.urls),
 
    path('assignment/', include('conservancy.assignment.urls')),
 
    path('blog/', include('conservancy.blog.urls')),
 
    path('casts/the-corresponding-source/', include('conservancy.podjango.urls')),
 
    path('casts/', include('conservancy.podjango.urls')),
 
    path('contacts/', include('conservancy.contacts.urls')),
 
    path('contractpatch/', include('conservancy.contractpatch.urls')),
 
    path('feeds/', feeds.view),
0 comments (0 inline, 0 general)