Wiki source code of Macros for displaying Blog-related RSS feeds
Last modified by Jan Rhebergen on 2021/02/27 22:16
Show last authors
author | version | line-number | content |
---|---|---|---|
1 | {{include reference="Blog.BlogCode"/}} | ||
2 | |||
3 | {{velocity output="false"}} | ||
4 | ## | ||
5 | ## | ||
6 | ## | ||
7 | #** | ||
8 | * Display a blog as a RSS feed. The output corresponds to the RSS 1.0 specification, and it makes use of the Dublin | ||
9 | * Core module to specify metadata. | ||
10 | * | ||
11 | * @param blogDoc The XDocument corresponding to the blog to be syndicated. | ||
12 | * @param entries The entries to display. Usually, these are the last entries belonging to the blog. | ||
13 | *### | ||
14 | #macro(displayBlogRss $blogDoc $entries) | ||
15 | ## Create a Jodatime date formatter that will be used to format dates | ||
16 | #set($dateFormatter = $xwiki.jodatime.getDateTimeFormatterForPattern("yyyy-MM-dd'T'hh:mm:ssZZ")) | ||
17 | ## Set the right mimetype | ||
18 | $!response.setContentType('application/rss+xml')## | ||
19 | #setBlogRssCacheSettings() | ||
20 | #printBlogRssHeader() | ||
21 | #printBlogRssChannelDescription($blogDoc $entries) | ||
22 | #printBlogRssImage($blogDoc) | ||
23 | #printBlogRssItems($entries) | ||
24 | #printBlogRssFooter() | ||
25 | #end | ||
26 | ## | ||
27 | ## | ||
28 | ## | ||
29 | #** | ||
30 | * Display blog entries from all the wiki as a RSS feed. The output corresponds to the RSS 1.0 specification, and it | ||
31 | * makes use of the Dublin Core module to specify metadata. | ||
32 | * | ||
33 | * @param entries The entries to display. Usually, these are the last entries belonging to the blog. | ||
34 | *### | ||
35 | #macro(displayGlobalBlogRss $entries) | ||
36 | ## Create a Jodatime date formatter that will be used to format dates | ||
37 | #set($dateFormatter = $xwiki.jodatime.getDateTimeFormatterForPattern("yyyy-MM-dd'T'hh:mm:ssZZ")) | ||
38 | ## Set the right mimetype | ||
39 | $!response.setContentType('application/rss+xml')## | ||
40 | #setBlogRssCacheSettings() | ||
41 | #printBlogRssHeader() | ||
42 | #printGlobalBlogRssChannelDescription($entries) | ||
43 | #printWikiRssImage($blogDoc) | ||
44 | #printBlogRssItems($entries) | ||
45 | #printBlogRssFooter() | ||
46 | #end | ||
47 | ## | ||
48 | ## | ||
49 | ## | ||
50 | #** | ||
51 | * Display blog entries belonging to a target category as a RSS feed. The output corresponds to the RSS 1.0 | ||
52 | * specification, and it makes use of the Dublin Core module to specify metadata. | ||
53 | * | ||
54 | * @param blogDoc The XDocument corresponding to the blog to be syndicated. | ||
55 | * @param categoryDoc The XDocument corresponding to the blog category to be syndicated. | ||
56 | * @param entries The entries to display. Usually, these are the last entries belonging to the blog. | ||
57 | *### | ||
58 | #macro(displayBlogCategoryRss $blogDoc $categoryDoc $entries) | ||
59 | ## Create a Jodatime date formatter that will be used to format dates | ||
60 | #set($dateFormatter = $xwiki.jodatime.getDateTimeFormatterForPattern("yyyy-MM-dd'T'hh:mm:ssZZ")) | ||
61 | ## Set the right mimetype | ||
62 | $!response.setContentType('application/rss+xml')## | ||
63 | #setBlogRssCacheSettings() | ||
64 | #printBlogRssHeader() | ||
65 | #printBlogCategoryRssChannelDescription($categoryDoc $entries) | ||
66 | #printBlogRssItems($entries) | ||
67 | #printBlogRssFooter() | ||
68 | #end | ||
69 | ## | ||
70 | ## | ||
71 | ## | ||
72 | #** | ||
73 | * Set the proper cache settings, both for the client (HTTP headers) and for the server (rendering cache). | ||
74 | *### | ||
75 | #macro(setBlogRssCacheSettings) | ||
76 | ## Internally cache the rendered RSS for 30 minutes, for better performance | ||
77 | ## TODO: This is disabled for security reasons. Since the cache doesn't take into account the current user, it might | ||
78 | ## serve hidden/unpublished entries to non-creators. | ||
79 | ## $!xcontext.setCacheDuration(1800) | ||
80 | ## Instruct the client to cache the response for 1 hour | ||
81 | #set($expires = $xwiki.jodatime.getMutableDateTime())## | ||
82 | $!expires.addHours(1)## | ||
83 | ## TODO: This has no effect, as the core contains a no-cache setting in com.xpn.xwiki.web.Utils | ||
84 | $!response.setDateHeader('Expires', $expires.millis)## | ||
85 | $!response.setHeader('Cache-Control', 'public')## | ||
86 | #end | ||
87 | ## | ||
88 | ## | ||
89 | ## | ||
90 | #** | ||
91 | * Print the start of the RSS: XML declaration and open root element. | ||
92 | *### | ||
93 | #macro(printBlogRssHeader) | ||
94 | <?xml version="1.0" encoding="$xwiki.encoding" ?> | ||
95 | <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:dc="http://purl.org/dc/elements/1.1/"> | ||
96 | #end | ||
97 | ## | ||
98 | ## | ||
99 | ## | ||
100 | #** | ||
101 | * Print the blog channel description: title, link, description, logo, creator, copyright, and the list of entries. | ||
102 | * | ||
103 | * @param blogDoc The XDocument corresponding to the blog to be displayed. | ||
104 | * @param entries The entries to display. Usually, these are the last entries belonging to the blog. | ||
105 | *### | ||
106 | #macro(printBlogRssChannelDescription $blogDoc $entries) | ||
107 | <channel rdf:about="$blogDoc.getURL()"> | ||
108 | #getBlogTitle($blogDoc $title) | ||
109 | <title>$title</title> | ||
110 | <link>$blogDoc.getExternalURL()</link> | ||
111 | ## TODO: Add a Description field in the blog class | ||
112 | <description>$services.localization.render('blog.code.description.space', [$blogDoc.space])</description> | ||
113 | #getWikiLogo($logoUrl) | ||
114 | <image rdf:resource="$logoUrl"/> | ||
115 | <dc:language>$blogDoc.defaultLocale</dc:language> | ||
116 | <dc:rights>$escapetool.xml($xwiki.spaceCopyright)</dc:rights> | ||
117 | ## TODO: Usually this is not something meaningful. Maybe add some Blog object properties for these. | ||
118 | ## <dc:publisher>$escapetool.xml($xwiki.getUserName($blogDoc.author, false))</dc:publisher> | ||
119 | ## <dc:creator>$escapetool.xml($xwiki.getUserName($blogDoc.creator, false))</dc:creator> | ||
120 | <items> | ||
121 | <rdf:Seq> | ||
122 | ## This is just a list of blog entries, which are detailed below. | ||
123 | #foreach ($entryDoc in $entries) | ||
124 | #if($xwiki.hasAccessLevel('view', ${entryDoc.fullName})) | ||
125 | <rdf:li rdf:resource="$entryDoc.getExternalURL('view', "language=${entryDoc.realLanguage}")" /> | ||
126 | #end | ||
127 | #end | ||
128 | </rdf:Seq> | ||
129 | </items> | ||
130 | </channel> | ||
131 | #end | ||
132 | ## | ||
133 | ## | ||
134 | ## | ||
135 | #** | ||
136 | * Print the wiki-wide channel description: title, link, description, logo, creator, copyright, and the list of entries. | ||
137 | * | ||
138 | * @param entries The entries to display. Usually, these are the last entries published in the wiki. | ||
139 | *### | ||
140 | #macro(printGlobalBlogRssChannelDescription $entries) | ||
141 | #set ($mainDoc = $xwiki.getDocument($services.model.resolveDocument('', 'default', $doc.documentReference.extractReference('WIKI')))) | ||
142 | <channel rdf:about="$mainDoc.getExternalURL()"> | ||
143 | <title>$escapetool.xml($mainDoc.plainTitle)</title> | ||
144 | <link>$mainDoc.getExternalURL()</link> | ||
145 | ## TODO: Add a Description field in the blog class | ||
146 | <description>$services.localization.render('blog.code.description.wiki')</description> | ||
147 | #getWikiLogo($logoUrl) | ||
148 | <image rdf:resource="$logoUrl"/> | ||
149 | <dc:rights>$escapetool.xml($xwiki.spaceCopyright)</dc:rights> | ||
150 | <dc:publisher>XWiki</dc:publisher> | ||
151 | <items> | ||
152 | <rdf:Seq> | ||
153 | ## This is just a list of blog entries, which are detailed below. | ||
154 | #foreach ($entryDoc in $entries) | ||
155 | #if($xwiki.hasAccessLevel('view', ${entryDoc.fullName})) | ||
156 | <rdf:li rdf:resource="$entryDoc.getExternalURL('view', "language=${entryDoc.realLanguage}")" /> | ||
157 | #end | ||
158 | #end | ||
159 | </rdf:Seq> | ||
160 | </items> | ||
161 | </channel> | ||
162 | #end | ||
163 | ## | ||
164 | ## | ||
165 | ## | ||
166 | #** | ||
167 | * Print the blog channel description: title, link, description, logo, creator, copyright, and the list of entries. | ||
168 | * | ||
169 | * @param blogDoc The XDocument corresponding to the blog to be displayed. | ||
170 | * @param entries The entries to display. Usually, these are the last entries belonging to the blog. | ||
171 | *### | ||
172 | #macro(printBlogCategoryRssChannelDescription $categoryDoc $entries) | ||
173 | <channel rdf:about="$categoryDoc.getURL()"> | ||
174 | #set ($macro.rssFeedTitle = $services.localization.render($categoryDoc.getValue('name'))) | ||
175 | #if ($categoryDoc.getObject('XWiki.DocumentSheetBinding').sheet == $blogCategoriesSheet)## Categories home page | ||
176 | #set ($macro.rssFeedTitle = $categoryDoc.title) | ||
177 | #if ("$!macro.rssFeedTitle" == '') | ||
178 | #set ($macro.rssFeedTitle = $services.localization.render('blog.categories.webhome.title')) | ||
179 | #end | ||
180 | #end | ||
181 | <title>$!macro.rssFeedTitle</title> | ||
182 | <link>$categoryDoc.getExternalURL()</link> | ||
183 | ## TODO: Add a Description field in the blog class | ||
184 | <description>$services.localization.render('blog.code.description.category', [$categoryDoc.display('name')])</description> | ||
185 | <dc:rights>$escapetool.xml($xwiki.spaceCopyright)</dc:rights> | ||
186 | <items> | ||
187 | <rdf:Seq> | ||
188 | ## This is just a list of blog entries, which are detailed below. | ||
189 | #foreach ($entryDoc in $entries) | ||
190 | #if($xwiki.hasAccessLevel('view', ${entryDoc.fullName})) | ||
191 | <rdf:li rdf:resource="$entryDoc.getExternalURL('view', "language=${entryDoc.realLanguage}")" /> | ||
192 | #end | ||
193 | #end | ||
194 | </rdf:Seq> | ||
195 | </items> | ||
196 | </channel> | ||
197 | #end | ||
198 | ## | ||
199 | ## | ||
200 | ## | ||
201 | #** | ||
202 | * Print the blog image description. Currently, this is the logo of the wiki. | ||
203 | * | ||
204 | * @param blogDoc The XDocument corresponding to the displayed blog. | ||
205 | *### | ||
206 | #macro(printBlogRssImage $blogDoc) | ||
207 | #getWikiLogo($logoUrl) | ||
208 | <image rdf:about="$logoUrl"> | ||
209 | <title>Wiki Logo</title> | ||
210 | <url>$logoUrl</url> | ||
211 | <link>$blogDoc.getExternalURL()</link> | ||
212 | </image> | ||
213 | #end | ||
214 | ## | ||
215 | ## | ||
216 | ## | ||
217 | #** | ||
218 | * Print the syndicated blog entries. These are the detailed "item"s, which must be referenced above, in the channel | ||
219 | * description, as otherwise they are ignored. | ||
220 | * | ||
221 | * @param entries The entries to display. Usually, these are the last entries belonging to the blog. | ||
222 | *### | ||
223 | #macro(printBlogRssItems $entries) | ||
224 | ## Print all the entry details | ||
225 | #foreach ($entryDoc in $entries) | ||
226 | #if($xwiki.hasAccessLevel('view', ${entryDoc.fullName})) | ||
227 | #printBlogRssItem($entryDoc) | ||
228 | #end | ||
229 | #end | ||
230 | #end | ||
231 | ## | ||
232 | ## | ||
233 | ## | ||
234 | #** | ||
235 | * Print a blog entry in the RSS feed. besides the mandatory RSS elements (title, link, and description), also print | ||
236 | * some metadata in the Dublin Core vocabulary (creator, categories, date). | ||
237 | * | ||
238 | * @param entryDoc The XDocument corresponding to the displayed blog entry. | ||
239 | *### | ||
240 | #macro(printBlogRssItem $entryDoc) | ||
241 | #set($entryUrl = $entryDoc.getExternalURL('view', "language=${entryDoc.realLanguage}")) | ||
242 | #getEntryObject($entryDoc $entryObj) | ||
243 | #getEntryContent($entryDoc $entryObj true $entryContent) | ||
244 | #if($!entryDoc.syntax.toIdString() == 'xwiki/1.0') | ||
245 | #set($desc = $entryContent) | ||
246 | #else | ||
247 | #set($desc = $entryDoc.getRenderedContent($entryContent, $entryDoc.getSyntax().toIdString())) | ||
248 | #end | ||
249 | #set($desc = $escapetool.xml($desc)) | ||
250 | <item rdf:about="$entryUrl"> | ||
251 | <title>$escapetool.xml($entryDoc.display("title", "view", $entryObj))</title> | ||
252 | <link>$entryUrl</link> | ||
253 | <description>$desc</description> | ||
254 | ## Some metadata, using the Dublin Core extension to RSS. | ||
255 | ## TODO: Display this in a better way. | ||
256 | <dc:subject>$escapetool.xml($entryObj.display('category', 'view'))</dc:subject> | ||
257 | <dc:date>$dateFormatter.print($entryDoc.date.time)</dc:date> | ||
258 | <dc:creator>$escapetool.xml($xwiki.getUserName($entryDoc.creator, false))</dc:creator> | ||
259 | #if($entryDoc.creator != $entryDoc.author) | ||
260 | <dc:contributor> | ||
261 | <rdf:Description link="$xwiki.getURL($entryDoc.author)"> | ||
262 | <rdf:value>$escapetool.xml($xwiki.getUserName($entryDoc.author, false))</rdf:value> | ||
263 | </rdf:Description> | ||
264 | </dc:contributor> | ||
265 | #end | ||
266 | </item> | ||
267 | #end | ||
268 | ## | ||
269 | ## | ||
270 | ## | ||
271 | #** | ||
272 | * Print the end of the RSS: close the root element. | ||
273 | *### | ||
274 | #macro(printBlogRssFooter) | ||
275 | </rdf:RDF> | ||
276 | #end | ||
277 | ## | ||
278 | ## | ||
279 | ## | ||
280 | #** | ||
281 | * Normally, this should be a Template eXtension, which would be used to display a blog as a RSS feed. Since TX are not | ||
282 | * yet implemented, the target blog should be passed in the URL. This macro determines exactly which blog should be | ||
283 | * syndicated. If the "blog" request parameter is not present, then the default Blog is used. | ||
284 | * | ||
285 | * @param blogDoc The resulting XDocument of the target blog. | ||
286 | *### | ||
287 | #macro(getTargetBlog $blogDoc) | ||
288 | #if("$!{request.blog}" != '') | ||
289 | #set($result = $xwiki.getDocument($request.blog)) | ||
290 | #else | ||
291 | #getBlogDocument('Blog' $result) | ||
292 | #end | ||
293 | #set ($blogDoc = $NULL) | ||
294 | #setVariable ("$blogDoc" $result) | ||
295 | ## TODO: Check if the document has a Blog.BlogClass object. | ||
296 | #end | ||
297 | ## | ||
298 | ## | ||
299 | ## | ||
300 | #macro(printFieldContent $entryDoc $entryObj $fieldName) | ||
301 | $escapetool.xml($entryDoc.display($fieldName, 'view', $entryObj))#end | ||
302 | ## | ||
303 | ## | ||
304 | ## | ||
305 | #macro(getWikiLogo $logoUrl) | ||
306 | #set ($path = $xwiki.getSkinFile($xwiki.getSkinPreference('logo', 'logo.png'))) | ||
307 | #set ($port = '') | ||
308 | #if (($request.scheme == 'http') && ($request.serverPort != 80)) | ||
309 | #set ($port = ":${request.serverPort}") | ||
310 | #elseif (($request.scheme == 'https') && ($request.serverPort != 443)) | ||
311 | #set ($port = ":${request.serverPort}") | ||
312 | #end | ||
313 | #set ($logoUrl = $NULL) | ||
314 | #setVariable ("$logoUrl" "${request.scheme}://${request.serverName}${port}${path}") | ||
315 | #end | ||
316 | {{/velocity}} |