/gstudio/xmlrpc/pingback.py

https://github.com/sumegha/django-gstudio · Python · 140 lines · 126 code · 12 blank · 2 comment · 4 complexity · 37a1d0883afaf4ccf503deb310a6283d MD5 · raw file

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