diff options
Diffstat (limited to 'gstudio/xmlrpc/pingback.py')
-rw-r--r-- | gstudio/xmlrpc/pingback.py | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/gstudio/xmlrpc/pingback.py b/gstudio/xmlrpc/pingback.py new file mode 100644 index 0000000..44aaafd --- /dev/null +++ b/gstudio/xmlrpc/pingback.py @@ -0,0 +1,140 @@ +"""XML-RPC methods of Gstudio Pingback""" +from urllib2 import urlopen +from urllib2 import URLError +from urllib2 import HTTPError +from urlparse import urlsplit + +from django.contrib import comments +from django.utils.html import strip_tags +from django.contrib.sites.models import Site +from django.core.urlresolvers import resolve +from django.core.urlresolvers import Resolver404 +from django.utils.translation import ugettext as _ +from django.contrib.contenttypes.models import ContentType + +from gstudio.models import Nodetype +from gstudio.settings import PINGBACK_CONTENT_LENGTH +from BeautifulSoup import BeautifulSoup +from django_xmlrpc.decorators import xmlrpc_func + +UNDEFINED_ERROR = 0 +SOURCE_DOES_NOT_EXIST = 16 +SOURCE_DOES_NOT_LINK = 17 +TARGET_DOES_NOT_EXIST = 32 +TARGET_IS_NOT_PINGABLE = 33 +PINGBACK_ALREADY_REGISTERED = 48 + + +def generate_pingback_content(soup, target, max_length, trunc_char='...'): + """Generate a description text for the pingback""" + link = soup.find('a', href=target) + + content = strip_tags(unicode(link.findParent())) + index = content.index(link.string) + + if len(content) > max_length: + middle = max_length / 2 + start = index - middle + end = index + middle + + if start <= 0: + end -= start + extract = content[0:end] + else: + extract = '%s%s' % (trunc_char, content[start:end]) + + if end < len(content): + extract += trunc_char + return extract + + return content + + +@xmlrpc_func(returns='string', args=['string', 'string']) +def pingback_ping(source, target): + """pingback.ping(sourceURI, targetURI) => 'Pingback message' + + Notifies the server that a link has been added to sourceURI, + pointing to targetURI. + + See: http://hixie.ch/specs/pingback/pingback-1.0""" + try: + if source == target: + return UNDEFINED_ERROR + + site = Site.objects.get_current() + try: + document = ''.join(urlopen(source).readlines()) + except (HTTPError, URLError): + return SOURCE_DOES_NOT_EXIST + + if not target in document: + return SOURCE_DOES_NOT_LINK + + scheme, netloc, path, query, fragment = urlsplit(target) + if netloc != site.domain: + return TARGET_DOES_NOT_EXIST + + try: + view, args, kwargs = resolve(path) + except Resolver404: + return TARGET_DOES_NOT_EXIST + + try: + nodetype = Nodetype.published.get( + slug=kwargs['slug'], + creation_date__year=kwargs['year'], + creation_date__month=kwargs['month'], + creation_date__day=kwargs['day']) + if not nodetype.pingback_enabled: + return TARGET_IS_NOT_PINGABLE + except (KeyError, Nodetype.DoesNotExist): + return TARGET_IS_NOT_PINGABLE + + soup = BeautifulSoup(document) + title = soup.find('title') + title = title and strip_tags(title) or _('No title') + description = generate_pingback_content(soup, target, + PINGBACK_CONTENT_LENGTH) + + comment, created = comments.get_model().objects.get_or_create( + content_type=ContentType.objects.get_for_model(Nodetype), + object_pk=nodetype.pk, user_url=source, site=site, + defaults={'comment': description, 'user_name': title}) + if created: + user = nodetype.authors.all()[0] + comment.flags.create(user=user, flag='pingback') + return 'Pingback from %s to %s registered.' % (source, target) + return PINGBACK_ALREADY_REGISTERED + except: + return UNDEFINED_ERROR + + +@xmlrpc_func(returns='string[]', args=['string']) +def pingback_extensions_get_pingbacks(target): + """pingback.extensions.getPingbacks(url) => '[url, url, ...]' + + Returns an array of URLs that link to the specified url. + + See: http://www.aquarionics.com/misc/archives/blogite/0198.html""" + site = Site.objects.get_current() + + scheme, netloc, path, query, fragment = urlsplit(target) + if netloc != site.domain: + return TARGET_DOES_NOT_EXIST + + try: + view, args, kwargs = resolve(path) + except Resolver404: + return TARGET_DOES_NOT_EXIST + + try: + nodetype = Nodetype.published.get( + slug=kwargs['slug'], + creation_date__year=kwargs['year'], + creation_date__month=kwargs['month'], + creation_date__day=kwargs['day']) + except (KeyError, Nodetype.DoesNotExist): + return TARGET_IS_NOT_PINGABLE + + return [pingback.user_url for pingback in nodetype.pingbacks] |