Changeset - c5289f39bb3c
[Not reviewed]
0 9 0
Ben Sturmfels (bsturmfels) - 2 months ago 2024-07-22 08:39:00
ben@sturm.com.au
Fix flake8 warnings
9 files changed with 37 insertions and 31 deletions:
0 comments (0 inline, 0 general)
conservancy/blog/models.py
Show inline comments
...
 
@@ -51,32 +51,32 @@ class Entry(models.Model, bsoup.SoupModelMixin):
 
        return ("/blog/%s/%s/"
 
                % (self.pub_date.strftime("%Y/%b/%d").lower(),
 
                   self.slug))
 

	
 
    def is_recent(self):
 
        return self.pub_date > (datetime.now() - timedelta(days=30))
 
        # question: does datetime.now() do a syscall each time is it called?
 

	
 
    # Ping google blogs and technorati.  Taken from
 
    # http://blog.foozia.com/blog/2007/apr/21/ping-technorati-your-django-blog-using-xml-rpc/
 
    def save(self):
 
        if settings.DEBUG or True: # "or True" means it is disabled always
 
            super().save()
 
            return
 

	
 
        blog_name = 'Software Freedom Conservancy Blog'
 
        blog_url =  'http://www.sfconservancy.org/blog/'
 
        post_url = ('http://www.sfconservancy.org'
 
                    + self.get_absolute_url())
 

	
 
        import xmlrpc.client
 

	
 
        # Ping Technorati
 
        j = xmlrpc.client.Server('http://rpc.technorati.com/rpc/ping')
 
        reply = j.weblogUpdates.ping(blog_name, blog_url)
 
        j.weblogUpdates.ping(blog_name, blog_url)
 

	
 
        # Ping Google Blog Search
 
        j = xmlrpc.client.Server('http://blogsearch.google.com/ping/RPC2')
 
        reply = j.weblogUpdates.ping(blog_name, blog_url, post_url)
 
        j.weblogUpdates.ping(blog_name, blog_url, post_url)
 

	
 
        # Call any superclass's method
 
        super().save()
conservancy/blog/views.py
Show inline comments
 
from datetime import datetime
 
from functools import reduce
 

	
 
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
 
from django.shortcuts import get_object_or_404, render
 
from django.views.generic import ListView
 
from django.views.generic.dates import (
 
    DateDetailView,
 
    DayArchiveView,
 
    MonthArchiveView,
 
    YearArchiveView,
 
)
 

	
 
from ..staff.models import Person
 
from .models import Entry, EntryTag
 
from .models import EntryTag
 

	
 

	
 
def OR_filter(field_name, objs):
 
    from django.db.models import Q
 
    return reduce(lambda x, y: x | y,
 
                  [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):
 
    """Blog list view that allows scrolling and also shows an index by
 
    year.
 
    """
 

	
 
    extra_context = kwargs.get('extra_context', {}).copy()
 
    date_field = 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)
conservancy/content/projects/policies/publish-policy.py
Show inline comments
...
 
@@ -25,90 +25,93 @@ except ImportError:
 

	
 
TEMPLATE_HEADER = """{% extends "base_projects.html" %}
 
{% block subtitle %}{% endblock %}
 
{% block submenuselection %}Policies{% endblock %}
 
{% block content %}
 

	
 
"""
 

	
 
TEMPLATE_FOOTER = """
 

	
 
{% endblock %}
 
"""
 

	
 
@contextlib.contextmanager
 
def run(cmd, encoding=None, ok_exitcodes=frozenset([0]), **kwargs):
 
    kwargs.setdefault('stdout', subprocess.PIPE)
 
    if encoding is None:
 
        mode = 'rb'
 
        no_data = b''
 
    else:
 
        mode = 'r'
 
        no_data = ''
 
    with contextlib.ExitStack() as exit_stack:
 
        proc = exit_stack.enter_context(subprocess.Popen(cmd, **kwargs))
 
        pipes = [exit_stack.enter_context(open(
 
                   getattr(proc, name).fileno(), mode, encoding=encoding, closefd=False))
 
                 for name in ['stdout', 'stderr']
 
                 if kwargs.get(name) is subprocess.PIPE]
 
        pipes = [
 
            exit_stack.enter_context(open(
 
                getattr(proc, name).fileno(), mode, encoding=encoding, closefd=False))
 
            for name in ['stdout', 'stderr']
 
            if kwargs.get(name) is subprocess.PIPE
 
        ]
 
        if pipes:
 
            yield (proc, *pipes)
 
        else:
 
            yield proc
 
        for pipe in pipes:
 
            for _ in iter(lambda: pipe.read(4096), no_data):
 
                pass
 
    if proc.returncode not in ok_exitcodes:
 
        raise subprocess.CalledProcessError(proc.returncode, cmd)
 

	
 
class GitPath:
 
    GIT_BIN = shutil.which('git')
 
    CLEAN_ENV = {k: v for k, v in os.environ.items() if not k.startswith('GIT_')}
 
    ANY_EXITCODE = range(-256, 257)
 
    IGNORE_ERRORS = {
 
        'ok_exitcodes': ANY_EXITCODE,
 
        'stderr': subprocess.DEVNULL,
 
    }
 
    STATUS_CLEAN_OR_UNMANAGED = frozenset(' ?')
 

	
 
    def __init__(self, path, encoding, env=None):
 
        self.path = path
 
        self.dir_path = path if path.is_dir() else path.parent
 
        self.encoding = encoding
 
        self.run_defaults = {
 
            'cwd': str(self.dir_path),
 
            'env': env,
 
        }
 

	
 
    @classmethod
 
    def can_run(cls):
 
        return cls.GIT_BIN is not None
 

	
 
    def _run(self, cmd, encoding=None, ok_exitcodes=frozenset([0]), **kwargs):
 
        return run(cmd, encoding, ok_exitcodes, **self.run_defaults, **kwargs)
 

	
 
    def _cache(orig_func):
 
        attr_name = '_cached_' + orig_func.__name__
 

	
 
        @functools.wraps(orig_func)
 
        def cache_wrapper(self):
 
            try:
 
                return getattr(self, attr_name)
 
            except AttributeError:
 
                setattr(self, attr_name, orig_func(self))
 
                return getattr(self, attr_name)
 
        return cache_wrapper
 

	
 
    @_cache
 
    def is_work_tree(self):
 
        with self._run([self.GIT_BIN, 'rev-parse', '--is-inside-work-tree'],
 
                       self.encoding, **self.IGNORE_ERRORS) as (_, stdout):
 
            return stdout.readline() == 'true\n'
 

	
 
    @_cache
 
    def status_lines(self):
 
        with self._run([self.GIT_BIN, 'status', '-z'],
 
                       self.encoding) as (_, stdout):
 
            return stdout.read().split('\0')
 

	
 
    @_cache
 
    def has_managed_modifications(self):
 
        return any(line and line[1] not in self.STATUS_CLEAN_OR_UNMANAGED
conservancy/feeds.py
Show inline comments
 
from datetime import datetime
 
from functools import reduce
 
import itertools
 
import operator
 

	
 
from django.conf import settings
 
from django.contrib.syndication.views import Feed
 
from django.shortcuts import render
 
from django.utils.feedgenerator import Rss201rev2Feed
 

	
 
from .blog.models import Entry as BlogEntry
 
from .news.models import PressRelease
 

	
 

	
 
class ConservancyFeedBase(Feed):
 
    def copyright_holder(self): return "Software Freedom Conservancy"
 
    def copyright_holder(self):
 
        return "Software Freedom Conservancy"
 

	
 
    def license_no_html(self): return "Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License."
 
    def license_no_html(self):
 
        return "Licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License."
 

	
 
    def item_copyright(self, item):
 
        year = 2008
 
        for attr in ('pub_date', 'date_created', 'date_last_modified'):
 
            if hasattr(item, attr):
 
                if hasattr(getattr(item, attr), 'year'):
 
                    year = getattr(getattr(item, attr), 'year')
 
                    break
 
        return 'Copyright (C) %d, %s.  %s' % (year, self.copyright_holder(), self.license_no_html())
 

	
 
    def item_extra_kwargs(self, item):
 
        year = 2008
 
        for attr in ('pub_date', 'date_created', 'date_last_modified'):
 
            if hasattr(item, attr):
 
                if hasattr(getattr(item, attr), 'year'):
 
                    year = getattr(getattr(item, attr), 'year')
 
                    break
 
        return { 'year' : year }
 

	
 
class PressReleaseFeed(Feed):
 
    get_absolute_url = '/feeds/news/'
 
    title = "Software Freedom Conservancy News"
 
    link = "/news/"
 
    description = ""
...
 
@@ -68,60 +70,58 @@ class OmnibusFeedType(Rss201rev2Feed):
 
    def add_item_elements(self, handler, item):
 
        super().add_item_elements(handler, item)
 
        # Block things that don't have an enclosure from iTunes in
 
        # case someone uploads this feed there.
 
        handler.addQuickElement("itunes:block", 'Yes')
 

	
 
class OmnibusFeed(ConservancyFeedBase):
 
    get_absolute_url = '/feeds/omnibus/'
 
    feed_type = OmnibusFeedType
 
    link ="/news/"
 
    title = "The Software Freedom Conservancy"
 
    description = "An aggregated feed of all RSS content available from the Software Freedom Conservancy, including both news items and blogs."
 
    title_template = "feeds/omnibus_title.html"
 
    description_template = "feeds/omnibus_description.html"
 
    author_email = "info@sfconservancy.org"
 
    author_link = "https://sfconservancy.org/"
 
    author_name = "Software Freedom Conservancy"
 

	
 
    def item_title(self, item):
 
        return item.headline
 

	
 
    def item_description(self, item):
 
        return item.summary
 

	
 
    def item_enclosure_mime_type(self): return "audio/mpeg"
 
    def item_enclosure_mime_type(self):
 
        return "audio/mpeg"
 

	
 
    def item_enclosure_url(self, item):
 
        if hasattr(item, 'mp3_path'):
 
            return "https://sfconservancy.org" + item.mp3_path
 
    def item_enclosure_length(self, item):
 
        if hasattr(item, 'mp3_path'):
 
            return item.mp3_length
 

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

	
 
    def item_author_name(self, item):
 
        if item.omnibus_type == "blog":
 
            return item.author.formal_name
 
        else:
 
            return "Software Freedom Conservancy"
 

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

	
 
    def item_author_email(self, item):
 
        if item.omnibus_type == "news":
 
            return "info@sfconservancy.org"
 
        elif hasattr(item, 'author'):
 
            return "%s@sfconservancy.org" % item.author
 
        else:
 
            return "info@sfconservancy.org"
 

	
 
    def item_pubdate(self, item):
 
        if item.omnibus_type == "event":
 
            return item.date_created
 
        else:
 
            return item.pub_date
 

	
 
    def item_link(self, item):
...
 
@@ -153,76 +153,80 @@ class OmnibusFeed(ConservancyFeedBase):
 

	
 
class BlogFeed(ConservancyFeedBase):
 
    link = "/blog/"
 
    get_absolute_url = '/feeds/blog/'
 

	
 
    def get_object(self, request):
 
        return request
 

	
 
    def title(self, obj):
 
        answer = "The Software Freedom Conservancy Blog"
 

	
 
        GET = obj.GET
 
        tags = []
 
        if 'author' in GET:
 
            tags = GET.getlist('author')
 
        if 'tag' in GET:
 
            tags += GET.getlist('tag')
 

	
 
        if len(tags) == 1:
 
            answer += " (" + tags[0] + ")"
 
        elif len(tags) > 1:
 
            firstTime = True
 
            done = {}
 
            for tag in tags:
 
                if tag in done: continue
 
                if tag in done:
 
                    continue
 
                if firstTime:
 
                    answer += " ("
 
                    firstTime = False
 
                else:
 
                    answer += ", "
 
                answer += tag
 
                done[tag] = tag
 
            answer += ")"
 
        else:
 
            answer += "."
 
        return answer
 
        
 
    def description(self, obj):
 
        answer = "Blogs at the Software Freedom Conservancy"
 

	
 
        GET = obj.GET
 
        tags = []
 
        if 'author' in GET: tags = GET.getlist('author')
 
        if 'tag' in GET:    tags += GET.getlist('tag')
 
        if 'author' in GET:
 
            tags = GET.getlist('author')
 
        if 'tag' in GET:
 
            tags += GET.getlist('tag')
 

	
 
        done = {}
 
        if len(tags) == 1:
 
            answer += " tagged with " + tags[0]
 
        elif len(tags) > 1:
 
            firstTime = True
 
            for tag in tags:
 
                if tag in done: continue
 
                if tag in done:
 
                    continue
 
                if firstTime:
 
                    answer += " tagged with "
 
                    firstTime = False
 
                else:
 
                    answer += " or "
 
                answer += tag
 
                done[tag] = tag
 
        else:
 
            answer = "All blogs at the Software Freedom Conservancy"
 
        answer += "."
 

	
 
        return answer
 
        
 
    def item_title(self, item):
 
        return item.headline
 

	
 
    def item_description(self, item):
 
        return item.summary
 

	
 
    def item_author_name(self, item):
 
        return item.author.formal_name
 

	
 
    def item_author_email(self, item):
 
        return "%s@sfconservancy.org" % item.author
conservancy/news/models.py
Show inline comments
...
 
@@ -13,79 +13,81 @@ class PressRelease(models.Model, bsoup.SoupModelMixin):
 
    """News release model"""
 

	
 
    headline = models.CharField(max_length=300)
 
    subhead = models.CharField(max_length=300, blank=True)
 
    slug = models.SlugField(unique_for_date="pub_date",
 
                            help_text=("automatically built from headline"))
 
    summary = models.TextField(help_text="First paragraph (raw HTML)")
 
    body = models.TextField(help_text="Remainder of post (raw HTML)",
 
                            blank=True)
 
    pub_date = models.DateTimeField("date [to be] published")
 
    sites = models.ManyToManyField(Site)
 

	
 
    date_last_modified = models.DateTimeField(auto_now=True)
 

	
 
    class Meta:
 
        ordering = ("-pub_date",)
 
        get_latest_by = "pub_date"
 

	
 
    SOUP_ATTRS = ['summary', 'body']
 

	
 
    def __str__(self):
 
        return self.headline
 

	
 
    def get_absolute_url(self):
 
        return "/news/{}/{}/".format(self.pub_date.strftime("%Y/%b/%d").lower(),
 
                                  self.slug)
 
        return "/news/{}/{}/".format(
 
            self.pub_date.strftime("%Y/%b/%d").lower(),
 
            self.slug,
 
        )
 

	
 
    def is_recent(self):
 
        return self.pub_date > (datetime.now() - timedelta(days=5))
 
        # question: does datetime.now() do a syscall each time is it called?
 

	
 
    def is_in_past_month(self):
 
        # This function is deprecated.  Use the date_within template
 
        # filter instead (example in conservancy/templates/frontpage.html)
 
        return self.pub_date > (datetime.now() - timedelta(days=30))
 

	
 
    def save(self):
 
        if settings.DEBUG or True:
 
            super().save()
 
            return
 

	
 
        blog_name = 'Software Freedom Conservancy News'
 
        blog_url = 'https://www.sfconservancy.org/news/'
 
        post_url = ('https://www.sfconservancy.org'
 
                    + self.get_absolute_url())
 

	
 
        import xmlrpc.client
 

	
 
        # Ping Technorati
 
        j = xmlrpc.client.Server('http://rpc.technorati.com/rpc/ping')
 
        reply = j.weblogUpdates.ping(blog_name, blog_url)
 
        j.weblogUpdates.ping(blog_name, blog_url)
 

	
 
        # Ping Google Blog Search
 
        j = xmlrpc.client.Server('http://blogsearch.google.com/ping/RPC2')
 
        reply = j.weblogUpdates.ping(blog_name, blog_url, post_url)
 
        j.weblogUpdates.ping(blog_name, blog_url, post_url)
 

	
 
        # Call any superclass's method
 
        super().save()
 

	
 
class ExternalArticleTag(models.Model):
 
    """A way to tag external articles"""
 

	
 
    label = models.CharField(max_length=100)
 

	
 
    date_created = models.DateField(auto_now_add=True)
 

	
 
    def __str__(self):
 
        return self.label
 

	
 
class PublicExternalArticleManager(models.Manager):
 
    def get_queryset(self):
 
        return super().get_queryset().filter(visible=True)
 

	
 
class ExternalArticle(models.Model):
 
    """A system for displaying Conservancy news mentions on the site.
 

	
 
    (Currently unused)
 
    """
 

	
conservancy/news/views.py
Show inline comments
 
from datetime import datetime
 

	
 
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
 
from django.http import HttpResponse
 
from django.shortcuts import render
 
from django.views.generic import ListView
 
from django.views.generic.dates import (
 
    DateDetailView,
 
    DayArchiveView,
 
    MonthArchiveView,
 
    YearArchiveView,
 
)
 

	
 
from ..events.models import Event
 
from .models import ExternalArticle, PressRelease
 
from .models import PressRelease
 

	
 

	
 
class NewsListView(ListView):
 
    extra_context = {}
 
    def get_context_data(self, **kwargs):
 
        context = super().get_context_data(**kwargs)
 
        # context['key'] = 'value'
 
        context.update(self.extra_context)
 
        return context
 
                                    
 
def listing(request, *args, **kwargs):
 
    news_queryset = PressRelease.objects.all()
 

	
 
#    if (not kwargs.has_key('allow_future')) or not kwargs['allow_future']:
 
    news_queryset = news_queryset.filter(**{'%s__lte' % kwargs['date_field']:
 
                          datetime.now()})
 
    news_queryset = news_queryset.filter(
 
        **{'%s__lte' % kwargs['date_field']: datetime.now()}
 
    )
 

	
 
    date_list = news_queryset.dates(kwargs['date_field'], 'year')
 

	
 
    paginate_by = kwargs.get('paginate_by', 6)  # Show 6 news items per page, by default
 
    paginator = Paginator(news_queryset, paginate_by)
 

	
 
    page = request.GET.get('page')
 
    try:
 
        news = paginator.page(page)
 
    except PageNotAnInteger:
 
        # If page is not an integer, deliver first page.
 
        news = paginator.page(1)
 
    except EmptyPage:
 
        # If page is out of range (e.g. 9999), deliver last page of results.
 
        news = paginator.page(paginator.num_pages)
 

	
 
    return render(request, 'news/pressrelease_list.html', {"news": news, "date_list" : date_list})
 

	
 
class NewsYearArchiveView(YearArchiveView):
 
    # queryset = Article.objects.all()
 
    # date_field = "pub_date"
 
    make_object_list = True
 
    allow_future = True
 

	
conservancy/podjango/models.py
Show inline comments
 
#  Copyright (C) 2008       Bradley M. Kuhn <bkuhn@ebb.org>
 
#  Copyright (C) 2006, 2007 Software Freedom Law Center, Inc.
 
#
 
# This software's license gives you freedom; you can copy, convey,
 
# propogate, redistribute and/or modify this program under the terms of
 
# the GNU Affero General Public License (AGPL) as published by the Free
 
# Software Foundation (FSF), either version 3 of the License, or (at your
 
# option) any later version of the AGPL published by the FSF.
 
#
 
# This program is distributed in the hope that it will be useful, but
 
# WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
 
# General Public License for more details.
 
#
 
# You should have received a copy of the GNU Affero General Public License
 
# 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 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)
 
    icon = models.ImageField(null=True)
 

	
 
    def __str__(self):
 
        return self.title
 

	
 

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

	
 
    label = models.CharField(max_length=100)
 
    slug = models.SlugField()
 

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

	
conservancy/settings/dev.py
Show inline comments
 
from .base import *
 
from .base import *  # NOQA
 

	
 
DEBUG = True
 
ALLOWED_HOSTS = ['*']
 

	
 
DATABASES = {
 
    'default': {
 
        'NAME': 'conservancy-website.sqlite3',
 
        'ENGINE': 'django.db.backends.sqlite3',
 
    }
 
}
 

	
 
SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
 

	
 
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
conservancy/settings/prod.py
Show inline comments
 
import json
 

	
 
from django.core.exceptions import ImproperlyConfigured
 

	
 
from .base import *
 
from .base import *  # NOQA
 

	
 
DEBUG = False
 
ALLOWED_HOSTS = ['www.sfconservancy.org', 'sfconservancy.org']
 

	
 
ADMINS = [
 
    ('Bradley M. Kuhn', 'sysadmin@sfconservancy.org'),
 
    ('Ben Sturmfels', 'sysadmin+conservancy@sturm.com.au'),
 
]
 

	
 
MANAGERS = [
 
    ('Bradley M. Kuhn', 'sysadmin@sfconservancy.org'),
 
]
 

	
 
DATABASES = {
 
    'default': {
 
        'NAME': '/var/lib/www/database/conservancy-website.sqlite3',
 
        'ENGINE': 'django.db.backends.sqlite3',
 
    }
 
}
 

	
 
# Apache/mod_wsgi doesn't make it straightforward to pass environment variables
 
# to Django (can't use the Apache config).
 
with open(BASE_DIR.parent / 'secrets.json') as f:
 
with open(BASE_DIR.parent / 'secrets.json') as f:  # NOQA
 
    secrets = json.load(f)
 

	
 
def get_secret(secrets, setting):
 
    try:
 
        return secrets[setting]
 
    except KeyError:
 
        raise ImproperlyConfigured(f'Missing secret \'{setting}\'')
 

	
 
SECRET_KEY = get_secret(secrets, 'SECRET_KEY')
 

	
 
SESSION_COOKIE_SECURE = True
0 comments (0 inline, 0 general)