1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - Event feed importer, based on the FeedReader macro, the irclog 4 script in MoinMoin, and the EventAggregatorNewEvent action 5 6 @copyright: 2008, 2009, 2010 by Paul Boddie <paul@boddie.org.uk> 7 2005-2007 MoinMoin:AlexanderSchremmer 8 2006 MoinMoin:ThomasWaldmann 9 10 @license: GNU GPL (v2 or later), see COPYING.txt for details. 11 """ 12 13 from MoinMoin.PageEditor import PageEditor 14 from MoinMoin.script import MoinScript 15 import EventAggregatorSupport 16 import urllib 17 import xml.dom.pulldom 18 19 # Utility class from the irclog script. 20 21 class IAmRoot(object): 22 def __getattr__(self, name): 23 return lambda *args, **kwargs: True 24 25 # The script's class. 26 27 class PluginScript(MoinScript): 28 29 """\ 30 Purpose: 31 ======== 32 This tool imports events from an RSS feed into event pages. 33 34 Detailed Instructions: 35 ====================== 36 General syntax: moin [options] import eventfeed [eventfeed-options] 37 38 [options] usually should be: 39 --config-dir=/path/to/my/cfg/ --wiki-url=wiki.example.org/ 40 41 [eventfeed-options] see below: 42 0. To import events from the FSFE event feed 43 moin ... import eventfeed --url=http://www.fsfe.org/events/events.en.rss ... 44 45 1. To use a specific template such as 'EventTemplate' 46 moin ... import eventfeed --template=EventTemplate ... 47 48 2. To assign pages to specific categories such as 'CategoryEvents CategoryMeetings' 49 moin ... import eventfeed --categories='CategoryEvents CategoryMeetings' ... 50 51 3. To use a specific author such as 'EventImporter' 52 moin ... import eventfeed --author=EventImporter ... 53 54 4. To add pages under a common parent page such as 'Events' 55 moin ... import eventfeed --parent=Events ... 56 57 5. To overwrite existing event pages 58 moin ... import eventfeed --overwrite ... 59 60 6. To delete any event pages associated with the feed 61 moin ... import eventfeed --delete ... 62 """ 63 64 FIELDS = ("title", "link", "description") 65 66 def __init__(self, argv, def_values): 67 MoinScript.__init__(self, argv, def_values) 68 self.parser.add_option( 69 "--url", dest="url", default="", 70 help="Specify the location of the events RSS feed" 71 ) 72 self.parser.add_option( 73 "--template", dest="template", default="EventTemplate", 74 help="Specify the template used to make the event pages" 75 ) 76 self.parser.add_option( 77 "--categories", dest="categories", default="CategoryEvents", 78 help="Specify the categories to which the event pages will belong" 79 ) 80 self.parser.add_option( 81 "--author", dest="author", default="EventImporter", 82 help="Specify the author of the event pages" 83 ) 84 self.parser.add_option( 85 "--parent", dest="parent", default="", 86 help="Specify the parent page of the event pages" 87 ) 88 self.parser.add_option( 89 "--overwrite", dest="overwrite", action="store_true", 90 help="Request that existing pages be overwritten" 91 ) 92 self.parser.add_option( 93 "--delete", dest="delete", action="store_true", 94 help="Request that event pages associated with the feed be deleted" 95 ) 96 97 def mainloop(self): 98 self.init_request() 99 if not self.options.url: 100 print "No URL specified. Not importing any events!" 101 else: 102 self.read_events(self.options.url) 103 104 def read_events(self, url): 105 106 """ 107 Read events from the given events RSS feed, specified by 'url', creating 108 new Wiki pages where appropriate. 109 """ 110 111 request = self.request 112 request.user.may = IAmRoot() 113 category_pagenames = self.options.categories.split() 114 115 # Locate the template for events. 116 117 template_page = PageEditor(request, self.options.template) 118 119 if not template_page.exists(): 120 print "Template %r cannot be found. Not importing any events!" % self.options.template 121 return 122 123 # Process the feed. 124 125 feed = urllib.urlopen(url) 126 127 try: 128 nodes = xml.dom.pulldom.parse(feed) 129 event_details = {} 130 131 in_item = 0 132 133 # Read the nodes from the feed. 134 135 for node_type, value in nodes: 136 if node_type == xml.dom.pulldom.START_ELEMENT: 137 if value.nodeName == "item": 138 in_item = 1 139 140 # Get the value of the important fields. 141 142 elif in_item and value.nodeName in self.FIELDS: 143 nodes.expandNode(value) 144 event_details[value.nodeName] = self.text(value) 145 146 # Where all fields have been read, make a new page. 147 148 if reduce(lambda x, y: x and event_details.has_key(y), self.FIELDS, 1): 149 150 # Define the page. 151 152 title = event_details["title"] 153 154 # Use any parent page information. 155 156 full_title = EventAggregatorSupport.getFullPageName(self.options.parent, title) 157 158 # Find the start and end dates. 159 160 dates = EventAggregatorSupport.getDateStrings(title) 161 162 # Require one or two dates. 163 164 if dates and 1 <= len(dates) <= 2: 165 166 # Deduce the end date. 167 168 if len(dates) == 2: 169 start_date, end_date = dates 170 elif len(dates) == 1: 171 start_date = end_date = dates[0] 172 173 # Load the new page and replace the event details in the body. 174 175 new_page = PageEditor(request, full_title, 176 uid_override=self.options.author) 177 178 # Delete the page if requested. 179 180 if new_page.exists() and self.options.delete: 181 182 try: 183 new_page.deletePage() 184 except new_page.AccessDenied: 185 print "Page %r has not been deleted." % full_title 186 187 # Complete the new page. 188 189 elif not new_page.exists() or self.options.overwrite: 190 event_details["summary"] = title 191 event_details["start"] = start_date 192 event_details["end"] = end_date 193 194 try: 195 EventAggregatorSupport.fillEventPageFromTemplate( 196 template_page, new_page, event_details, 197 category_pagenames) 198 199 except new_page.Unchanged: 200 print "Page %r is not changed." % full_title 201 202 else: 203 print "Not overwriting page %r." % full_title 204 205 else: 206 print "Could not deduce dates from %r." % title 207 208 event_details = {} 209 210 elif node_type == xml.dom.pulldom.END_ELEMENT: 211 if value.nodeName == "item": 212 in_item = 0 213 214 finally: 215 feed.close() 216 217 def text(self, element): 218 219 "Return the text within the given 'element'." 220 221 nodes = [] 222 for node in element.childNodes: 223 if node.nodeType == node.TEXT_NODE: 224 nodes.append(node.nodeValue) 225 return "".join(nodes) 226 227 # vim: tabstop=4 expandtab shiftwidth=4