Changeset - 2d078b0004fb
[Not reviewed]
0 10 0
Ben Sturmfels (bsturmfels) - 2 years ago 2021-11-29 20:55:45
ben@sturm.com.au
Apply `futurize --stage-2` Python 2/3 compatibility transformations.

These changes specifically require the use of the "future" library.
10 files changed with 31 insertions and 17 deletions:
0 comments (0 inline, 0 general)
www/conservancy/__init__.py
Show inline comments
 
from past.builtins import basestring
 
from builtins import object
 
import hashlib
 

	
 
from django.conf import settings
 
from django.template import RequestContext
 

	
 
# This is backwards compatibilty support for a custom function we wrote
 
# ourselves that is no longer necessary in modern Django.
 
from django.shortcuts import render as render_template_with_context
 

	
 
class ParameterValidator(object):
 
    def __init__(self, given_hash_or_params, params_hash_key=None):
 
        if params_hash_key is None:
 
            self.given_hash = given_hash_or_params
 
        else:
 
            self.given_hash = given_hash_or_params.get(params_hash_key)
 
        seed = getattr(settings, 'CONSERVANCY_SECRET_KEY', '').encode('utf-8')
 
        self.hasher = hashlib.sha256(seed)
 
        if isinstance(self.given_hash, basestring):
 
            self.hash_type = type(self.given_hash)
 
        else:
 
            self.hash_type = type(self.hasher.hexdigest())
 
        self.valid = None
 
        if not (self.given_hash and seed):
www/conservancy/apps/blog/models.py
Show inline comments
 
from future import standard_library
 
standard_library.install_aliases()
 
from builtins import object
 
from django.db import models
 
from django.conf import settings
 
from conservancy import bsoup
 
from conservancy.apps.staff.models import Person
 
from datetime import datetime, timedelta
 

	
 
class EntryTag(models.Model):
 
    """Tagging for blog entries"""
 

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

	
 
    class Meta(object):
 
        db_table = 'techblog_entrytag' # legacy
 

	
 
    def __unicode__(self):
 
        return self.label
 

	
 
    def get_absolute_url(self):
 
        return u"/blog/?tag=%s" % self.slug
 

	
 
class Entry(models.Model, bsoup.SoupModelMixin):
 
    """Blog entry"""
 

	
...
 
@@ -44,36 +47,36 @@ class Entry(models.Model, bsoup.SoupModelMixin):
 
    def __unicode__(self):
 
        return self.headline
 

	
 
    def get_absolute_url(self):
 
        return (u"/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.CONSERVANCY_DEVEL or True: # "or True" means it is disabled always
 
            super(Entry, self).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 xmlrpclib
 
        import xmlrpc.client
 

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

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

	
 
        # Call any superclass's method
 
        super(Entry, self).save()
www/conservancy/apps/events/view_helpers.py
Show inline comments
 
def organize_media_by_event(eventmedia_queryset):
 
    """Organizes event media by event.
 

	
 
    Given a queryset of event media, it returns a list of 'objects'
 
    with the following properties:
 

	
 
    * event (event object)
 
    * date (date object for most recently posted media from event)
 
    * media_list (a string of the available media types)
 
    """
 

	
 
    media_by_event = {}
 
    for media in eventmedia_queryset:
 
        media_by_event.setdefault(media.event.id, []).append(media)
 
    mbe = [{'event': x[0].event,
 
            'date': max(y.date_created for y in x),
 
            'media_list': ', '.join(set(y.get_format_display() for y in x))}
 
           for x in media_by_event.values()]
 
           for x in list(media_by_event.values())]
 
    mbe.sort(key=(lambda x: x['date']), reverse=True) # sort by date
 
    return mbe
www/conservancy/apps/fundgoal/models.py
Show inline comments
 
from __future__ import division
 
from past.utils import old_div
 
from builtins import object
 
import random
 

	
 
from django.db import models
 

	
 
class FundraisingGoal(models.Model):
 
    """Conservancy fundraiser Goal"""
 

	
 
    fundraiser_code_name = models.CharField(max_length=200, blank=False, unique=True)
 
    fundraiser_goal_amount = models.DecimalField(max_digits=10, decimal_places=2)
 
    fundraiser_so_far_amount = models.DecimalField(max_digits=10, decimal_places=2)
 
    fundraiser_donation_count = models.IntegerField()
 
    fundraiser_donation_count_disclose_threshold = models.IntegerField()
 
    fundraiser_endtime = models.DateTimeField(null=True)
 

	
 
    def __unicode__(self):
 
        return self.fundraiser_code_name
 

	
 
    def percentage_there(self):
 
        return (self.fundraiser_so_far_amount / self.fundraiser_goal_amount ) * 100
 
        return (old_div(self.fundraiser_so_far_amount, self.fundraiser_goal_amount) ) * 100
 
    
 
    class Meta(object):
 
        ordering = ('fundraiser_code_name',)
 

	
 
    def providers(self):
 
        return GoalProvider.objects.filter(fundraising_goal=self)
 

	
 
    def random_providers(self, k=None):
 
        providers = self.providers()
 
        if not providers.exists():
 
            return None
 
        elif k is None:
 
            return random.choice(providers)
 
        else:
 
            return random.sample(providers, k)
 

	
 

	
 
class GoalProvider(models.Model):
 
    fundraising_goal = models.ForeignKey(
 
        'FundraisingGoal',
 
        on_delete=models.CASCADE,
 
    )
 
    provider_name = models.CharField(max_length=512)
 

	
www/conservancy/apps/news/models.py
Show inline comments
 
from future import standard_library
 
standard_library.install_aliases()
 
from builtins import object
 
from django.db import models
 
from django.conf import settings
 
from conservancy import bsoup
 
from conservancy.apps.staff.models import Person
 
from conservancy.apps.events.models import Event
 
from django.contrib.sites.models import Site
 
from datetime import datetime, timedelta
 

	
 
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)
 

	
...
 
@@ -33,56 +35,56 @@ class PressRelease(models.Model, bsoup.SoupModelMixin):
 

	
 
    def get_absolute_url(self):
 
        return u"/news/%s/%s/" % (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.CONSERVANCY_DEVEL or True:
 
            super(PressRelease, self).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 xmlrpclib
 
        import xmlrpc.client
 

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

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

	
 
        # Call any superclass's method
 
        super(PressRelease, self).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 __unicode__(self):
 
        return self.label
 

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

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

	
 
    (Currently unused)
 
    """
www/conservancy/apps/news/templatetags/fill_url.py
Show inline comments
 
import urlparse
 
from future import standard_library
 
standard_library.install_aliases()
 
from builtins import zip
 
import urllib.parse
 

	
 
from django import template
 

	
 
register = template.Library()
 

	
 
@register.filter(name='fill_url')
 
def fill_url(given_url, base_url):
 
    """"Fill out" missing pieces of one URL from another.
 

	
 
    This function parses the given URL, and if it's missing any pieces
 
    (scheme, netloc, etc.), it fills those in from the base URL.
 
    Typical usage is "/URL/path"|fill_url:"https://hostname/"
 
    to generate "https://hostname/URL/path".
 
    """
 
    given_parts = urlparse.urlsplit(given_url)
 
    base_parts = urlparse.urlsplit(base_url)
 
    return urlparse.urlunsplit(
 
    given_parts = urllib.parse.urlsplit(given_url)
 
    base_parts = urllib.parse.urlsplit(base_url)
 
    return urllib.parse.urlunsplit(
 
        given_part or base_part for given_part, base_part in zip(given_parts, base_parts)
 
    )
www/conservancy/bsoup.py
Show inline comments
 
# -*- encoding: utf-8 -*-
 

	
 
from builtins import filter
 
from builtins import object
 
import io
 
import itertools
 
import re
 

	
 
import bs4
 
import bs4.element
 

	
 
class BeautifulSoup(bs4.BeautifulSoup):
 
    """A wrapper of the original BeautifulSoup class, with convenience methods added."""
 

	
 
    IMAGE_ATTRS = {
 
        'img': 'src',
 
        'video': 'poster',
 
    }
 
    NON_BODY_TEXT_TAGS = frozenset([
 
        'img',
 
        'video',
 
    ])
 
    SENTENCE_END = re.compile(r'[.?!]\s*\W*\s*$')
 

	
 
    def __init__(self, src, parser='html5lib'):
 
        # WARNING!  It seems like it would be ideal to use the 'lxml' parser
 
        # for speed, but that doesn't work in our web application.  On
...
 
@@ -123,49 +124,49 @@ class SoupModelMixin(object):
 
        except AttributeError:
 
            html = io.StringIO()
 
            for attr_name in self.SOUP_ATTRS:
 
                html.write(getattr(self, attr_name))
 
            html.seek(0)
 
            self._soup = BeautifulSoup(html)
 
            return self._soup
 

	
 
    def _elem_key(self, attr_name=OG_PREVIEW_ATTR, getvalue=int, fallback=999999):
 
        def elem_sort_key(elem):
 
            try:
 
                sort_key = getvalue(elem[attr_name])
 
            except (KeyError, ValueError):
 
                sort_key = fallback
 
            elem[attr_name] = sort_key
 
            return sort_key
 
        return elem_sort_key
 

	
 
    def _elem_pred(self, attr_name=OG_PREVIEW_ATTR, test=lambda n: n > 0):
 
        def elem_pred(elem):
 
            return test(elem[attr_name])
 
        return elem_pred
 

	
 
    def _sort_and_slice_elems(self, elem_seq, elem_key, pred, *slice_args):
 
        seq = itertools.ifilter(pred, sorted(elem_seq, key=elem_key))
 
        seq = filter(pred, sorted(elem_seq, key=elem_key))
 
        if slice_args:
 
            return itertools.islice(seq, *slice_args)
 
        else:
 
            return seq
 

	
 
    def get_description(self):
 
        """Return a string with a brief excerpt of body text from the HTML."""
 
        return u''.join(self._get_soup().some_body_text())
 

	
 
    def get_image_urls(self, *slice_args):
 
        """Return an iterator of source URL strings of all images in the HTML.
 

	
 
        Images include <img> sources and <video> poster attributes.
 
        """
 
        for elem in self._sort_and_slice_elems(
 
                self._get_soup().iter_images(),
 
                self._elem_key(),
 
                self._elem_pred(),
 
                *slice_args
 
        ):
 
            yield elem[BeautifulSoup.IMAGE_ATTRS[elem.name]]
 

	
 
    def get_one_image_url(self):
 
        return self.get_image_urls(1)
www/conservancy/local_context_processors.py
Show inline comments
 
from datetime import datetime as DateTime
 
from pytz import utc as UTC
 

	
 
import conservancy.settings
 
from conservancy.apps.fundgoal.models import FundraisingGoal as FundraisingGoal
 

	
 
SITE_FUNDGOAL = 'cy2021-end-year-match'
 

	
 
def fundgoal_lookup(fundraiser_sought):
 
    try:
 
        return FundraisingGoal.objects.get(fundraiser_code_name=fundraiser_sought)
 
    except FundraisingGoal.DoesNotExist:
 
        # we have no object!  do something
 
        return None
 

	
 
def sitefundraiser(request):
 
    return {
 
        'datetime_now': DateTime.now(),
 
        'sitefundgoal': fundgoal_lookup(SITE_FUNDGOAL),
 
    }
 

	
 
if conservancy.settings.FORCE_CANONICAL_HOSTNAME:
 
    _HOST_URL_VAR = {'host_url': 'https://' + conservancy.settings.FORCE_CANONICAL_HOSTNAME}
 
    def host_url(request):
 
        return _HOST_URL_VAR
 
        return _HOST_URL_VAR.decode('utf-8')
 
else:
 
    def host_url(request):
 
        return {'host_url': request.build_absolute_uri('/').rstrip('/')}
 
        return {'host_url': request.build_absolute_uri('/').rstrip('/').decode('utf-8')}
www/conservancy/static/views.py
Show inline comments
 
from builtins import str
 
import mimetypes
 
import os.path
 
from django.http import HttpResponse
 
from django.template.response import TemplateResponse
 

	
 
from conservancy.local_context_processors import fundgoal_lookup
 

	
 
STATIC_ROOT = os.path.abspath(os.path.dirname(__file__))
 
FILESYSTEM_ENCODING = 'utf-8'
 

	
 
def handler(request, errorcode):
 
    path = os.path.join('error', str(errorcode), 'index.html')
 
    fullpath = os.path.join(STATIC_ROOT, path)
 
    if not os.path.exists(fullpath):
 
        return HttpResponse("Internal error: " + path, status=int(errorcode))
 
    else:
 
        return TemplateResponse(request, path, status=int(errorcode))
 

	
 
def handler401(request):
 
    return handler(request, 401)
 

	
 
def handler403(request):
 
    return handler(request, 403)
 

	
www/modpythoncustom.py
Show inline comments
 
from builtins import str
 
from mod_python import apache
 

	
 
# 404 should do NOTHING so apache can handle it.  This view is referenced
 
# in sflc.urls
 
def view404(request):
 
    from django.http import HttpResponseNotFound
 
    return HttpResponseNotFound("")
 

	
 
def outputfilter(filter):
 
    # set appropriate cache timeout
 
    filter.req.headers_out["Cache-Control"] = "max-age=600"
 

	
 
    # read raw template
 
    raw = []
 
    s = filter.read()
 
    while s:
 
        raw.append(s)
 
        s = filter.read()
 
    raw = "".join(raw)
 

	
 
    # render it
 
    from django.template import Context, Template
 
    t = Template(raw.decode('utf-8'))
 
    del raw
...
 
@@ -62,41 +63,41 @@ class ModPythonHandler(BaseHandler):
 

	
 
        set_script_prefix(req.get_options().get('django.root', '')) 
 
        signals.request_started.send(sender=self.__class__) 
 
        try:
 
            try:
 
                request = self.request_class(req)
 
            except UnicodeDecodeError:
 
                response = http.HttpResponseBadRequest()
 
            else:
 
                response = self.get_response(request)
 

	
 
                # Apply response middleware
 
                for middleware_method in self._response_middleware:
 
                    response = middleware_method(request, response)
 
                response = self.apply_response_fixes(request, response)
 
        finally:
 
            signals.request_finished.send(sender=self.__class__) 
 

	
 
        # SFLC: decline so apache can serve a static file
 
        if response.status_code == 404:
 
            return apache.DECLINED
 

	
 
        # Convert our custom HttpResponse object back into the mod_python req.
 
        req.content_type = response['Content-Type']
 
        for key, value in response.items():
 
        for key, value in list(response.items()):
 
            if key != 'content-type':
 
                req.headers_out[str(key)] = str(value)
 
        for c in response.cookies.values():
 
        for c in list(response.cookies.values()):
 
            req.headers_out.add('Set-Cookie', c.output(header=''))
 
        req.status = response.status_code
 
        try:
 
            for chunk in response:
 
                req.write(chunk)
 
        finally:
 
            response.close()
 

	
 
        return apache.DONE # skip all remaining phases (sf[l]c customization)
 

	
 
def postreadrequesthandler(req):
 
    # mod_python hooks into this function.
 
    return ModPythonHandler()(req)
0 comments (0 inline, 0 general)