1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

# Copyright 2013-2018 The Distro Tracker Developers 

# See the COPYRIGHT file at the top-level directory of this distribution and 

# at https://deb.li/DTAuthors 

# 

# This file is part of Distro Tracker. It is subject to the license terms 

# in the LICENSE file found in the top-level directory of this 

# distribution and at https://deb.li/DTLicense. No part of Distro Tracker, 

# including this file, may be copied, modified, propagated, or distributed 

# except according to the terms contained in the LICENSE file. 

"""Implements the RSS news feed.""" 

 

import re 

from itertools import chain 

 

from django.conf import settings 

from django.contrib.syndication.views import Feed 

from django.http import Http404 

 

from distro_tracker.core.models import ( 

ActionItem, 

News, 

NewsRenderer, 

get_web_package 

) 

 

 

def filter_control_chars(method): 

"""Filter out undesirable control characters.""" 

# We have to filter out control chars otherwise the FeedGenerator 

# raises UnserializableContentError (see django/utils/xmlutils.py) 

def wrapped(self, obj): 

result = method(self, obj) 

return re.sub(r'[\x00-\x08\x0B-\x0C\x0E-\x1F]', '', result) 

return wrapped 

 

 

class PackageNewsFeed(Feed): 

_DEFAULT_LIMIT = 30 

 

def get_object(self, request, package_name): 

package = get_web_package(package_name) 

if package is None: 

raise Http404 

 

return package 

 

@filter_control_chars 

def title(self, obj): 

return "{vendor} package news for {pkg}".format( 

vendor=settings.DISTRO_TRACKER_VENDOR_NAME, 

pkg=obj.name) 

 

@filter_control_chars 

def link(self, obj): 

return obj.get_absolute_url() 

 

@filter_control_chars 

def description(self, obj): 

return ( 

"Latest developer's news for {vendor} source package {pkg}" 

.format(vendor=settings.DISTRO_TRACKER_VENDOR_NAME, pkg=obj.name) 

) 

 

def items(self, obj): 

item_limit = getattr(settings, 'DISTRO_TRACKER_RSS_ITEM_LIMIT', 

self._DEFAULT_LIMIT) 

 

news = obj.news_set.all() 

action_items = obj.action_items.all() 

 

def item_key(item): 

if isinstance(item, ActionItem): 

return item.last_updated_timestamp 

74 ↛ exitline 74 didn't return from function 'item_key', because the condition on line 74 was never false elif isinstance(item, News): 

return item.datetime_created 

 

all_items = chain(news, action_items) 

return sorted(all_items, key=item_key, reverse=True)[:item_limit] 

 

@filter_control_chars 

def item_title(self, item): 

if isinstance(item, News): 

return item.title 

84 ↛ exitline 84 didn't return from function 'item_title', because the condition on line 84 was never false elif isinstance(item, ActionItem): 

return item.short_description 

 

@filter_control_chars 

def item_description(self, item): 

if isinstance(item, News): 

renderer_class = NewsRenderer.get_renderer_for_content_type( 

item.content_type) 

92 ↛ 93line 92 didn't jump to line 93, because the condition on line 92 was never true if renderer_class is None: 

renderer_class = NewsRenderer.get_renderer_for_content_type( 

'text/plain') 

renderer = renderer_class(item) 

 

return renderer.render_to_string() 

98 ↛ exitline 98 didn't return from function 'item_description', because the condition on line 98 was never false elif isinstance(item, ActionItem): 

return item.full_description 

 

def item_pubdate(self, item): 

if isinstance(item, ActionItem): 

return item.last_updated_timestamp 

104 ↛ exitline 104 didn't return from function 'item_pubdate', because the condition on line 104 was never false elif isinstance(item, News): 

return item.datetime_created