1
"""Pings utilities for Zinnia"""
5
from urllib2 import urlopen
6
from urlparse import urlsplit
7
from logging import getLogger
9
from BeautifulSoup import BeautifulSoup
11
from django.contrib.sites.models import Site
12
from django.core.urlresolvers import reverse
14
from zinnia.settings import PROTOCOL
17
class URLRessources(object):
18
"""Object defining the ressources of the website"""
21
self.current_site = Site.objects.get_current()
22
self.site_url = '%s://%s' % (PROTOCOL, self.current_site.domain)
23
self.blog_url = '%s%s' % (self.site_url,
24
reverse('zinnia_entry_archive_index'))
25
self.blog_feed = '%s%s' % (self.site_url,
26
reverse('zinnia_entry_latest_feed'))
29
class DirectoryPinger(threading.Thread):
30
"""Threaded Directory Pinger"""
32
def __init__(self, server_name, entries, timeout=10, start_now=True):
34
self.timeout = timeout
35
self.entries = entries
36
self.server_name = server_name
37
self.server = xmlrpclib.ServerProxy(self.server_name)
38
self.ressources = URLRessources()
40
threading.Thread.__init__(self)
45
"""Ping entries to a Directory in a Thread"""
46
logger = getLogger('zinnia.ping.directory')
47
socket.setdefaulttimeout(self.timeout)
48
for entry in self.entries:
49
reply = self.ping_entry(entry)
50
self.results.append(reply)
51
logger.info('%s : %s' % (self.server_name, reply['message']))
52
socket.setdefaulttimeout(None)
54
def ping_entry(self, entry):
55
"""Ping an entry to a Directory"""
56
entry_url = '%s%s' % (self.ressources.site_url,
57
entry.get_absolute_url())
58
categories = '|'.join([c.title for c in entry.categories.all()])
61
reply = self.server.weblogUpdates.extendedPing(
62
self.ressources.current_site.name,
63
self.ressources.blog_url, entry_url,
64
self.ressources.blog_feed, categories)
67
reply = self.server.weblogUpdates.ping(
68
self.ressources.current_site.name,
69
self.ressources.blog_url, entry_url,
72
reply = {'message': '%s is an invalid directory.' % \
78
class ExternalUrlsPinger(threading.Thread):
79
"""Threaded ExternalUrls Pinger"""
81
def __init__(self, entry, timeout=10, start_now=True):
84
self.timeout = timeout
85
self.ressources = URLRessources()
86
self.entry_url = '%s%s' % (self.ressources.site_url,
87
self.entry.get_absolute_url())
89
threading.Thread.__init__(self)
94
"""Ping external URLS in a Thread"""
95
logger = getLogger('zinnia.ping.external_urls')
96
socket.setdefaulttimeout(self.timeout)
98
external_urls = self.find_external_urls(self.entry)
99
external_urls_pingable = self.find_pingback_urls(external_urls)
101
for url, server_name in external_urls_pingable.items():
102
reply = self.pingback_url(server_name, url)
103
self.results.append(reply)
104
logger.info('%s : %s' % (url, reply))
106
socket.setdefaulttimeout(None)
108
def is_external_url(self, url, site_url):
109
"""Check of the url in an external url"""
110
url_splitted = urlsplit(url)
111
if not url_splitted.netloc:
113
return url_splitted.netloc != urlsplit(site_url).netloc
115
def find_external_urls(self, entry):
116
"""Find external urls in an entry"""
117
soup = BeautifulSoup(entry.html_content)
118
external_urls = [a['href'] for a in soup.findAll('a')
119
if self.is_external_url(
120
a['href'], self.ressources.site_url)]
123
def find_pingback_href(self, content):
124
"""Try to find Link markup to pingback url"""
125
soup = BeautifulSoup(content)
126
for link in soup.findAll('link'):
127
dict_attr = dict(link.attrs)
128
if 'rel' in dict_attr and 'href' in dict_attr:
129
if dict_attr['rel'].lower() == 'pingback':
130
return dict_attr.get('href')
132
def find_pingback_urls(self, urls):
133
"""Find the pingback urls of each urls"""
139
server_url = page.info().get('X-Pingback') or \
140
self.find_pingback_href(page.read())
142
server_url_splitted = urlsplit(server_url)
143
if not server_url_splitted.netloc:
144
url_splitted = urlsplit(url)
145
server_url = '%s://%s%s' % (url_splitted.scheme,
148
pingback_urls[url] = server_url
153
def pingback_url(self, server_name, target_url):
154
"""Do a pingback call for the target url"""
156
server = xmlrpclib.ServerProxy(server_name)
157
reply = server.pingback.ping(self.entry_url, target_url)
158
except xmlrpclib.Error:
159
reply = '%s cannot be pinged.' % target_url