PageRenderTime 54ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/zinnia/xmlrpc/pingback.py

https://github.com/aparo/django-blog-zinnia
Python | 141 lines | 127 code | 12 blank | 2 comment | 4 complexity | f6d58d7abbc1174650179b91ac4c4e09 MD5 | raw file
Possible License(s): GPL-3.0
  1. """XML-RPC methods of Zinnia Pingback"""
  2. from urllib2 import urlopen
  3. from urllib2 import URLError
  4. from urllib2 import HTTPError
  5. from urlparse import urlsplit
  6. from django.contrib import comments
  7. from django.utils.html import strip_tags
  8. from django.contrib.sites.models import Site
  9. from django.core.urlresolvers import resolve
  10. from django.core.urlresolvers import Resolver404
  11. from django.utils.translation import ugettext as _
  12. from django.contrib.contenttypes.models import ContentType
  13. from zinnia.models import Entry
  14. from zinnia.managers import PINGBACK
  15. from zinnia.settings import PINGBACK_CONTENT_LENGTH
  16. from BeautifulSoup import BeautifulSoup
  17. from django_xmlrpc.decorators import xmlrpc_func
  18. UNDEFINED_ERROR = 0
  19. SOURCE_DOES_NOT_EXIST = 16
  20. SOURCE_DOES_NOT_LINK = 17
  21. TARGET_DOES_NOT_EXIST = 32
  22. TARGET_IS_NOT_PINGABLE = 33
  23. PINGBACK_ALREADY_REGISTERED = 48
  24. def generate_pingback_content(soup, target, max_length, trunc_char='...'):
  25. """Generate a description text for the pingback"""
  26. link = soup.find('a', href=target)
  27. content = strip_tags(unicode(link.findParent()))
  28. index = content.index(link.string)
  29. if len(content) > max_length:
  30. middle = max_length / 2
  31. start = index - middle
  32. end = index + middle
  33. if start <= 0:
  34. end -= start
  35. extract = content[0:end]
  36. else:
  37. extract = '%s%s' % (trunc_char, content[start:end])
  38. if end < len(content):
  39. extract += trunc_char
  40. return extract
  41. return content
  42. @xmlrpc_func(returns='string', args=['string', 'string'])
  43. def pingback_ping(source, target):
  44. """pingback.ping(sourceURI, targetURI) => 'Pingback message'
  45. Notifies the server that a link has been added to sourceURI,
  46. pointing to targetURI.
  47. See: http://hixie.ch/specs/pingback/pingback-1.0"""
  48. try:
  49. if source == target:
  50. return UNDEFINED_ERROR
  51. site = Site.objects.get_current()
  52. try:
  53. document = ''.join(urlopen(source).readlines())
  54. except (HTTPError, URLError):
  55. return SOURCE_DOES_NOT_EXIST
  56. if not target in document:
  57. return SOURCE_DOES_NOT_LINK
  58. scheme, netloc, path, query, fragment = urlsplit(target)
  59. if netloc != site.domain:
  60. return TARGET_DOES_NOT_EXIST
  61. try:
  62. view, args, kwargs = resolve(path)
  63. except Resolver404:
  64. return TARGET_DOES_NOT_EXIST
  65. try:
  66. entry = Entry.published.get(
  67. slug=kwargs['slug'],
  68. creation_date__year=kwargs['year'],
  69. creation_date__month=kwargs['month'],
  70. creation_date__day=kwargs['day'])
  71. if not entry.pingback_enabled:
  72. return TARGET_IS_NOT_PINGABLE
  73. except (KeyError, Entry.DoesNotExist):
  74. return TARGET_IS_NOT_PINGABLE
  75. soup = BeautifulSoup(document)
  76. title = soup.find('title')
  77. title = title and strip_tags(title) or _('No title')
  78. description = generate_pingback_content(soup, target,
  79. PINGBACK_CONTENT_LENGTH)
  80. comment, created = comments.get_model().objects.get_or_create(
  81. content_type=ContentType.objects.get_for_model(Entry),
  82. object_pk=entry.pk, user_url=source, site=site,
  83. defaults={'comment': description, 'user_name': title})
  84. if created:
  85. user = entry.authors.all()[0]
  86. comment.flags.create(user=user, flag=PINGBACK)
  87. return 'Pingback from %s to %s registered.' % (source, target)
  88. return PINGBACK_ALREADY_REGISTERED
  89. except:
  90. return UNDEFINED_ERROR
  91. @xmlrpc_func(returns='string[]', args=['string'])
  92. def pingback_extensions_get_pingbacks(target):
  93. """pingback.extensions.getPingbacks(url) => '[url, url, ...]'
  94. Returns an array of URLs that link to the specified url.
  95. See: http://www.aquarionics.com/misc/archives/blogite/0198.html"""
  96. site = Site.objects.get_current()
  97. scheme, netloc, path, query, fragment = urlsplit(target)
  98. if netloc != site.domain:
  99. return TARGET_DOES_NOT_EXIST
  100. try:
  101. view, args, kwargs = resolve(path)
  102. except Resolver404:
  103. return TARGET_DOES_NOT_EXIST
  104. try:
  105. entry = Entry.published.get(
  106. slug=kwargs['slug'],
  107. creation_date__year=kwargs['year'],
  108. creation_date__month=kwargs['month'],
  109. creation_date__day=kwargs['day'])
  110. except (KeyError, Entry.DoesNotExist):
  111. return TARGET_IS_NOT_PINGABLE
  112. return [pingback.user_url for pingback in entry.pingbacks]