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.
This commit is contained in:
parent
9447528938
commit
956f8c6fda
23 changed files with 277 additions and 202 deletions
|
@ -18,7 +18,12 @@
|
||||||
#
|
#
|
||||||
from django.contrib import admin
|
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)
|
@admin.register(CastTag)
|
||||||
|
@ -26,12 +31,10 @@ class CastTagAdmin(admin.ModelAdmin):
|
||||||
prepopulated_fields = {'slug': ('label',)}
|
prepopulated_fields = {'slug': ('label',)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@admin.register(Cast)
|
@admin.register(Cast)
|
||||||
class CastAdmin(admin.ModelAdmin):
|
class CastAdmin(admin.ModelAdmin):
|
||||||
list_display = ('pub_date', 'title')
|
list_display = ('pub_date', 'title')
|
||||||
list_filter = ['pub_date']
|
list_filter = ['pub_date', 'podcast']
|
||||||
date_hierarchy = 'pub_date'
|
date_hierarchy = 'pub_date'
|
||||||
search_fields = ['title', 'summary', 'body']
|
search_fields = ['title', 'summary', 'body']
|
||||||
prepopulated_fields = {'slug': ("title",)}
|
prepopulated_fields = {'slug': ("title",)}
|
||||||
|
|
|
@ -21,10 +21,12 @@ from datetime import datetime
|
||||||
|
|
||||||
from django.contrib.sites.shortcuts import get_current_site
|
from django.contrib.sites.shortcuts import get_current_site
|
||||||
from django.contrib.syndication.views import Feed, add_domain
|
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 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
|
# FIXME: Settings here should not be hard-coded for given casts, but
|
||||||
# should instead have settings from the main screen.
|
# 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('dc:creator', self.feed['dcCreator'])
|
||||||
handler.addQuickElement('itunes:explicit', self.feed['iTunesExplicit'])
|
handler.addQuickElement('itunes:explicit', self.feed['iTunesExplicit'])
|
||||||
handler.addQuickElement('itunes:block', self.feed['iTunesBlock'])
|
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('media:thumbnail', '' , { 'url' : self.feed['rssImage']['url'] })
|
||||||
handler.addQuickElement('itunes:image', '' , { 'href' : self.feed['iTunesImage']['url']})
|
handler.addQuickElement('itunes:image', '' , { 'href' : self.feed['iTunesImage']['url']})
|
||||||
|
@ -188,7 +190,7 @@ class CastFeed(CastFeedBase):
|
||||||
link = "/cast/"
|
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."
|
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_email = "podcast@faif.us"
|
||||||
author_link = "http://www.faif.us/"
|
author_link = "https://sfconservancy.org/"
|
||||||
author_name = "Software Freedom Conservancy"
|
author_name = "Software Freedom Conservancy"
|
||||||
title_template = "feeds/podcast_title.html"
|
title_template = "feeds/podcast_title.html"
|
||||||
description_template = "feeds/podcast_description.html"
|
description_template = "feeds/podcast_description.html"
|
||||||
|
@ -202,14 +204,18 @@ class CastFeed(CastFeedBase):
|
||||||
self.is_secure = request.is_secure()
|
self.is_secure = request.is_secure()
|
||||||
return super().get_feed(obj, request)
|
return super().get_feed(obj, request)
|
||||||
|
|
||||||
def items(self):
|
def get_object(self, request, podcast_slug):
|
||||||
return Cast.objects.filter(pub_date__lte=datetime.now()).order_by('-pub_date')
|
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):
|
def item_pubdate(self, item):
|
||||||
return item.pub_date
|
return item.pub_date
|
||||||
|
|
||||||
def item_link(self, item):
|
def item_link(self, item):
|
||||||
return item.get_absolute_url()
|
return episode_url(self.podcast, item)
|
||||||
|
|
||||||
def item_author_email(self, obj):
|
def item_author_email(self, obj):
|
||||||
return "oggcast@faif.us"
|
return "oggcast@faif.us"
|
||||||
|
@ -218,7 +224,7 @@ class CastFeed(CastFeedBase):
|
||||||
return "Software Freedom Conservancy"
|
return "Software Freedom Conservancy"
|
||||||
|
|
||||||
def item_author_link(self, obj):
|
def item_author_link(self, obj):
|
||||||
return "http://faif.us"
|
return "https://sfconservancy.org"
|
||||||
|
|
||||||
def item_categories(self, item):
|
def item_categories(self, item):
|
||||||
return ('Technology',)
|
return ('Technology',)
|
||||||
|
@ -264,19 +270,17 @@ class OggCastFeed(CastFeed):
|
||||||
return item.ogg_length
|
return item.ogg_length
|
||||||
|
|
||||||
|
|
||||||
feed_dict = {
|
def view(request, podcast_slug):
|
||||||
'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):
|
|
||||||
"""Listing of all available feeds
|
"""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()
|
feeds = feed_dict.values()
|
||||||
return render(request, "feeds.html", {'feeds': feeds})
|
return render(request, "feeds.html", {'podcast': podcast,
|
||||||
|
'feeds': feeds})
|
||||||
|
|
|
@ -19,19 +19,19 @@
|
||||||
|
|
||||||
from datetime import datetime
|
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
|
"""Cast front page view
|
||||||
Performs all object queries necessary to render the front page.
|
Performs all object queries necessary to render the front page.
|
||||||
"""
|
"""
|
||||||
|
podcast = get_object_or_404(Podcast, slug=podcast_slug)
|
||||||
cast = Cast.objects.all().filter(pub_date__lte=datetime.now())[:3]
|
cast = Cast.objects.filter(podcast=podcast, pub_date__lte=datetime.now())[:3]
|
||||||
|
|
||||||
c = {
|
c = {
|
||||||
'cast': cast,
|
'cast': cast,
|
||||||
|
'podcast': podcast,
|
||||||
}
|
}
|
||||||
return render(request, "podjango/frontpage.html", c)
|
return render(request, "podjango/frontpage.html", c)
|
||||||
|
|
33
conservancy/podjango/migrations/0003_podcast_cast_podcast.py
Normal file
33
conservancy/podjango/migrations/0003_podcast_cast_podcast.py
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
# 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'),
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,35 @@
|
||||||
|
# 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,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
# 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),
|
||||||
|
),
|
||||||
|
]
|
|
@ -22,6 +22,16 @@ from django.db import models
|
||||||
from django.urls import reverse
|
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):
|
class CastTag(models.Model):
|
||||||
"""Tagging for casts"""
|
"""Tagging for casts"""
|
||||||
|
|
||||||
|
@ -30,13 +40,13 @@ class CastTag(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'cast_tags' # legacy
|
db_table = 'cast_tags' # legacy
|
||||||
|
verbose_name = 'episode tag'
|
||||||
|
verbose_name_plural = 'episode tags'
|
||||||
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.label
|
return self.label
|
||||||
|
|
||||||
def get_absolute_url(self):
|
|
||||||
return reverse('podjango:cast') + "?tag=%s" % self.slug
|
|
||||||
|
|
||||||
|
|
||||||
class CastManager(models.Manager):
|
class CastManager(models.Manager):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
|
@ -45,13 +55,14 @@ class CastManager(models.Manager):
|
||||||
|
|
||||||
|
|
||||||
class Cast(models.Model):
|
class Cast(models.Model):
|
||||||
"""Cast"""
|
"""A podcast episode."""
|
||||||
|
|
||||||
title = models.CharField(max_length=200)
|
title = models.CharField(max_length=200)
|
||||||
slug = models.SlugField(unique=True)
|
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.")
|
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.")
|
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()
|
pub_date = models.DateTimeField()
|
||||||
|
podcast = models.ManyToManyField(Podcast)
|
||||||
tags = models.ManyToManyField(CastTag, blank=True)
|
tags = models.ManyToManyField(CastTag, blank=True)
|
||||||
ogg_path = models.CharField(
|
ogg_path = models.CharField(
|
||||||
max_length=300, blank=True,
|
max_length=300, blank=True,
|
||||||
|
@ -69,23 +80,16 @@ class Cast(models.Model):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
db_table = 'casts_entries' # legacy
|
db_table = 'casts_entries' # legacy
|
||||||
verbose_name_plural = 'casts'
|
verbose_name = 'episode'
|
||||||
|
verbose_name_plural = 'episodes'
|
||||||
ordering = ('-pub_date',)
|
ordering = ('-pub_date',)
|
||||||
get_latest_by = 'pub_date'
|
get_latest_by = 'pub_date'
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def month_str(self):
|
||||||
return reverse(
|
return self.pub_date.strftime("%b").lower()
|
||||||
'podjango:detail',
|
|
||||||
kwargs={
|
|
||||||
'year': self.pub_date.year,
|
|
||||||
'month': self.pub_date.strftime("%b").lower(),
|
|
||||||
'day': self.pub_date.day,
|
|
||||||
'slug': self.slug,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
def is_recent(self):
|
def is_recent(self):
|
||||||
return self.pub_date > (datetime.now() - timedelta(days=14))
|
return self.pub_date > (datetime.now() - timedelta(days=14))
|
||||||
|
|
|
@ -17,19 +17,4 @@
|
||||||
}
|
}
|
||||||
a.feedlink img { margin-left: 0.5rem }
|
a.feedlink img { margin-left: 0.5rem }
|
||||||
</style>
|
</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 %}
|
{% 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…</a></p>
|
|
||||||
{% endblock %}
|
|
||||||
{% endcomment %}
|
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
<!-- 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" %}
|
|
||||||
|
|
||||||
{% block subtitle %}Archive: {{ day|date:"F j, Y" }} - {% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' %}">The Corresponding Source</h1>
|
|
||||||
|
|
||||||
<h2>Archive: {{ day|date:"F j, Y" }}</h2>
|
|
||||||
|
|
||||||
{% for object in object_list %}
|
|
||||||
<div class="pa2 mb2" style="background: #F0FFB8">
|
|
||||||
<h3><a href="{{ object.get_absolute_url }}">{{ object.title|safe }}</a></h3>
|
|
||||||
<p class="date">{{ object.pub_date|date:"F j, Y" }}</p>
|
|
||||||
{{ object.summary|safe }}
|
|
||||||
<p><span class="continued"><a href="{{ object.get_absolute_url
|
|
||||||
}}">Read More...</a></span></p>
|
|
||||||
<p>Released on {{ object.pub_date|date:"F j, Y" }}; its running time is {{ object.duration }}</p>
|
|
||||||
{% if object.tags.all %}<p class="blog-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 %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,27 +0,0 @@
|
||||||
<!-- 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" %}
|
|
||||||
|
|
||||||
{% block subtitle %}Archive: {{ month|date:"F, Y" }} - {% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' %}">The Corresponding Source</h1>
|
|
||||||
|
|
||||||
<h2>Archive: {{ month|date:"F, Y" }}</h2>
|
|
||||||
|
|
||||||
{% for object in object_list %}
|
|
||||||
<div class="pa2 mb2" style="background: #F0FFB8">
|
|
||||||
<h3><a href="{{ object.get_absolute_url }}">{{ object.title|safe }}</a></h3>
|
|
||||||
<p class="date">{{ object.pub_date|date:"F j, Y" }}</p>
|
|
||||||
{{ object.summary|safe }}
|
|
||||||
<p><span class="continued"><a href="{{ object.get_absolute_url
|
|
||||||
}}">Read More...</a></span></p>
|
|
||||||
<p>Released on {{ object.pub_date|date:"F j, Y" }}; its running time is {{ object.duration }}</p>
|
|
||||||
{% if object.tags.all %}<p class="blog-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 %}
|
|
||||||
</div>
|
|
||||||
{% endfor %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -1,22 +0,0 @@
|
||||||
<!-- 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" %}
|
|
||||||
|
|
||||||
{% block subtitle %}Archive: {{ year }} - {% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<h1>{% include 'podjango/feed_links.inc.html' %} <a href="{% url 'podjango:cast-home' %}">The Corresponding Source</h1>
|
|
||||||
|
|
||||||
<h2>Archive: {{ year }}</h2>
|
|
||||||
|
|
||||||
<ul>
|
|
||||||
{% for object in object_list %}
|
|
||||||
<li><a href="{{ object.get_absolute_url }}"><b>{{ object.title|safe }}</b></a><br/>
|
|
||||||
<i>{{ object.pub_date|date:"F j, Y" }}; duration: {{ object.duration }}</i></li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
|
@ -4,11 +4,13 @@
|
||||||
<!-- and/or convey this template in any form. -->
|
<!-- and/or convey this template in any form. -->
|
||||||
{% extends "podjango/base_podcast.html" %}
|
{% 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 %}
|
{% 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>
|
<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>
|
<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" %}
|
{% include "podjango/license.inc.html" %}
|
||||||
</div>
|
</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…</a></span></p>
|
<p><span class="continued"><a href="{% url 'podjango:cast' podcast_slug=podcast.slug %}">Other episodes…</a></span></p>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -4,15 +4,23 @@
|
||||||
<!-- and/or convey this template in any form. -->
|
<!-- and/or convey this template in any form. -->
|
||||||
{% extends "podjango/base_podcast.html" %}
|
{% 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 %}
|
{% 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 %}
|
{% if tags %}
|
||||||
<p>Displaying casts
|
<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>
|
</p>
|
||||||
{% endif %}
|
{% 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.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 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>
|
<p class="date">{{ object.pub_date|date:"F j, Y" }}</p>
|
||||||
<h4>Summary</h4>
|
<h4>Summary</h4>
|
||||||
|
|
||||||
|
@ -36,7 +44,7 @@ tagged {% for tag in tags %}{% if not forloop.last %}{% if not forloop.first %},
|
||||||
{{ object.body|safe }}
|
{{ object.body|safe }}
|
||||||
</div>
|
</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>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
{% load static %}
|
{% 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]"/>
|
<img src="{% static 'podjango/img/cast/rss-audioogg.png' %}" alt="[Ogg/Vorbis Audio RSS]"/>
|
||||||
</a>
|
</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]"/>
|
<img src="{% static 'podjango/img/cast/rss-audiomp3.png' %}" alt="[MP3 Audio RSS]"/>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -1,37 +1,35 @@
|
||||||
{% extends "podjango/base_podcast.html" %}
|
{% 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">
|
<div class="singleColumn">
|
||||||
|
|
||||||
<h1>The Corresponding Source</h1>
|
<h1>{{ podcast.title }}</h1>
|
||||||
|
|
||||||
<p>The Corresponding Source (formerly Free as in Freedom) is a bi-weekly oggcast, hosted and presented by
|
{{ podcast.long_description|safe }}
|
||||||
<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>
|
|
||||||
|
|
||||||
{% include "podjango/credits.inc.html" %}
|
|
||||||
{% include "podjango/feedback.inc.html" %}
|
|
||||||
|
|
||||||
<h2>Follow the RSS and Other Feeds</h2>
|
<h2>Follow the RSS and Other Feeds</h2>
|
||||||
|
|
||||||
<p>There is RSS for both <a href="{% url 'podjango:feed-ogg' %}">ogg format</a>
|
<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' %}">mp3 format</a>.<!-- These links <em>might</em>
|
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' %}">subscribe to the show</a> <a href="https://itunes.apple.com/us/podcast/free-as-in-freedom/id450458894">with proprietary Apple devices.</a>--></p>
|
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 %}
|
{% for cc in cast %}
|
||||||
<div class="pa2 mb2" style="background: #F0FFB8">
|
<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.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>
|
<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>
|
<p class="date">{{ cc.pub_date|date:"F j, Y" }}</p>
|
||||||
{{ cc.summary|safe }}
|
{{ cc.summary|safe }}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<p><a href="{% url 'podjango:cast' %}">All oggcasts…</a></p>
|
<p><a href="{% url 'podjango:cast' podcast_slug=podcast.slug %}">All oggcasts…</a></p>
|
||||||
</div>
|
</div>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
18
conservancy/podjango/templates/podjango/podcasts.html
Normal file
18
conservancy/podjango/templates/podjango/podcasts.html
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<!-- 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 %}
|
0
conservancy/podjango/templatetags/__init__.py
Normal file
0
conservancy/podjango/templatetags/__init__.py
Normal file
26
conservancy/podjango/templatetags/podjango.py
Normal file
26
conservancy/podjango/templatetags/podjango.py
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
)
|
|
@ -20,39 +20,54 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.shortcuts import get_object_or_404
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
from django.views.generic.dates import (
|
from django.views.generic.dates import DateDetailView
|
||||||
DateDetailView,
|
|
||||||
DayArchiveView,
|
|
||||||
MonthArchiveView,
|
|
||||||
YearArchiveView,
|
|
||||||
)
|
|
||||||
|
|
||||||
from . import frontpage
|
from . import frontpage
|
||||||
from .feeds import Mp3CastFeed, OggCastFeed, view
|
from .feeds import Mp3CastFeed, OggCastFeed, view
|
||||||
from .models import Cast, CastTag
|
from .models import Cast, CastTag, Podcast
|
||||||
from .views import custom_index, query
|
from . import views
|
||||||
|
|
||||||
app_name = 'podjango'
|
app_name = 'podjango'
|
||||||
|
|
||||||
extra_context = {}
|
extra_context = {}
|
||||||
info_dict = {
|
info_dict = {
|
||||||
'queryset': Cast.objects.all(),
|
|
||||||
'date_field': 'pub_date',
|
'date_field': 'pub_date',
|
||||||
'extra_context': extra_context,
|
'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 = [
|
urlpatterns = [
|
||||||
path('', frontpage.view, name='cast-home'),
|
path('', views.podcasts, name='podcasts'),
|
||||||
path('<int:year>/<month>/<int:day>/<slug:slug>/', DateDetailView.as_view(**info_dict), name='detail'),
|
path('<slug:podcast_slug>/', frontpage.view, name='cast-home'),
|
||||||
path('<int:year>/<month>/<int:day>/', DayArchiveView.as_view(**info_dict), name='day-archive'),
|
path(
|
||||||
path('<int:year>/<month>/', MonthArchiveView.as_view(**info_dict), name='month-archive'),
|
'<slug:podcast_slug>/<int:year>/<month>/<int:day>/<slug:slug>/',
|
||||||
path('<int:year>/', YearArchiveView.as_view(**info_dict), name='year-archive'),
|
PodcastDateDetailView.as_view(
|
||||||
path('all/', custom_index, dict(info_dict, paginate_by=20), name='cast'),
|
template_name='podjango/cast_detail.html',
|
||||||
path('feeds/ogg/', OggCastFeed(), name='feed-ogg'),
|
),
|
||||||
path('feeds/mp3/', Mp3CastFeed(), name='feed-mp3'),
|
name='detail'
|
||||||
path('feeds/', view, name='feeds'),
|
),
|
||||||
|
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:
|
if settings.DEBUG:
|
||||||
|
|
|
@ -22,7 +22,12 @@ from operator import or_
|
||||||
|
|
||||||
from django.shortcuts import get_object_or_404, render
|
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):
|
def OR_filter(field_name, objs):
|
||||||
|
@ -35,11 +40,12 @@ def last_name(person):
|
||||||
return person.formal_name.rpartition(' ')[2]
|
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
|
"""Cast list view that allows scrolling and also shows an index by
|
||||||
year.
|
year.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
podcast = get_object_or_404(Podcast, slug=podcast_slug)
|
||||||
kwargs = kwargs.copy()
|
kwargs = kwargs.copy()
|
||||||
kwargs['extra_context'] = kwargs.get('extra_context', {}).copy()
|
kwargs['extra_context'] = kwargs.get('extra_context', {}).copy()
|
||||||
extra_context = kwargs['extra_context']
|
extra_context = kwargs['extra_context']
|
||||||
|
@ -48,30 +54,26 @@ def custom_index(request, queryset, *args, **kwargs):
|
||||||
del kwargs['date_field']
|
del kwargs['date_field']
|
||||||
|
|
||||||
if not kwargs.get('allow_future', False):
|
if not kwargs.get('allow_future', False):
|
||||||
queryset = queryset.filter(**{'%s__lte' % date_field: datetime.now()})
|
queryset = Cast.objects.filter(
|
||||||
|
podcast=podcast,
|
||||||
authors = []
|
**{'%s__lte' % date_field: datetime.now()},
|
||||||
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))
|
|
||||||
|
|
||||||
tags = []
|
tags = []
|
||||||
if 'tag' in request.GET:
|
if 'tag' in request.GET:
|
||||||
tags = [get_object_or_404(CastTag, slug=tag)
|
tags = [get_object_or_404(CastTag, slug=tag)
|
||||||
for tag in request.GET.getlist('tag')]
|
for tag in request.GET.getlist('tag')]
|
||||||
extra_context['tags'] = tags
|
extra_context['tags'] = tags
|
||||||
queryset = queryset.filter(OR_filter('tags', tags))
|
queryset = queryset.filter(OR_filter('tags', tags), podcast=podcast)
|
||||||
|
|
||||||
if authors or tags:
|
if tags:
|
||||||
query_string = '&'.join(['author=%s' % a.username for a in authors]
|
query_string = '&'.join('tag=%s' % t.slug for t in tags)
|
||||||
+ ['tag=%s' % t.slug for t in tags])
|
|
||||||
extra_context['query_string'] = query_string
|
extra_context['query_string'] = query_string
|
||||||
|
|
||||||
else:
|
else:
|
||||||
date_list = queryset.dates(date_field, 'year')
|
date_list = queryset.dates(date_field, 'year')
|
||||||
extra_context['date_list'] = date_list
|
extra_context['date_list'] = date_list
|
||||||
|
|
||||||
# TODO
|
return render(request, 'podjango/cast_list.html', {'podcast': podcast,
|
||||||
return render(request, 'podjango/cast/cast_list.html', {'object_list': queryset})
|
'object_list': queryset,
|
||||||
|
'tags': tags})
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<ul>
|
<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/glossary.html">Glossary of Terms</a></li>
|
||||||
<li><a href="/copyleft-compliance/vizio.html">Vizio Lawsuit</a></li>
|
<li><a href="/copyleft-compliance/vizio.html">Vizio Lawsuit</a></li>
|
||||||
<li><a href="/press/qanda.html">Q&A</a></li>
|
<li><a href="/press/qanda.html">Q&A</a></li>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<ul>
|
<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="CopyleftCompliance"><a href="/copyleft-compliance/">Copyleft Compliance</a></li>
|
||||||
<li class="VizioTopBar"><a href="/copyleft-compliance/vizio.html">Vizio Lawsuit</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>
|
<li class="FIXME"><a href="/projects/">Member Projects</a></li>
|
||||||
|
|
|
@ -29,7 +29,7 @@ urlpatterns = [
|
||||||
path('admin/', admin.site.urls),
|
path('admin/', admin.site.urls),
|
||||||
path('assignment/', include('conservancy.assignment.urls')),
|
path('assignment/', include('conservancy.assignment.urls')),
|
||||||
path('blog/', include('conservancy.blog.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('contacts/', include('conservancy.contacts.urls')),
|
||||||
path('contractpatch/', include('conservancy.contractpatch.urls')),
|
path('contractpatch/', include('conservancy.contractpatch.urls')),
|
||||||
path('feeds/', feeds.view),
|
path('feeds/', feeds.view),
|
||||||
|
|
Loading…
Reference in a new issue