1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/scripts/import/eventfeed.py Sat Mar 06 22:51:27 2010 +0100
1.3 @@ -0,0 +1,220 @@
1.4 +# -*- coding: iso-8859-1 -*-
1.5 +"""
1.6 + MoinMoin - Event feed importer, based on the FeedReader macro, the irclog
1.7 + script in MoinMoin, and the EventAggregatorNewEvent action
1.8 +
1.9 + @copyright: 2008, 2009, 2010 by Paul Boddie <paul@boddie.org.uk>
1.10 + 2005-2007 MoinMoin:AlexanderSchremmer
1.11 + 2006 MoinMoin:ThomasWaldmann
1.12 +
1.13 + @license: GNU GPL (v2 or later), see COPYING.txt for details.
1.14 +"""
1.15 +
1.16 +from MoinMoin.PageEditor import PageEditor
1.17 +from MoinMoin.script import MoinScript
1.18 +import EventAggregatorSupport
1.19 +import urllib
1.20 +import xml.dom.pulldom
1.21 +
1.22 +# The script's class.
1.23 +
1.24 +class PluginScript(MoinScript):
1.25 +
1.26 + """\
1.27 +Purpose:
1.28 +========
1.29 +This tool imports events from an RSS feed into event pages.
1.30 +
1.31 +Detailed Instructions:
1.32 +======================
1.33 +General syntax: moin [options] import eventfeed [eventfeed-options]
1.34 +
1.35 +[options] usually should be:
1.36 + --config-dir=/path/to/my/cfg/ --wiki-url=wiki.example.org/
1.37 +
1.38 +[eventfeed-options] see below:
1.39 + 0. To import events from the FSFE event feed
1.40 + moin ... import eventfeed --url=http://www.fsfe.org/events/events.en.rss ...
1.41 +
1.42 + 1. To use a specific template such as 'EventTemplate'
1.43 + moin ... import eventfeed --template=EventTemplate ...
1.44 +
1.45 + 2. To assign pages to specific categories such as 'CategoryEvents CategoryMeetings'
1.46 + moin ... import eventfeed --categories='CategoryEvents CategoryMeetings' ...
1.47 +
1.48 + 3. To use a specific author such as 'EventImporter'
1.49 + moin ... import eventfeed --author=EventImporter ...
1.50 +
1.51 + 4. To add pages under a common parent page such as 'Events'
1.52 + moin ... import eventfeed --parent=Events ...
1.53 +
1.54 + 5. To overwrite existing event pages
1.55 + moin ... import eventfeed --overwrite ...
1.56 +
1.57 + 5. To delete any event pages associated with the feed
1.58 + moin ... import eventfeed --delete ...
1.59 +"""
1.60 +
1.61 + FIELDS = ("title", "link", "description")
1.62 +
1.63 + def __init__(self, argv, def_values):
1.64 + MoinScript.__init__(self, argv, def_values)
1.65 + self.parser.add_option(
1.66 + "--url", dest="url", default="",
1.67 + help="Specify the location of the events RSS feed"
1.68 + )
1.69 + self.parser.add_option(
1.70 + "--template", dest="template", default="EventTemplate",
1.71 + help="Specify the template used to make the event pages"
1.72 + )
1.73 + self.parser.add_option(
1.74 + "--categories", dest="categories", default="CategoryEvents",
1.75 + help="Specify the categories to which the event pages will belong"
1.76 + )
1.77 + self.parser.add_option(
1.78 + "--author", dest="author", default="EventImporter",
1.79 + help="Specify the author of the event pages"
1.80 + )
1.81 + self.parser.add_option(
1.82 + "--parent", dest="parent", default="",
1.83 + help="Specify the parent page of the event pages"
1.84 + )
1.85 + self.parser.add_option(
1.86 + "--overwrite", dest="overwrite", action="store_true",
1.87 + help="Request that existing pages be overwritten"
1.88 + )
1.89 + self.parser.add_option(
1.90 + "--delete", dest="delete", action="store_true",
1.91 + help="Request that event pages associated with the feed be deleted"
1.92 + )
1.93 +
1.94 + def mainloop(self):
1.95 + self.init_request()
1.96 + if not self.options.url:
1.97 + print "No URL specified. Not importing any events!"
1.98 + else:
1.99 + self.read_events(self.options.url)
1.100 +
1.101 + def read_events(self, url):
1.102 +
1.103 + """
1.104 + Read events from the given events RSS feed, specified by 'url', creating
1.105 + new Wiki pages where appropriate.
1.106 + """
1.107 +
1.108 + request = self.request
1.109 + category_pagenames = self.options.categories.split()
1.110 +
1.111 + # Locate the template for events.
1.112 +
1.113 + template_page = PageEditor(request, self.options.template)
1.114 +
1.115 + if not template_page.exists():
1.116 + print "Template %r cannot be found. Not importing any events!" % self.options.template
1.117 + return
1.118 +
1.119 + # Process the feed.
1.120 +
1.121 + feed = urllib.urlopen(url)
1.122 +
1.123 + try:
1.124 + nodes = xml.dom.pulldom.parse(feed)
1.125 + event_details = {}
1.126 +
1.127 + in_item = 0
1.128 +
1.129 + # Read the nodes from the feed.
1.130 +
1.131 + for node_type, value in nodes:
1.132 + if node_type == xml.dom.pulldom.START_ELEMENT:
1.133 + if value.nodeName == "item":
1.134 + in_item = 1
1.135 +
1.136 + # Get the value of the important fields.
1.137 +
1.138 + elif in_item and value.nodeName in self.FIELDS:
1.139 + nodes.expandNode(value)
1.140 + event_details[value.nodeName] = self.text(value)
1.141 +
1.142 + # Where all fields have been read, make a new page.
1.143 +
1.144 + if reduce(lambda x, y: x and event_details.has_key(y), self.FIELDS, 1):
1.145 +
1.146 + # Define the page.
1.147 +
1.148 + title = event_details["title"]
1.149 +
1.150 + # Use any parent page information.
1.151 +
1.152 + full_title = EventAggregatorSupport.getFullPageName(self.options.parent, title)
1.153 +
1.154 + # Find the start and end dates.
1.155 +
1.156 + dates = EventAggregatorSupport.getDateStrings(title)
1.157 +
1.158 + # Require one or two dates.
1.159 +
1.160 + if dates and 1 <= len(dates) <= 2:
1.161 +
1.162 + # Deduce the end date.
1.163 +
1.164 + if len(dates) == 2:
1.165 + start_date, end_date = dates
1.166 + elif len(dates) == 1:
1.167 + start_date = end_date = dates[0]
1.168 +
1.169 + # Load the new page and replace the event details in the body.
1.170 +
1.171 + new_page = PageEditor(request, full_title,
1.172 + uid_override=self.options.author)
1.173 +
1.174 + # Delete the page if requested.
1.175 +
1.176 + if new_page.exists() and self.options.delete:
1.177 +
1.178 + try:
1.179 + new_page.deletePage()
1.180 + except new_page.AccessDenied:
1.181 + print "Page %r has not been deleted." % full_title
1.182 +
1.183 + # Complete the new page.
1.184 +
1.185 + elif not new_page.exists() or self.options.overwrite:
1.186 + event_details["summary"] = title
1.187 + event_details["start"] = start_date
1.188 + event_details["end"] = end_date
1.189 +
1.190 + try:
1.191 + EventAggregatorSupport.fillEventPageFromTemplate(
1.192 + template_page, new_page, event_details,
1.193 + category_pagenames)
1.194 +
1.195 + except new_page.Unchanged:
1.196 + print "Page %r is not changed." % full_title
1.197 +
1.198 + else:
1.199 + print "Not overwriting page %r." % full_title
1.200 +
1.201 + else:
1.202 + print "Could not deduce dates from %r." % title
1.203 +
1.204 + event_details = {}
1.205 +
1.206 + elif node_type == xml.dom.pulldom.END_ELEMENT:
1.207 + if value.nodeName == "item":
1.208 + in_item = 0
1.209 +
1.210 + finally:
1.211 + feed.close()
1.212 +
1.213 + def text(self, element):
1.214 +
1.215 + "Return the text within the given 'element'."
1.216 +
1.217 + nodes = []
1.218 + for node in element.childNodes:
1.219 + if node.nodeType == node.TEXT_NODE:
1.220 + nodes.append(node.nodeValue)
1.221 + return "".join(nodes)
1.222 +
1.223 +# vim: tabstop=4 expandtab shiftwidth=4