summaryrefslogtreecommitdiff
path: root/django/core/rss.py
blob: 7563d2ea823862e36d19775c1ef5c08ee55dba57 (plain)
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
from django.core.exceptions import ObjectDoesNotExist
from django.core.template import Context, loader
from django.models.core import sites
from django.utils import feedgenerator
from django.conf.settings import LANGUAGE_CODE, SETTINGS_MODULE

class FeedConfiguration:
    def __init__(self, slug, title_cb, link_cb, description_cb, get_list_func_cb, get_list_kwargs,
        param_func=None, param_kwargs_cb=None, get_list_kwargs_cb=None, get_pubdate_cb=None,
        enc_url=None, enc_length=None, enc_mime_type=None):
        """
        slug -- Normal Python string. Used to register the feed.

        title_cb, link_cb, description_cb -- Functions that take the param
        (if applicable) and return a normal Python string.

        get_list_func_cb -- Function that takes the param and returns a
        function to use in retrieving items.

        get_list_kwargs -- Dictionary of kwargs to pass to the function
        returned by get_list_func_cb.

        param_func -- Function to use in retrieving the param (if applicable).

        param_kwargs_cb -- Function that takes the slug and returns a
        dictionary of kwargs to use in param_func.

        get_list_kwargs_cb -- Function that takes the param and returns a
        dictionary to use in addition to get_list_kwargs (if applicable).

        get_pubdate_cb -- Function that takes the object and returns a datetime
        to use as the publication date in the feed.

        The three enc_* parameters are strings representing methods or
        attributes to call on a particular item to get its enclosure
        information. Each of those methods/attributes should return a normal
        Python string.
        """
        self.slug = slug
        self.title_cb, self.link_cb = title_cb, link_cb
        self.description_cb = description_cb
        self.get_list_func_cb = get_list_func_cb
        self.get_list_kwargs = get_list_kwargs
        self.param_func, self.param_kwargs_cb = param_func, param_kwargs_cb
        self.get_list_kwargs_cb = get_list_kwargs_cb
        self.get_pubdate_cb = get_pubdate_cb
        assert (None == enc_url == enc_length == enc_mime_type) or (enc_url is not None and enc_length is not None and enc_mime_type is not None)
        self.enc_url = enc_url
        self.enc_length = enc_length
        self.enc_mime_type = enc_mime_type

    def get_feed(self, param_slug=None):
        """
        Returns a utils.feedgenerator.DefaultRssFeed object, fully populated,
        representing this FeedConfiguration.
        """
        if param_slug:
            try:
                param = self.param_func(**self.param_kwargs_cb(param_slug))
            except ObjectDoesNotExist:
                raise FeedIsNotRegistered
        else:
            param = None
        current_site = sites.get_current()
        f = self._get_feed_generator_object(param)
        title_template = loader.get_template('rss/%s_title' % self.slug)
        description_template = loader.get_template('rss/%s_description' % self.slug)
        kwargs = self.get_list_kwargs.copy()
        if param and self.get_list_kwargs_cb:
            kwargs.update(self.get_list_kwargs_cb(param))
        get_list_func = self.get_list_func_cb(param)
        for obj in get_list_func(**kwargs):
            link = obj.get_absolute_url()
            if not link.startswith('http://'):
                link = u'http://%s%s' % (current_site.domain, link)
            enc = None
            if self.enc_url:
                enc_url = getattr(obj, self.enc_url)
                enc_length = getattr(obj, self.enc_length)
                enc_mime_type = getattr(obj, self.enc_mime_type)
                try:
                    enc_url = enc_url()
                except TypeError:
                    pass
                try:
                    enc_length = enc_length()
                except TypeError:
                    pass
                try:
                    enc_mime_type = enc_mime_type()
                except TypeError:
                    pass
                enc = feedgenerator.Enclosure(enc_url.decode('utf-8'),
                    (enc_length and str(enc_length).decode('utf-8') or ''), enc_mime_type.decode('utf-8'))
            f.add_item(
                title = title_template.render(Context({'obj': obj, 'site': current_site})).decode('utf-8'),
                link = link,
                description = description_template.render(Context({'obj': obj, 'site': current_site})).decode('utf-8'),
                unique_id=link,
                enclosure=enc,
                pubdate = self.get_pubdate_cb and self.get_pubdate_cb(obj) or None,
            )
        return f

    def _get_feed_generator_object(self, param):
        current_site = sites.get_current()
        link = self.link_cb(param).decode()
        if not link.startswith('http://'):
            link = u'http://%s%s' % (current_site.domain, link)
        return feedgenerator.DefaultRssFeed(
            title = self.title_cb(param).decode(),
            link = link,
            description = self.description_cb(param).decode(),
            language = LANGUAGE_CODE.decode(),
        )


# global dict used by register_feed and get_registered_feed
_registered_feeds = {}

class FeedIsNotRegistered(Exception):
    pass

class FeedRequiresParam(Exception):
    pass

def register_feed(feed):
    _registered_feeds[feed.slug] = feed

def get_registered_feed(slug):
    # try to load a RSS settings module so that feeds can be registered
    try:
        __import__(SETTINGS_MODULE + '_rss', '', '', [''])
    except (KeyError, ImportError, ValueError):
        pass
    try:
        return _registered_feeds[slug]
    except KeyError:
        raise FeedIsNotRegistered