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