summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorluxagraf <sng@luxagraf.net>2014-05-23 10:48:20 -0400
committerluxagraf <sng@luxagraf.net>2014-05-23 10:48:20 -0400
commit4bae11bb25a8e3c43118891d17fd8e981ecf8dc6 (patch)
tree6c452743157ad9403ec54a7399b10069688d048f
parenteebf53322e0d19be42e41d8f355c5d2a744441ae (diff)
Refactored code to use PEP8/Pyflake coding styles and cleaned up cruft a
bit
-rw-r--r--app/cron/create_country_sidebar.py19
-rw-r--r--app/cron/create_region_sidebar.py18
-rw-r--r--app/cron/full_build.py33
-rwxr-xr-xapp/cron/full_build.sh2
-rw-r--r--app/lib/ssl/__init__.py0
-rw-r--r--app/lib/ssl/middleware.py41
-rw-r--r--app/lib/templatetags/templatetags/get_latest.py1
-rw-r--r--app/lib/templatetags/templatetags/get_latest_pub.py1
-rw-r--r--app/lib/utils/APIClients.py104
-rw-r--r--app/lib/utils/__init__.py0
-rw-r--r--app/lib/utils/pinboard.py558
-rw-r--r--app/lib/utils/strutils.py50
-rw-r--r--app/links/sync_links.py (renamed from app/cron/sync_links.py)0
-rw-r--r--app/photos/sync_photo_sets.py (renamed from app/cron/sync_photo_sets.py)0
-rw-r--r--app/photos/sync_photos.py (renamed from app/cron/sync_photos.py)0
-rw-r--r--design/templates/archives/writing_date.html26
-rw-r--r--design/templates/comments/base.html8
-rw-r--r--design/templates/comments/comment.html32
-rw-r--r--design/templates/comments/comment_notification_email.txt20
-rw-r--r--design/templates/comments/deleted.html21
-rw-r--r--design/templates/comments/flagged.html21
-rw-r--r--design/templates/comments/form.html18
-rw-r--r--design/templates/comments/list.html14
-rw-r--r--design/templates/comments/posted.html25
-rw-r--r--design/templates/comments/preview.html30
25 files changed, 215 insertions, 827 deletions
diff --git a/app/cron/create_country_sidebar.py b/app/cron/create_country_sidebar.py
deleted file mode 100644
index f660c73..0000000
--- a/app/cron/create_country_sidebar.py
+++ /dev/null
@@ -1,19 +0,0 @@
-import sys, os
-
-sys.path.append('/home/luxagraf/webapps/django1_1')
-sys.path.append('/home/luxagraf/webapps/django1_1/luxagraf')
-sys.path.append('/home/luxagraf/webapps/django1_1/luxagraf/apps')
-sys.path.append('/home/luxagraf/webapps/django1_1/luxagraf/lib')
-sys.path.append('/home/luxagraf/webapps/django1_1/lib/python2.5/')
-os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-
-from django.template import Context
-from django.template import loader
-from django.conf import settings
-from locations.models import Country,Region
-c = Context({'country_list': Country.objects.filter(visited=True),})
-t = loader.render_to_string('includes/country_sidebar_template.html',c)
-fpath = '%s%s' %(settings.PROJ_ROOT,'templates/includes/country_sidebar.html')
-file = open(fpath, 'w')
-file.write(t)
-file.close() \ No newline at end of file
diff --git a/app/cron/create_region_sidebar.py b/app/cron/create_region_sidebar.py
deleted file mode 100644
index 77f2628..0000000
--- a/app/cron/create_region_sidebar.py
+++ /dev/null
@@ -1,18 +0,0 @@
-import sys, os
-
-sys.path.append('/home/luxagraf/webapps/django1_1')
-sys.path.append('/home/luxagraf/webapps/django1_1/luxagraf')
-sys.path.append('/home/luxagraf/webapps/django1_1/luxagraf/apps')
-sys.path.append('/home/luxagraf/webapps/django1_1/luxagraf/lib')
-sys.path.append('/home/luxagraf/webapps/django1_1/lib/python2.5/')
-os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-
-from django.template import Context,loader
-from django.conf import settings
-from locations.models import Region
-c = Context({'region_list': Region.objects.all(),})
-t = loader.render_to_string('includes/regions_sidebar_template.html',c)
-fpath = '%s%s' %(settings.PROJ_ROOT,'templates/includes/regions_sidebar.html')
-file = open(fpath, 'w')
-file.write(t)
-file.close() \ No newline at end of file
diff --git a/app/cron/full_build.py b/app/cron/full_build.py
deleted file mode 100644
index e52d005..0000000
--- a/app/cron/full_build.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import sys, os
-from os.path import dirname, abspath
-
-PROJECT_ROOT = abspath(dirname(dirname(__file__)))
-
-sys.path.append(PROJECT_ROOT)
-sys.path.append(PROJECT_ROOT+'/apps')
-sys.path.append(PROJECT_ROOT+'/lib')
-sys.path.append('/home/luxagraf/webapps/django1_3/lib/python2.7/')
-os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
-
-from build.base import BuildWriting,BuildMap,BuildPhotos,BuildAbout,BuildProjects,BuildSitemap,BuildContact
-
-b = BuildWriting()
-b.build()
-
-b = BuildPhotos()
-b.build()
-
-b = BuildMap()
-b.build()
-
-b = BuildAbout()
-b.build()
-
-b = BuildProjects()
-b.build()
-
-b = BuildSitemap()
-b.build()
-
-b = BuildContact()
-b.build() \ No newline at end of file
diff --git a/app/cron/full_build.sh b/app/cron/full_build.sh
deleted file mode 100755
index c065d48..0000000
--- a/app/cron/full_build.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-python2.7 /home/luxagraf/webapps/django/luxagraf/cron/full_build.py \ No newline at end of file
diff --git a/app/lib/ssl/__init__.py b/app/lib/ssl/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/app/lib/ssl/__init__.py
+++ /dev/null
diff --git a/app/lib/ssl/middleware.py b/app/lib/ssl/middleware.py
deleted file mode 100644
index 11e1076..0000000
--- a/app/lib/ssl/middleware.py
+++ /dev/null
@@ -1,41 +0,0 @@
-__license__ = "Python"
-__copyright__ = "Copyright (C) 2007, Stephen Zabel"
-__author__ = "Stephen Zabel - sjzabel@gmail.com"
-__contributors__ = "Jay Parlar - parlar@gmail.com"
-
-from django.conf import settings
-from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect, get_host
-
-SSL = 'SSL'
-
-class SSLRedirect:
-
- def process_view(self, request, view_func, view_args, view_kwargs):
- if SSL in view_kwargs:
- secure = view_kwargs[SSL]
- del view_kwargs[SSL]
- else:
- secure = False
-
- if not secure == self._is_secure(request):
- return self._redirect(request, secure)
-
- def _is_secure(self, request):
- if request.is_secure():
- return True
-
- #Handle the Webfaction case until this gets resolved in the request.is_secure()
- if 'HTTP_X_FORWARDED_SSL' in request.META:
- return request.META['HTTP_X_FORWARDED_SSL'] == 'on'
-
- return False
-
- def _redirect(self, request, secure):
- protocol = secure and "https" or "http"
- newurl = "%s://%s%s" % (protocol,get_host(request),request.get_full_path())
- if settings.DEBUG and request.method == 'POST':
- raise RuntimeError, \
- """Django can't perform a SSL redirect while maintaining POST data.
- Please structure your views so that redirects only occur during GETs."""
-
- return HttpResponsePermanentRedirect(newurl) \ No newline at end of file
diff --git a/app/lib/templatetags/templatetags/get_latest.py b/app/lib/templatetags/templatetags/get_latest.py
deleted file mode 100644
index 6c9f9fa..0000000
--- a/app/lib/templatetags/templatetags/get_latest.py
+++ /dev/null
@@ -1 +0,0 @@
-from django.template import Library, Node from django.db.models import get_model register = Library() class LatestContentNode(Node): def __init__(self, model, num, varname): self.num, self.varname = num, varname self.model = get_model(*model.split('.')) def render(self, context): context[self.varname] = self.model._default_manager.all()[:self.num] return '' def get_latest(parser, token): bits = token.contents.split() if len(bits) != 5: raise TemplateSyntaxError, "get_latest tag takes exactly four arguments" if bits[3] != 'as': raise TemplateSyntaxError, "third argument to get_latest tag must be 'as'" return LatestContentNode(bits[1], bits[2], bits[4]) get_latest = register.tag(get_latest) \ No newline at end of file
diff --git a/app/lib/templatetags/templatetags/get_latest_pub.py b/app/lib/templatetags/templatetags/get_latest_pub.py
deleted file mode 100644
index 151befa..0000000
--- a/app/lib/templatetags/templatetags/get_latest_pub.py
+++ /dev/null
@@ -1 +0,0 @@
-from django.template import Library, Node from django.db.models import get_model register = Library() class LatestContentNode(Node): def __init__(self, model, num, varname): self.num, self.varname = num, varname self.model = get_model(*model.split('.')) def render(self, context): context[self.varname] = self.model._default_manager.filter(status__exact=1)[:self.num] return '' def get_latest_pub(parser, token): bits = token.contents.split() if len(bits) != 5: raise TemplateSyntaxError, "get_latest tag takes exactly four arguments" if bits[3] != 'as': raise TemplateSyntaxError, "third argument to get_latest tag must be 'as'" return LatestContentNode(bits[1], bits[2], bits[4]) get_latest_pub = register.tag(get_latest_pub) \ No newline at end of file
diff --git a/app/lib/utils/APIClients.py b/app/lib/utils/APIClients.py
deleted file mode 100644
index 24ab97b..0000000
--- a/app/lib/utils/APIClients.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# APIClients for grabbing data from popular web services
-# By Scott Gilbertson
-# Copyright is lame, take what you want, except for those portions noted
-
-# Dependencies:
-import sys, urllib
-import xml.etree.cElementTree as xml_parser
-
-
-DEBUG = 0
-
-"""
-base class -- handles GoodReads.com, but works for any rss feed, just send an empty string for anything you don't need
-"""
-class APIClient:
- def __init__(self, base_path, api_key):
- self.api_key = api_key
- self.base_path = base_path
-
- def __getattr__(self, method):
- def method(_self=self, _method=method, **params):
- url = "%s%s?%s&" % (self.base_path, self.api_key, urllib.urlencode(params))
- if DEBUG: print url
- data = self.fetch(url)
- return data
-
- return method
-
- def fetch(self, url):
- u = urllib.FancyURLopener(None)
- usock = u.open(url)
- rawdata = usock.read()
- if DEBUG: print rawdata
- usock.close()
- return xml_parser.fromstring(rawdata)
-
-"""
- Extend APIClient to work with the ma.gnolia.com API
- (http://wiki.ma.gnolia.com/Ma.gnolia_API)
- Adds some error handling as well
-"""
-class MagnoliaError(Exception):
- def __init__(self, code, message):
- self.code = code
- self.message = message
-
- def __str__(self):
- return 'Magnolia Error %s: %s' % (self.code, self.message)
-
-
-class MagnoliaClient(APIClient):
- def __getattr__(self, method):
- def method(_self=self, _method=method, **params):
- url = "%s%s?%s&api_key=%s" % (self.base_path, _method, urllib.urlencode(params), self.api_key)
- if DEBUG: print url
- data = APIClient.fetch(self, url)
- return data
- return method
-
-
-"""
- Extend APIClient to work with the Flickr API
- (http://www.flickr.com/services/api/)
- Adds error handling as well
-"""
-
-class FlickrError(Exception):
- def __init__(self, code, message):
- self.code = code
- self.message = message
-
- def __str__(self):
- return 'Flickr Error %s: %s' % (self.code, self.message)
-
-class FlickrClient(APIClient):
- def __getattr__(self, method):
- def method(_self=self, _method=method, **params):
- _method = _method.replace("_", ".")
- url = "%s?method=%s&%s&api_key=%s" % (self.base_path, _method, urllib.urlencode(params), self.api_key)
- if DEBUG: print url
- data = APIClient.fetch(self, url)
- return data
- return method
-
-class TumblrClient:
- def __init__(self, base_path):
- self.base_path = base_path
-
- def __getattr__(self, method):
- def method(_self=self, _method=method, **params):
- url = "%s" % (self.base_path)
- if DEBUG: print url
- data = self.fetch(url)
- return data
-
- return method
-
- def fetch(self, url):
- u = urllib.FancyURLopener(None)
- usock = u.open(url)
- rawdata = usock.read()
- if DEBUG: print rawdata
- usock.close()
- return xml_parser.fromstring(rawdata)
diff --git a/app/lib/utils/__init__.py b/app/lib/utils/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/app/lib/utils/__init__.py
+++ /dev/null
diff --git a/app/lib/utils/pinboard.py b/app/lib/utils/pinboard.py
deleted file mode 100644
index e05935e..0000000
--- a/app/lib/utils/pinboard.py
+++ /dev/null
@@ -1,558 +0,0 @@
-#!/usr/bin/env python
-"""Python-Pinboard
-
-Python module for access to pinboard <http://pinboard.in/> via its API.
-Recommended: Python 2.6 or later (untested on previous versions)
-
-This library was built on top of Paul Mucur's original work on the python-delicious
-which was supported for python 2.3. Morgan became a contributor and ported this library
-to pinboard.in when it was announced in December 2010 that delicious servers may be
-shutting down.
-
-The port to pinboard resulted in the inclusion of gzip support
-
-"""
-
-__version__ = "1.0"
-__license__ = "BSD"
-__copyright__ = "Copyright 2011, Morgan Craft"
-__author__ = "Morgan Craft <http://www.morgancraft.com/>"
-
-#TODO:
-# Should text be properly escaped for XML? Or that not this module's
-# responsibility?
-# Create test suite
-
-
-_debug = 0
-
-# The user agent string sent to pinboard.in when making requests. If you are
-# using this module in your own application, you should probably change this.
-USER_AGENT = "Python-Pinboard/%s +http://morgancraft.com/service_layer/python-pinboard/" % __version__
-
-
-import urllib
-import urllib2
-import sys
-import re
-import time
-## added to handle gzip compression from server
-import StringIO
-import gzip
-
-from xml.dom import minidom
-try:
- StringTypes = basestring
-except:
- try:
- # Python 2.2 does not have basestring
- from types import StringTypes
- except:
- # Python 2.0 and 2.1 do not have StringTypes
- from types import StringType, UnicodeType
- StringTypes = None
-try:
- ListType = list
- TupleType = tuple
-except:
- from types import ListType, TupleType
-
-# Taken from Mark Pilgrim's amazing Universal Feed Parser
-# <http://feedparser.org/>
-try:
- UserDict = dict
-except NameError:
- from UserDict import UserDict
-try:
- import datetime
-except:
- datetime = None
-
-
-# The URL of the Pinboard API
-PINBOARD_API = "https://api.pinboard.in/v1"
-AUTH_HANDLER_REALM = 'API'
-AUTH_HANDLER_URI = "https://api.pinboard.in/"
-
-def open(username, password):
- """Open a connection to a pinboard.in account"""
- return PinboardAccount(username, password)
-
-def connect(username, password):
- """Open a connection to a pinboard.in account"""
- return open(username, password)
-
-
-# Custom exceptions
-
-class PinboardError(Exception):
- """Error in the Python-Pinboard module"""
- pass
-
-class ThrottleError(PinboardError):
- """Error caused by pinboard.in throttling requests"""
- def __init__(self, url, message):
- self.url = url
- self.message = message
- def __str__(self):
- return "%s: %s" % (self.url, self.message)
-
-class AddError(PinboardError):
- """Error adding a post to pinboard.in"""
- pass
-
-class DeleteError(PinboardError):
- """Error deleting a post from pinboard.in"""
- pass
-
-class BundleError(PinboardError):
- """Error bundling tags on pinboard.in"""
- pass
-
-class DeleteBundleError(PinboardError):
- """Error deleting a bundle from pinboard.in"""
- pass
-
-class RenameTagError(PinboardError):
- """Error renaming a tag in pinboard.in"""
- pass
-
-class DateParamsError(PinboardError):
- '''Date params error'''
- pass
-
-class PinboardAccount(UserDict):
- """A pinboard.in account"""
-
- # Used to track whether all posts have been downloaded yet.
- __allposts = 0
- __postschanged = 0
-
- # Time of last request so that the one second limit can be enforced.
- __lastrequest = None
-
- # Special methods
-
- def __init__(self, username, password):
- UserDict.__init__(self)
- # Authenticate the URL opener so that it can access Pinboard
- if _debug:
- sys.stderr.write("Initialising Pinboard Account object.\n")
- auth_handler = urllib2.HTTPBasicAuthHandler()
- auth_handler.add_password("API", "https://api.pinboard.in/", \
- username, password)
- opener = urllib2.build_opener(auth_handler)
- opener.addheaders = [("User-agent", USER_AGENT), ('Accept-encoding', 'gzip')]
- urllib2.install_opener(opener)
- if _debug:
- sys.stderr.write("URL opener with HTTP authenticiation installed globally.\n")
-
-
- if _debug:
- sys.stderr.write("Time of last update loaded into class dictionary.\n")
-
- def __getitem__(self, key):
- try:
- return UserDict.__getitem__(self, key)
- except KeyError:
- if key == "tags":
- return self.tags()
- elif key == "dates":
- return self.dates()
- elif key == "posts":
- return self.posts()
- elif key == "bundles":
- return self.bundles()
-
- def __setitem__(self, key, value):
- if key == "posts":
- if _debug:
- sys.stderr.write("The value of posts has been changed.\n")
- self.__postschanged = 1
- return UserDict.__setitem__(self, key, value)
-
-
- def __request(self, url):
-
- # Make sure that it has been at least 1 second since the last
- # request was made. If not, halt execution for approximately one
- # seconds.
- if self.__lastrequest and (time.time() - self.__lastrequest) < 2:
- if _debug:
- sys.stderr.write("It has been less than two seconds since the last request; halting execution for one second.\n")
- time.sleep(1)
- if _debug and self.__lastrequest:
- sys.stderr.write("The delay between requests was %d.\n" % (time.time() - self.__lastrequest))
- self.__lastrequest = time.time()
- if _debug:
- sys.stderr.write("Opening %s.\n" % url)
-
- try:
- ## for pinboard a gzip request is made
- raw_xml = urllib2.urlopen(url)
- compresseddata = raw_xml.read()
- ## bing unpackaging gzipped stream buffer
- compressedstream = StringIO.StringIO(compresseddata)
- gzipper = gzip.GzipFile(fileobj=compressedstream)
- xml = gzipper.read()
-
- except urllib2.URLError, e:
- raise e
-
- self["headers"] = {}
- for header in raw_xml.headers.headers:
- (name, value) = header.split(": ")
- self["headers"][name.lower()] = value[:-2]
- if raw_xml.headers.status == "503":
- raise ThrottleError(url, \
- "503 HTTP status code returned by pinboard.in")
- if _debug:
- sys.stderr.write("%s opened successfully.\n" % url)
- return minidom.parseString(xml)
-
-
-
-
- def posts(self, tag="", date="", todt="", fromdt="", count=0):
- """Return pinboard.in bookmarks as a list of dictionaries.
-
- This should be used without arguments as rarely as possible by
- combining it with the lastupdate attribute to only get all posts when
- there is new content as it places a large load on the pinboard.in
- servers.
-
- """
- query = {}
-
- ## if a date is passed then a ranged set of date params CANNOT be passed
- if date and (todt or fromdt):
- raise DateParamsError
-
- if not count and not date and not todt and not fromdt and not tag:
- path = "all"
-
- # If attempting to load all of the posts from pinboard.in, and
- # a previous download has been done, check to see if there has
- # been an update; if not, then just return the posts stored
- # inside the class.
- if _debug:
- sys.stderr.write("Checking to see if a previous download has been made.\n")
- if not self.__postschanged and self.__allposts and \
- self.lastupdate() == self["lastupdate"]:
- if _debug:
- sys.stderr.write("It has; returning old posts instead.\n")
- return self["posts"]
- elif not self.__allposts:
- if _debug:
- sys.stderr.write("Making note of request for all posts.\n")
- self.__allposts = 1
- elif date:
- path = "get"
- elif todt or fromdt:
- path = "all"
- else:
- path = "recent"
- if count:
- query["count"] = count
- if tag:
- query["tag"] = tag
-
- ##todt
- if todt and (isinstance(todt, ListType) or isinstance(todt, TupleType)):
- query["todt"] = "-".join([str(x) for x in todt[:3]])
- elif todt and (todt and isinstance(todt, datetime.datetime) or \
- isinstance(todt, datetime.date)):
- query["todt"] = "-".join([str(todt.year), str(todt.month), str(todt.day)])
- elif todt:
- query["todt"] = todt
-
- ## fromdt
- if fromdt and (isinstance(fromdt, ListType) or isinstance(fromdt, TupleType)):
- query["fromdt"] = "-".join([str(x) for x in fromdt[:3]])
- elif fromdt and (fromdt and isinstance(fromdt, datetime.datetime) or \
- isinstance(fromdt, datetime.date)):
- query["fromdt"] = "-".join([str(fromdt.year), str(fromdt.month), str(fromdt.day)])
- elif fromdt:
- query["fromdt"] = fromdt
-
- if date and (isinstance(date, ListType) or isinstance(date, TupleType)):
- query["dt"] = "-".join([str(x) for x in date[:3]])
- elif date and (datetime and isinstance(date, datetime.datetime) or \
- isinstance(date, datetime.date)):
- query["dt"] = "-".join([str(date.year), str(date.month), str(date.day)])
- elif date:
- query["dt"] = date
-
- postsxml = self.__request("%s/posts/%s?%s" % (PINBOARD_API, path, \
- urllib.urlencode(query))).getElementsByTagName("post")
- posts = []
- if _debug:
- sys.stderr.write("Parsing posts XML into a list of dictionaries.\n")
-
- # For each post, extract every attribute (splitting tags into sub-lists)
- # and insert as a dictionary into the `posts` list.
- for post in postsxml:
- postdict = {}
- for (name, value) in post.attributes.items():
- if name == u"tag":
- name = u"tags"
- value = value.split(" ")
- if name == u"time":
- postdict[u"time_parsed"] = time.strptime(value, "%Y-%m-%dT%H:%M:%SZ")
- postdict[name] = value
- if self.has_key("posts") and isinstance(self["posts"], ListType) \
- and postdict not in self["posts"]:
- self["posts"].append(postdict)
- posts.append(postdict)
- if _debug:
- sys.stderr.write("Inserting posts list into class attribute.\n")
- if not self.has_key("posts"):
- self["posts"] = posts
- if _debug:
- sys.stderr.write("Resetting marker so module doesn't think posts has been changed.\n")
- self.__postschanged = 0
- return posts
-
- def tags(self):
- """Return a dictionary of tags with the number of posts in each one"""
- tagsxml = self.__request("%s/tags/get?" % \
- PINBOARD_API).getElementsByTagName("tag")
- tags = []
- if _debug:
- sys.stderr.write("Parsing tags XML into a list of dictionaries.\n")
- for tag in tagsxml:
- tagdict = {}
- for (name, value) in tag.attributes.items():
- if name == u"tag":
- name = u"name"
- elif name == u"count":
- value = int(value)
- tagdict[name] = value
- if self.has_key("tags") and isinstance(self["tags"], ListType) \
- and tagdict not in self["tags"]:
- self["tags"].append(tagdict)
- tags.append(tagdict)
- if _debug:
- sys.stderr.write("Inserting tags list into class attribute.\n")
- if not self.has_key("tags"):
- self["tags"] = tags
- return tags
-
- def bundles(self):
- """Return a dictionary of all bundles"""
- bundlesxml = self.__request("%s/tags/bundles/all" % \
- PINBOARD_API).getElementsByTagName("bundle")
- bundles = []
- if _debug:
- sys.stderr.write("Parsing bundles XML into a list of dictionaries.\n")
- for bundle in bundlesxml:
- bundledict = {}
- for (name, value) in bundle.attributes.items():
- bundledict[name] = value
- if self.has_key("bundles") and isinstance(self["bundles"], ListType) \
- and bundledict not in self["bundles"]:
- self["bundles"].append(bundledict)
- bundles.append(bundledict)
- if _debug:
- sys.stderr.write("Inserting bundles list into class attribute.\n")
- if not self.has_key("bundles"):
- self["bundles"] = bundles
- return bundles
-
- def dates(self, tag=""):
- """Return a dictionary of dates with the number of posts at each date"""
- if tag:
- query = urllib.urlencode({"tag":tag})
- else:
- query = ""
- datesxml = self.__request("%s/posts/dates?%s" % \
- (PINBOARD_API, query)).getElementsByTagName("date")
- dates = []
- if _debug:
- sys.stderr.write("Parsing dates XML into a list of dictionaries.\n")
- for date in datesxml:
- datedict = {}
- for (name, value) in date.attributes.items():
- if name == u"date":
- datedict[u"date_parsed"] = time.strptime(value, "%Y-%m-%d")
- elif name == u"count":
- value = int(value)
- datedict[name] = value
- if self.has_key("dates") and isinstance(self["dates"], ListType) \
- and datedict not in self["dates"]:
- self["dates"].append(datedict)
- dates.append(datedict)
- if _debug:
- sys.stderr.write("Inserting dates list into class attribute.\n")
- if not self.has_key("dates"):
- self["dates"] = dates
- return dates
-
-
- # Methods to modify pinboard.in content
-
- def add(self, url, description, extended="", tags=(), date="", toread="no"):
- """Add a new post to pinboard.in"""
- query = {}
- query["url"] = url
- query ["description"] = description
- query["toread"] = toread
- if extended:
- query["extended"] = extended
- if tags and (isinstance(tags, TupleType) or isinstance(tags, ListType)):
- query["tags"] = " ".join(tags)
- elif tags and (StringTypes and isinstance(tags, StringTypes)) or \
- (not StringTypes and (isinstance(tags, StringType) or \
- isinstance(tags, UnicodeType))):
- query["tags"] = tags
-
- # This is a rather rudimentary way of parsing date strings into
- # ISO8601 dates: if the date string is shorter than the required
- # 20 characters then it is assumed that it is a partial date
- # such as "2005-3-31" or "2005-3-31T20:00" and it is split into a
- # list along non-numerals. Empty elements are then removed
- # and then this is passed to the tuple/list case where
- # the tuple/list is padded with necessary 0s and then formatted
- # into an ISO8601 date string. This does not take into account
- # time zones.
- if date and (StringTypes and isinstance(tags, StringTypes)) or \
- (not StringTypes and (isinstance(tags, StringType) or \
- isinstance(tags, UnicodeType))) and len(date) < 20:
- date = re.split("\D", date)
- while '' in date:
- date.remove('')
- if date and (isinstance(date, ListType) or isinstance(date, TupleType)):
- date = list(date)
- if len(date) > 2 and len(date) < 6:
- for i in range(6 - len(date)):
- date.append(0)
- query["dt"] = "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ" % tuple(date)
- elif date and (datetime and (isinstance(date, datetime.datetime) \
- or isinstance(date, datetime.date))):
- query["dt"] = "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ" % date.utctimetuple()[:6]
- elif date:
- query["dt"] = date
- try:
- response = self.__request("%s/posts/add?%s" % (PINBOARD_API, \
- urllib.urlencode(query)))
- if response.firstChild.getAttribute("code") != u"done":
- raise AddError
- if _debug:
- sys.stderr.write("Post, %s (%s), added to pinboard.in\n" \
- % (description, url))
- except:
- if _debug:
- sys.stderr.write("Unable to add post, %s (%s), to pinboard.in\n" \
- % (description, url))
-
- def bundle(self, bundle, tags):
- """Bundle a set of tags together"""
- query = {}
- query["bundle"] = bundle
- if tags and (isinstance(tags, TupleType) or isinstance(tags, ListType)):
- query["tags"] = " ".join(tags)
- elif tags and isinstance(tags, StringTypes):
- query["tags"] = tags
- try:
- response = self.__request("%s/tags/bundles/set?%s" % (PINBOARD_API, \
- urllib.urlencode(query)))
- if response.firstChild.getAttribute("code") != u"done":
- raise BundleError
- if _debug:
- sys.stderr.write("Tags, %s, bundled into %s.\n" \
- % (repr(tags), bundle))
- except:
- if _debug:
- sys.stderr.write("Unable to bundle tags, %s, into %s to pinboard.in\n" \
- % (repr(tags), bundle))
-
- def delete(self, url):
- """Delete post from pinboard.in by its URL"""
- try:
- response = self.__request("%s/posts/delete?%s" % (PINBOARD_API, \
- urllib.urlencode({"url":url})))
- if response.firstChild.getAttribute("code") != u"done":
- raise DeleteError
- if _debug:
- sys.stderr.write("Post, %s, deleted from pinboard.in\n" \
- % url)
- except:
- if _debug:
- sys.stderr.write("Unable to delete post, %s, from pinboard.in\n" \
- % url)
-
- def delete_bundle(self, name):
- """Delete bundle from pinboard.in by its name"""
- try:
- response = self.__request("%s/tags/bundles/delete?%s" % (PINBOARD_API, \
- urllib.urlencode({"bundle":name})))
- if response.firstChild.getAttribute("code") != u"done":
- raise DeleteBundleError
- if _debug:
- sys.stderr.write("Bundle, %s, deleted from pinboard.in\n" \
- % name)
- except:
- if _debug:
- sys.stderr.write("Unable to delete bundle, %s, from pinboard.in\n" \
- % name)
-
- def rename_tag(self, old, new):
- """Rename a tag"""
- query = {"old":old, "new":new}
- try:
- response = self.__request("%s/tags/rename?%s" % (PINBOARD_API, \
- urllib.urlencode(query)))
- if response.firstChild.getAttribute("code") != u"done":
- raise RenameTagError
- if _debug:
- sys.stderr.write("Tag, %s, renamed to %s\n" \
- % (old, new))
- except:
- if _debug:
- sys.stderr.write("Unable to rename %s tag to %s in pinboard.in\n" \
- % (old, new))
-
-if __name__ == "__main__":
- if sys.argv[1:][0] == '-v' or sys.argv[1:][0] == '--version':
- print __version__
-
-#REVISION HISTORY
-## leaving as legacy for now, this should probably removed now for pinboard.in
-#0.1 - 29/3/2005 - PEM - Initial version.
-#0.2 - 30/3/2005 - PEM - Now using urllib's urlencode to handle query building
-# and the class now extends dict (or failing that: UserDict).
-#0.3 - 30/3/2005 - PEM - Rewrote doc strings and improved the metaphor that the
-# account is a dictionary by adding posts, tags and dates to the account
-# object when they are called. This has the added benefit of reducing
-# requests to delicious as one need only call posts(), dates() and tags()
-# once and they are stored inside the class instance until deletion.
-#0.4 - 30/3/2005 - PEM - Added private __request method to handle URL requests
-# to del.icio.us and implemented throttle detection.
-#0.5 - 30/3/2005 - PEM - Now implements every part of the API specification
-#0.6 - 30/3/2005 - PEM - Heavily vetted code to conform with PEP 8: use of
-# isinstance(), use of `if var` and `if not var` instead of comparison to
-# empty strings and changed all string delimiters to double primes for
-# consistency.
-#0.7 - 31/3/2005 - PEM - Made it so that when a fetching operation such as
-# posts() or tags() is used, only new posts are added to the class dictionary
-# in part to increase efficiency and to prevent, say, an all posts call of
-# posts() being overwritten by a specific request such as posts(tag="ruby")
-# Added more intelligent date handling for adding posts; will now attempt to
-# format any *reasonable* string, tuple or list into an ISO8601 date. Also
-# changed the command to get the lastupdate as it was convoluted. The
-# all posts command now checks to see if del.icio.us has been updated since
-# it was last called, again, this is to reduce the load on the servers and
-# increase speed a little. Changed the version string to a pre-1.0 release
-# Subversion-generated one because I am lazy.
-#0.8 - 1/4/2005 - PEM - Improved intelligence of posts caching: will only
-# re-download all posts if the posts attribute has been changed. Added
-# the mandatory delay between requests of at least one second. Changed the
-# crude string replace method to encode ampersands with a more intelligent
-# regular expression.
-#0.9 - 2/4/2005 - PEM - Now uses datetime objects when possible.
-#0.10 - 4/4/2005 - PEM - Uses the time module when the datetime module is
-# unavailable (such as versions of Python prior to 2.3). Now uses time
-# tuples instead of datetime objects when outputting for compatibility and
-# consistency. Time tuples are a new attribute: "date_parsed", with the
-# original string format of the date (or datetime) in "date" etc. Now stores
-# the headers of each request.
diff --git a/app/lib/utils/strutils.py b/app/lib/utils/strutils.py
deleted file mode 100644
index 368d3d8..0000000
--- a/app/lib/utils/strutils.py
+++ /dev/null
@@ -1,50 +0,0 @@
-
-#
-# String/unicode conversion utils.
-#
-
-def safestr(s):
- """
- Safely corerce *anything* to a string. If the object can't be str'd, an
- empty string will be returned.
-
- You can (and I do) use this for really crappy unicode handling, but it's
- a bit like killing a mosquito with a bazooka.
- """
- if s is None:
- return ""
- if isinstance(s, unicode):
- return s.encode('ascii', 'xmlcharrefreplace')
- else:
- try:
- return str(s)
- except:
- return ""
-
-def safeint(s):
- """Like safestr(), but always returns an int. Returns 0 on failure."""
- try:
- return int(safestr(s))
- except ValueError:
- return 0
-
-
-def convertentity(m):
- import htmlentitydefs
- """Convert a HTML entity into normal string (ISO-8859-1)"""
- if m.group(1)=='#':
- try:
- return chr(int(m.group(2)))
- except ValueError:
- return '&#%s;' % m.group(2)
- try:
- return htmlentitydefs.entitydefs[m.group(2)]
- except KeyError:
- return '&%s;' % m.group(2)
-
-def unquotehtml(s):
- import re
- """Convert a HTML quoted string into normal string (ISO-8859-1).
-
- Works with &#XX; and with &nbsp; &gt; etc."""
- return re.sub(r'&(#?)(.+?);',convertentity,s)
diff --git a/app/cron/sync_links.py b/app/links/sync_links.py
index cd1373d..cd1373d 100644
--- a/app/cron/sync_links.py
+++ b/app/links/sync_links.py
diff --git a/app/cron/sync_photo_sets.py b/app/photos/sync_photo_sets.py
index beac435..beac435 100644
--- a/app/cron/sync_photo_sets.py
+++ b/app/photos/sync_photo_sets.py
diff --git a/app/cron/sync_photos.py b/app/photos/sync_photos.py
index 634a2fc..634a2fc 100644
--- a/app/cron/sync_photos.py
+++ b/app/photos/sync_photos.py
diff --git a/design/templates/archives/writing_date.html b/design/templates/archives/writing_date.html
new file mode 100644
index 0000000..103d9df
--- /dev/null
+++ b/design/templates/archives/writing_date.html
@@ -0,0 +1,26 @@
+{% extends 'base.html' %}
+{% load typogrify_tags %}
+{% load html5_datetime %}
+{% block pagetitle %}{{block.super}}: Archive{% endblock %}
+{% block bodyid %}id="archive"{%endblock%}
+{% block primary %}
+<p>How did you get here? You URL chopping maniac you. Right on.</p>
+
+<h1>{% if type == 'year' %}{{date}}, on luxagraf{%else%} Archive: {{date}} {% endif %}</h1>{% if type == 'year' %}
+ <ul class="archive">{% regroup object_list by pub_date.month as entries_by_month %}{% for entries in entries_by_month %}
+ <li><span>{{ entries.list.0.pub_date|date:"F Y" }}</span>
+ <ul>{% for post in entries.list %}
+ <li>
+ <a href="{{post.get_absolute_url}}" title="{{post.title}}">{{post.title|smartypants|widont|safe }}</a>
+ <time datetime="{{post.pub_date|html5_datetime}}">{{post.pub_date|date:"M d, Y"}}</time>
+ </li> {% endfor %}
+ </ul>
+ </li>{% endfor %}
+ </ul>{% else %}
+ <ul class="archive">{% for post in object_list %}
+ <li><a href="{{post.get_absolute_url}}" title="{{post.title}}">{{post.title|smartypants|widont|safe }}</a>
+ <time datetime="{{post.pub_date|html5_datetime}}">{{post.pub_date|date:"M d, Y"}}</time>
+ </li> {% endfor %}
+ </ul>
+ {% endif %}
+{% endblock%}
diff --git a/design/templates/comments/base.html b/design/templates/comments/base.html
new file mode 100644
index 0000000..d4382ce
--- /dev/null
+++ b/design/templates/comments/base.html
@@ -0,0 +1,8 @@
+{% extends 'base.html' %}
+{% block headtitle %}{% block title %}{% trans "Responses for page" %}{% endblock %}{% endblock %}
+
+{% block main %}
+ <div id="comments-wrapper">
+ {% block content %}{% endblock %}
+ </div>
+{% endblock %}
diff --git a/design/templates/comments/comment.html b/design/templates/comments/comment.html
new file mode 100644
index 0000000..475775d
--- /dev/null
+++ b/design/templates/comments/comment.html
@@ -0,0 +1,32 @@
+{% comment %}
+ Something that django.contrib.comments does not provide:
+ An individual template for a single comment, to easily be reused.
+
+ This include is also used by the Ajax comments view.
+ The div id should be "c{id}", because the comment.get_absolute_url() points to it.
+
+ NOTE: to override the displayed date format, don't replace this template.
+ Instead, define DATETIME_FORMAT in a locale file. Requires setting:
+
+ FORMAT_MODULE_PATH = 'settings.locale'
+
+ Then create 'settings/locale/XY/formats.py' with:
+
+ DATETIME_FORMAT = '...'
+
+ This should give you consistent dates across all views.
+{% endcomment %}
+{% load i18n %}
+ <div {% if preview %} id="comment-preview"{% else %} id="comment{{ comment.id }}"{% endif %} class="p-comment h-cite u-in-reply-to comment--item {% if comment.url == "http://lux.me/" %}comment--me{%endif%}">
+ {% if preview %}<h3>{% trans "Preview of your comment" %}</h3>{% endif %}
+ <h6 class="p-author h-card comment--author">
+ {% if comment.url %}{%if comment.url == "http://lux.me/"%}<a href="/">{%else%}<a href="{{ comment.url }}" rel="nofollow">{% endif %}{% endif %}
+ {% if comment.name %}{{ comment.name }}{% else %}{% trans "Anonymous" %}{% endif %}{% comment %}
+ {% endcomment %}{% if comment.url %}</a>{% endif %}
+ {% if not comment.is_public %}<span class="comment-moderated-flag">({% trans "moderated" %})</span>{% endif %}
+ {% if USE_THREADEDCOMMENTS and not preview %}<a href="#c{{ comment.id }}" data-comment-id="{{ comment.id }}" class="comment-reply-link">{% trans "reply" %}</a>{% endif %}
+ </h6>
+ <a class="comment--datelink" href="#comment{{comment.id}}"><time datetime="{{comment.submit_date|date:'c'}}" class="dt-updated">{% blocktrans with submit_date=comment.submit_date %}{{ submit_date }}{% endblocktrans %}</time></a>
+
+ <div class="e-content comment--content">{{ comment.comment|linebreaks }}</div>
+ </div>
diff --git a/design/templates/comments/comment_notification_email.txt b/design/templates/comments/comment_notification_email.txt
new file mode 100644
index 0000000..9dfb821
--- /dev/null
+++ b/design/templates/comments/comment_notification_email.txt
@@ -0,0 +1,20 @@
+{% load url from future %}{% autoescape off %}{% comment %}
+{% endcomment %}A new comment has been posted on your site "{{ site }}, to the page entitled "{{ content_object }}".
+Link to the page: http://{{ site.domain }}{{ content_object.get_absolute_url }}
+
+IP-address: 95.97.240.121{% if comment.title %}
+Title: {{ comment.title }}{% endif %}
+Name: {{ comment.user_name|default:comment.user }}
+Email: {{ comment.user_email }}
+Homepage: {{ comment.user_url }}
+Moderated: {{ comment.is_public|yesno:'no,yes' }}
+
+Comment:
+{{ comment.comment }}
+
+----
+You have the following options available:
+ View comment -- http://{{ site.domain }}{{ comment.get_absolute_url }}
+ Flag comment -- http://{{ site.domain }}{% url 'comments-flag' comment.pk %}
+ Delete comment -- http://{{ site.domain }}{% url 'comments-delete' comment.pk %}
+{% endautoescape %} \ No newline at end of file
diff --git a/design/templates/comments/deleted.html b/design/templates/comments/deleted.html
new file mode 100644
index 0000000..c62a1ff
--- /dev/null
+++ b/design/templates/comments/deleted.html
@@ -0,0 +1,21 @@
+{% extends "comments/base.html" %}
+{% load i18n %}
+
+{% block title %}{% trans "Thanks for removing" %}.{% endblock %}
+
+{% block extrahead %}
+ {{ block.super }}
+ <meta http-equiv="Refresh" content="5; url={{ comment.content_object.get_absolute_url }}#c{{ comment.id }}" />
+{% endblock %}
+
+{% block content %}
+ <h2>{% trans "Thanks for removing the comment" %}</h2>
+ <p>
+ {% blocktrans %}
+ Thanks for taking the time to improve the quality of discussion on our site.<br/>
+ You will be sent back to the article...
+ {% endblocktrans %}
+ </p>
+
+ <p><a href="{{ comment.content_object.get_absolute_url }}#c{{ comment.id }}">{% trans "Back to the article" %}</a></p>
+{% endblock %}
diff --git a/design/templates/comments/flagged.html b/design/templates/comments/flagged.html
new file mode 100644
index 0000000..bebc151
--- /dev/null
+++ b/design/templates/comments/flagged.html
@@ -0,0 +1,21 @@
+{% extends "comments/base.html" %}
+{% load i18n %}
+
+{% block title %}{% trans "Thanks for flagging" %}.{% endblock %}
+
+{% block extrahead %}
+ {{ block.super }}
+ <meta http-equiv="Refresh" content="5; url={{ comment.content_object.get_absolute_url }}#c{{ comment.id }}" />
+{% endblock %}
+
+{% block content %}
+ <h2>{% trans "Thanks for flagging the comment" %}</h2>
+ <p>
+ {% blocktrans %}
+ Thanks for taking the time to improve the quality of discussion on our site.<br/>
+ You will be sent back to the article...
+ {% endblocktrans %}
+ </p>
+
+ <p><a href="{{ comment.content_object.get_absolute_url }}#c{{ comment.id }}">{% trans "Back to the article" %}</a></p>
+{% endblock %}
diff --git a/design/templates/comments/form.html b/design/templates/comments/form.html
new file mode 100644
index 0000000..f8bb18d
--- /dev/null
+++ b/design/templates/comments/form.html
@@ -0,0 +1,18 @@
+{% load comments i18n crispy_forms_tags fluent_comments_tags %}{% load url from future %}
+
+{% if not form.target_object|comments_are_open %}
+ <p>{% trans "Comments are closed." %}</p>
+{% else %}
+ <form action="{% comment_form_target %}" method="post" class="js-comments-form comments-form form-horizontal"
+ data-ajax-action="{% url 'comments-post-comment-ajax' %}">{% csrf_token %}
+ {% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %}
+
+ {{ form|crispy }}
+
+ <div class="form-actions">
+ <input type="submit" name="post" class="btn btn-primary" value="{% trans "Post" %}" />
+ <input type="submit" name="preview" class="btn" value="{% trans "Preview" %}" />
+ {% ajax_comment_tags %}
+ </div>
+ </form>
+{% endif %} \ No newline at end of file
diff --git a/design/templates/comments/list.html b/design/templates/comments/list.html
new file mode 100644
index 0000000..c105279
--- /dev/null
+++ b/design/templates/comments/list.html
@@ -0,0 +1,14 @@
+{% comment %}
+
+ Since we support both flat comments, and threadedcomments,
+ the 'fluent_comments_list' templatetag loads the proper template.
+
+ It either loads:
+ - fluent_comments/templatetags/flat_html.html
+ - fluent_comments/templatetags/threaded_list.html
+
+ Both reuse comments/comment.html eventually.
+ To style comments, consider overwriting that template.
+
+{% endcomment %}
+{% load fluent_comments_tags %}{% fluent_comments_list %}
diff --git a/design/templates/comments/posted.html b/design/templates/comments/posted.html
new file mode 100644
index 0000000..e13288d
--- /dev/null
+++ b/design/templates/comments/posted.html
@@ -0,0 +1,25 @@
+{% extends "comments/base.html" %}{% load i18n %}
+
+{% block title %}{% trans "Thanks for commenting" %}{% endblock %}
+
+{% block extrahead %}
+{{ block.super }}
+ <meta http-equiv="Refresh" content="5; url={{ comment.content_object.get_absolute_url }}#c{{ comment.id }}" />
+{% endblock %}
+
+{% block content %}
+ <h2>{% trans "Thanks for posting your comment" %}</h2>
+ <p>
+ {% blocktrans %}
+ We have received your comment, and posted it on the web site.<br/>
+ You will be sent back to the article...
+ {% endblocktrans %}
+ </p>
+
+ {# Use identical formatting to normal comment list #}
+ <div id="comments">
+ {% include "comments/comment.html" %}
+ </div>
+
+ <p><a href="{{ comment.content_object.get_absolute_url }}#c{{ comment.id }}">{% trans "Back to the article" %}</a></p>
+{% endblock %}
diff --git a/design/templates/comments/preview.html b/design/templates/comments/preview.html
new file mode 100644
index 0000000..663b5ca
--- /dev/null
+++ b/design/templates/comments/preview.html
@@ -0,0 +1,30 @@
+{% extends "comments/base.html" %}{% load i18n crispy_forms_tags comments %}
+
+{% block title %}{% trans "Preview your comment" %}{% endblock %}
+
+{% block content %}
+ <form action="{% comment_form_target %}" method="post" class="form-horizontal">{% csrf_token %}
+ {% if next %}<div><input type="hidden" name="next" value="{{ next }}" /></div>{% endif %}
+
+ {% if form.errors %}
+ <h2>{% blocktrans count form.errors|length as counter %}Please correct the error below{% plural %}Please correct the errors below{% endblocktrans %}</h2>
+ {% else %}
+ <h2>{% trans "Preview of your comment" %}</h2>
+
+ <blockquote class="comment-preview">{{ comment|linebreaks }}</blockquote>
+
+ <div class="form-actions">
+ <input type="submit" name="submit" class="btn btn-primary" value="{% trans "Post your comment" %}" id="submit" />
+ </div>
+
+ <p>{% trans "Or make changes" %}:</p>
+ {% endif %}
+
+ {{ form|crispy }}
+
+ <div class="form-actions">
+ <input type="submit" name="post" class="btn btn-primary" value="{% trans "Post" %}" />
+ <input type="submit" name="preview" class="btn" value="{% trans "Preview" %}" />
+ </div>
+ </form>
+{% endblock %}