podjango: Fix linting warnings

This commit is contained in:
Ben Sturmfels 2024-02-23 15:02:04 +11:00
parent ffa2889acb
commit 75e3ab4d35
Signed by: bsturmfels
GPG key ID: 023C05E2C9C068F0
8 changed files with 84 additions and 64 deletions

View file

@ -1,5 +1,7 @@
# To-do
* remove `ForceCanonicalHostnameMiddleware` by ensuring canonical redirect and HTTPS redirect is done by Apache
* serve a 400 in Apache for a hostname we don't explicitly support
* use `<detail>` elements for supporter page hidden sections, rather than complex jQuery - or consider Alpine.js
* replace `internalNavigate` with inline flexbox layout
* migrate to Django 4.2

View file

@ -24,8 +24,10 @@ from .models import Cast, CastTag
class CastTagAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('label',)}
admin.site.register(CastTag, CastTagAdmin)
class CastAdmin(admin.ModelAdmin):
list_display = ('pub_date', 'title')
list_filter = ['pub_date']

View file

@ -18,10 +18,7 @@
#
from datetime import datetime
import itertools
import operator
from django.conf import settings
from django.contrib.sites.shortcuts import get_current_site
from django.contrib.syndication.views import Feed, add_domain
from django.shortcuts import render
@ -53,33 +50,40 @@ class CastFeedBase(Feed):
if hasattr(getattr(item, attr), 'year'):
year = getattr(getattr(item, attr), 'year')
break
return { 'year' : year }
return {'year': year}
def for_podcast_feed_extra_kwargs(self, obj):
return { 'managingEditorNames' : 'Bradley and Karen',
'rssImage' : { 'url' : 'http://faif.us/img/cast/faif_144x144.jpg',
'width' : '144', 'height' : '144' },
'webMaster' : 'oggcast@faif.us (Bradley and Karen)',
'dcCreator' : 'oggcast@faif.us (Bradley and Karen)',
'iTunesExplicit' : 'No',
'iTunesBlock' : 'No',
'iTunesImage' : { 'url' : 'http://faif.us/img/cast/faif_300x300.jpg',
'title' : 'The Corresponding Source (formerly Free as in Freedom)',
'link' : self.author_link,
'type' : 'video/jpg'},
'category' : { 'name' : 'Government & Organizations', 'scheme' : 'http://www.itunes.com/dtds/podcast-1.0.dtd',
'subcats' : [ 'Non-Profit' ] },
'keywords' : 'open source, opensource, freesoftware, software freedom, legal, law, linux, free, license, gpl, lgpl, agpl, bsd',
'iTunesAuthor' : 'Software Freedom Conservancy',
'iTunesSubtitle' : 'Bi-Weekly Discussion of Legal, Policy, and Any other Issues in the Free, Libre, and Open Source Software (FLOSS) Community',
'copyrightHolder' : self.copyright_holder(),
'copyrightLicense' : self.license_no_html() }
return {
'managingEditorNames': 'Bradley and Karen',
'rssImage': {'url': 'http://faif.us/img/cast/faif_144x144.jpg',
'width': '144', 'height': '144'},
'webMaster': 'oggcast@faif.us (Bradley and Karen)',
'dcCreator': 'oggcast@faif.us (Bradley and Karen)',
'iTunesExplicit': 'No',
'iTunesBlock': 'No',
'iTunesImage': {'url': 'http://faif.us/img/cast/faif_300x300.jpg',
'title': 'The Corresponding Source (formerly Free as in Freedom)',
'link': self.author_link,
'type': 'video/jpg'},
'category': {'name': 'Government & Organizations', 'scheme': 'http://www.itunes.com/dtds/podcast-1.0.dtd',
'subcats': ['Non-Profit']},
'keywords': 'open source, opensource, freesoftware, software freedom, legal, law, linux, free, license, gpl, lgpl, agpl, bsd',
'iTunesAuthor': 'Software Freedom Conservancy',
'iTunesSubtitle': 'Bi-Weekly Discussion of Legal, Policy, and Any other Issues in the Free, Libre, and Open Source Software (FLOSS) Community',
'copyrightHolder': self.copyright_holder(),
'copyrightLicense': self.license_no_html(),
}
def for_podcast_item_extra_kwargs(self, item):
return { 'duration' : item.duration,
'year' : item.date_created.year,
'dcCreator' : 'oggcast@faif.us (Bradley and Karen)',
'intheitembkuhn' : item.__dict__.__str__()}
return {
'duration': item.duration,
'year': item.date_created.year,
'dcCreator': 'oggcast@faif.us (Bradley and Karen)',
'intheitembkuhn': item.__dict__.__str__(),
}
def podcast_helper_add_root_elements(self, handler):
handler.addQuickElement('managingEditor', self.feed['author_email']
@ -104,13 +108,13 @@ def podcast_helper_add_root_elements(self, handler):
# 'type' : self.feed['iTunesImage']['type']})
handler.addQuickElement("media:category", self.feed['category']['name'],
{ 'scheme': self.feed['category']['scheme']})
{'scheme': self.feed['category']['scheme']})
if not (self.feed['category']['subcats'] and len(self.feed['category']['subcats']) > 0):
handler.addQuickElement("itunes:category", '', { 'text': self.feed['category']['name']})
handler.addQuickElement("itunes:category", '', {'text': self.feed['category']['name']})
else:
handler.startElement("itunes:category", { 'text': self.feed['category']['name']})
handler.startElement("itunes:category", {'text': self.feed['category']['name']})
for cc in self.feed['category']['subcats']:
handler.addQuickElement("itunes:category", '', { 'text': cc })
handler.addQuickElement("itunes:category", '', {'text': cc})
handler.endElement("itunes:category")
handler.addQuickElement("media:keywords", self.feed['keywords'].replace(" ", ","))
@ -124,8 +128,8 @@ def podcast_helper_add_root_elements(self, handler):
handler.addQuickElement("itunes:subtitle", self.feed['iTunesSubtitle'])
handler.addQuickElement("itunes:author", self.feed['iTunesAuthor'])
handler.addQuickElement('atom:link', '', { 'rel' : "self", 'href' : self.feed['feed_url'],
'type' : "application/rss+xml"})
handler.addQuickElement('atom:link', '', {'rel': "self", 'href': self.feed['feed_url'],
'type': "application/rss+xml"})
years = {}
for ii in self.items: years[ii['year']] = 1
@ -139,6 +143,7 @@ def podcast_helper_add_root_elements(self, handler):
handler.addQuickElement('copyright', copyrightString)
handler.addQuickElement('media:copyright', "Copyright (C) " + copyrightString)
def podcast_helper_add_item_elements(self, handler, item):
handler.addQuickElement("itunes:explicit", self.feed['iTunesExplicit'])
handler.addQuickElement("itunes:block", self.feed['iTunesBlock'])
@ -147,9 +152,9 @@ def podcast_helper_add_item_elements(self, handler, item):
handler.addQuickElement("itunes:author", item['author_name'])
handler.addQuickElement("itunes:duration", item['duration'])
if 'enclosure' in item:
handler.addQuickElement('media:content', '', { 'url' : item['enclosure'].url,
'fileSize' : item['enclosure'].length,
'type' : item['enclosure'].mime_type})
handler.addQuickElement('media:content', '', {'url': item['enclosure'].url,
'fileSize': item['enclosure'].length,
'type': item['enclosure'].mime_type})
# http://www.feedforall.com/itune-tutorial-tags.htm
# http://www.feedforall.com/mediarss.htm
@ -210,7 +215,7 @@ class CastFeed(CastFeedBase):
return "http://faif.us"
def item_categories(self, item):
return ('Technology',)
return ('Technology',)
def copyright_holder(self): return "Software Freedom Conservancy"
@ -236,6 +241,7 @@ class Mp3CastFeed(CastFeed):
def item_enclosure_length(self, item):
return item.mp3_length
class OggCastFeed(CastFeed):
def item_enclosure_mime_type(self): return "audio/ogg"
def item_enclosure_url(self, item):
@ -243,6 +249,7 @@ class OggCastFeed(CastFeed):
def item_enclosure_length(self, item):
return item.ogg_length
feed_dict = {
'cast-ogg': OggCastFeed,
'cast-mp3': Mp3CastFeed,
@ -252,6 +259,7 @@ feed_dict = {
for k, v in feed_dict.items():
v.get_absolute_url = '/feeds/%s/' % k
def view(request):
"""Listing of all available feeds
"""

View file

@ -17,7 +17,7 @@
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
from datetime import datetime, timedelta
from datetime import datetime
from django.shortcuts import render

View file

@ -53,10 +53,12 @@ class Cast(models.Model):
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()
tags = models.ManyToManyField(CastTag, blank=True)
ogg_path = models.CharField(max_length=300, blank=True,
help_text="Local filename of the Ogg file, relative to webroot. File should be uploaded into the static media area for casts.")
mp3_path = models.CharField(max_length=300, blank=True,
help_text="Local filename of the mp3 file, relative to webroot. File should be uploaded into the static media area for casts.")
ogg_path = models.CharField(
max_length=300, blank=True,
help_text="Local filename of the Ogg file, relative to webroot. File should be uploaded into the static media area for casts.")
mp3_path = models.CharField(
max_length=300, blank=True,
help_text="Local filename of the mp3 file, relative to webroot. File should be uploaded into the static media area for casts.")
ogg_length = models.IntegerField(blank=False, help_text="size in bytes of ogg file")
mp3_length = models.IntegerField(blank=False, help_text="size in bytes of mp3 file")
duration = models.CharField(max_length=8, blank=False, help_text="length in hh:mm:ss of mp3 file")

View file

@ -4,6 +4,7 @@ from django import template
register = template.Library()
@register.filter
def date_within_past_days(value, arg):
# question: does datetime.now() do a syscall each time is it called?

View file

@ -17,10 +17,10 @@
# along with this program in a file in the toplevel directory called
# "AGPLv3". If not, see <http://www.gnu.org/licenses/>.
import datetime
from django.conf import settings
from django.conf.urls import include, url
from django.contrib import admin
from django.contrib.syndication.views import Feed
from django.conf.urls import url
from django.views.generic.dates import (
DateDetailView,
DayArchiveView,
@ -29,7 +29,7 @@ from django.views.generic.dates import (
)
from . import frontpage
from .feeds import Mp3CastFeed, OggCastFeed, feed_dict, view
from .feeds import Mp3CastFeed, OggCastFeed, view
from .models import Cast, CastTag
from .views import custom_index, query
@ -60,6 +60,7 @@ if settings.DEBUG:
from django.conf.urls.static import static
urlpatterns += static('/', document_root='podjango/static')
def all_tags_by_use_amount():
"""Returns all tags with an added 'cnt' attribute (how many times used)
@ -85,6 +86,7 @@ def all_tags_by_use_amount():
retval.sort(key=lambda x: -x.cnt)
return retval
# The functions are passed to the context uncalled so they will be
# called for each web request. If we want to only make these database
# queries a single time when a web server process begins, call both

View file

@ -21,9 +21,8 @@ from functools import reduce
from operator import or_
from django.shortcuts import get_object_or_404, render
from django.views.generic.list import ListView
from .models import Cast, CastTag
from .models import CastTag
def OR_filter(field_name, objs):
@ -31,9 +30,11 @@ def OR_filter(field_name, objs):
return reduce(or_,
[Q(**{field_name: x.id}) for x in objs])
def last_name(person):
return person.formal_name.rpartition(' ')[2]
def custom_index(request, queryset, *args, **kwargs):
"""Cast list view that allows scrolling and also shows an index by
year.
@ -75,6 +76,7 @@ def custom_index(request, queryset, *args, **kwargs):
# TODO
return render(request, 'podjango/cast/cast_list.html', {'object_list': queryset})
def query(request):
"""Page to query the cast based on and tags
"""
@ -82,15 +84,15 @@ def query(request):
if request.GET:
d = request.GET.copy()
if 'authors' in d.getlist('all'):
d.setlist('author', []) # remove author queries
d.setlist('author', []) # remove author queries
if 'tags' in d.getlist('all'):
d.setlist('tag', []) # remove tag queries
d.setlist('all', []) # remove "all" from the query string
d.setlist('tag', []) # remove tag queries
d.setlist('all', []) # remove "all" from the query string
base_url = '/cast/'
if 'rss' in d:
base_url = '/feeds/cast/'
d.setlist('rss', []) # remove it
d.setlist('rss', []) # remove it
query_string = d.urlencode()
@ -100,6 +102,7 @@ def query(request):
tags = CastTag.objects.all().order_by('label')
return render(request, 'podjango/cast/query.html', {'tags': tags})
def relative_redirect(request, path):
from django import http
from django.conf import settings