1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/MoinMoin/script/import/eventfeed.py Sat Mar 13 15:59:30 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
2.1 --- a/README.txt Thu Mar 11 23:43:19 2010 +0100
2.2 +++ b/README.txt Sat Mar 13 15:59:30 2010 +0100
2.3 @@ -36,7 +36,8 @@
2.4 Installation
2.5 ------------
2.6
2.7 -To install the support library, consider using the setup.py script provided:
2.8 +To install the support library and MoinMoin-related scripts, consider using
2.9 +the setup.py script provided:
2.10
2.11 python setup.py install
2.12
2.13 @@ -89,16 +90,6 @@
2.14 actions directory in this distribution into the actions directory of your
2.15 Wiki.
2.16
2.17 -To install the eventfeed script which can import events from RSS feeds, use
2.18 -the instscripts script, making sure to set your PYTHONPATH so that the script
2.19 -can find your MoinMoin installation:
2.20 -
2.21 - PYTHONPATH=path-to-site-packages ./instscripts
2.22 -
2.23 -This script should work on UNIX and non-UNIX systems, although the above
2.24 -example demonstrates setting the PYTHONPATH in the bash shell on UNIX-like
2.25 -systems.
2.26 -
2.27 Useful Pages
2.28 ------------
2.29
3.1 --- a/scripts/import/eventfeed.py Thu Mar 11 23:43:19 2010 +0100
3.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
3.3 @@ -1,220 +0,0 @@
3.4 -# -*- coding: iso-8859-1 -*-
3.5 -"""
3.6 - MoinMoin - Event feed importer, based on the FeedReader macro, the irclog
3.7 - script in MoinMoin, and the EventAggregatorNewEvent action
3.8 -
3.9 - @copyright: 2008, 2009, 2010 by Paul Boddie <paul@boddie.org.uk>
3.10 - 2005-2007 MoinMoin:AlexanderSchremmer
3.11 - 2006 MoinMoin:ThomasWaldmann
3.12 -
3.13 - @license: GNU GPL (v2 or later), see COPYING.txt for details.
3.14 -"""
3.15 -
3.16 -from MoinMoin.PageEditor import PageEditor
3.17 -from MoinMoin.script import MoinScript
3.18 -import EventAggregatorSupport
3.19 -import urllib
3.20 -import xml.dom.pulldom
3.21 -
3.22 -# The script's class.
3.23 -
3.24 -class PluginScript(MoinScript):
3.25 -
3.26 - """\
3.27 -Purpose:
3.28 -========
3.29 -This tool imports events from an RSS feed into event pages.
3.30 -
3.31 -Detailed Instructions:
3.32 -======================
3.33 -General syntax: moin [options] import eventfeed [eventfeed-options]
3.34 -
3.35 -[options] usually should be:
3.36 - --config-dir=/path/to/my/cfg/ --wiki-url=wiki.example.org/
3.37 -
3.38 -[eventfeed-options] see below:
3.39 - 0. To import events from the FSFE event feed
3.40 - moin ... import eventfeed --url=http://www.fsfe.org/events/events.en.rss ...
3.41 -
3.42 - 1. To use a specific template such as 'EventTemplate'
3.43 - moin ... import eventfeed --template=EventTemplate ...
3.44 -
3.45 - 2. To assign pages to specific categories such as 'CategoryEvents CategoryMeetings'
3.46 - moin ... import eventfeed --categories='CategoryEvents CategoryMeetings' ...
3.47 -
3.48 - 3. To use a specific author such as 'EventImporter'
3.49 - moin ... import eventfeed --author=EventImporter ...
3.50 -
3.51 - 4. To add pages under a common parent page such as 'Events'
3.52 - moin ... import eventfeed --parent=Events ...
3.53 -
3.54 - 5. To overwrite existing event pages
3.55 - moin ... import eventfeed --overwrite ...
3.56 -
3.57 - 5. To delete any event pages associated with the feed
3.58 - moin ... import eventfeed --delete ...
3.59 -"""
3.60 -
3.61 - FIELDS = ("title", "link", "description")
3.62 -
3.63 - def __init__(self, argv, def_values):
3.64 - MoinScript.__init__(self, argv, def_values)
3.65 - self.parser.add_option(
3.66 - "--url", dest="url", default="",
3.67 - help="Specify the location of the events RSS feed"
3.68 - )
3.69 - self.parser.add_option(
3.70 - "--template", dest="template", default="EventTemplate",
3.71 - help="Specify the template used to make the event pages"
3.72 - )
3.73 - self.parser.add_option(
3.74 - "--categories", dest="categories", default="CategoryEvents",
3.75 - help="Specify the categories to which the event pages will belong"
3.76 - )
3.77 - self.parser.add_option(
3.78 - "--author", dest="author", default="EventImporter",
3.79 - help="Specify the author of the event pages"
3.80 - )
3.81 - self.parser.add_option(
3.82 - "--parent", dest="parent", default="",
3.83 - help="Specify the parent page of the event pages"
3.84 - )
3.85 - self.parser.add_option(
3.86 - "--overwrite", dest="overwrite", action="store_true",
3.87 - help="Request that existing pages be overwritten"
3.88 - )
3.89 - self.parser.add_option(
3.90 - "--delete", dest="delete", action="store_true",
3.91 - help="Request that event pages associated with the feed be deleted"
3.92 - )
3.93 -
3.94 - def mainloop(self):
3.95 - self.init_request()
3.96 - if not self.options.url:
3.97 - print "No URL specified. Not importing any events!"
3.98 - else:
3.99 - self.read_events(self.options.url)
3.100 -
3.101 - def read_events(self, url):
3.102 -
3.103 - """
3.104 - Read events from the given events RSS feed, specified by 'url', creating
3.105 - new Wiki pages where appropriate.
3.106 - """
3.107 -
3.108 - request = self.request
3.109 - category_pagenames = self.options.categories.split()
3.110 -
3.111 - # Locate the template for events.
3.112 -
3.113 - template_page = PageEditor(request, self.options.template)
3.114 -
3.115 - if not template_page.exists():
3.116 - print "Template %r cannot be found. Not importing any events!" % self.options.template
3.117 - return
3.118 -
3.119 - # Process the feed.
3.120 -
3.121 - feed = urllib.urlopen(url)
3.122 -
3.123 - try:
3.124 - nodes = xml.dom.pulldom.parse(feed)
3.125 - event_details = {}
3.126 -
3.127 - in_item = 0
3.128 -
3.129 - # Read the nodes from the feed.
3.130 -
3.131 - for node_type, value in nodes:
3.132 - if node_type == xml.dom.pulldom.START_ELEMENT:
3.133 - if value.nodeName == "item":
3.134 - in_item = 1
3.135 -
3.136 - # Get the value of the important fields.
3.137 -
3.138 - elif in_item and value.nodeName in self.FIELDS:
3.139 - nodes.expandNode(value)
3.140 - event_details[value.nodeName] = self.text(value)
3.141 -
3.142 - # Where all fields have been read, make a new page.
3.143 -
3.144 - if reduce(lambda x, y: x and event_details.has_key(y), self.FIELDS, 1):
3.145 -
3.146 - # Define the page.
3.147 -
3.148 - title = event_details["title"]
3.149 -
3.150 - # Use any parent page information.
3.151 -
3.152 - full_title = EventAggregatorSupport.getFullPageName(self.options.parent, title)
3.153 -
3.154 - # Find the start and end dates.
3.155 -
3.156 - dates = EventAggregatorSupport.getDateStrings(title)
3.157 -
3.158 - # Require one or two dates.
3.159 -
3.160 - if dates and 1 <= len(dates) <= 2:
3.161 -
3.162 - # Deduce the end date.
3.163 -
3.164 - if len(dates) == 2:
3.165 - start_date, end_date = dates
3.166 - elif len(dates) == 1:
3.167 - start_date = end_date = dates[0]
3.168 -
3.169 - # Load the new page and replace the event details in the body.
3.170 -
3.171 - new_page = PageEditor(request, full_title,
3.172 - uid_override=self.options.author)
3.173 -
3.174 - # Delete the page if requested.
3.175 -
3.176 - if new_page.exists() and self.options.delete:
3.177 -
3.178 - try:
3.179 - new_page.deletePage()
3.180 - except new_page.AccessDenied:
3.181 - print "Page %r has not been deleted." % full_title
3.182 -
3.183 - # Complete the new page.
3.184 -
3.185 - elif not new_page.exists() or self.options.overwrite:
3.186 - event_details["summary"] = title
3.187 - event_details["start"] = start_date
3.188 - event_details["end"] = end_date
3.189 -
3.190 - try:
3.191 - EventAggregatorSupport.fillEventPageFromTemplate(
3.192 - template_page, new_page, event_details,
3.193 - category_pagenames)
3.194 -
3.195 - except new_page.Unchanged:
3.196 - print "Page %r is not changed." % full_title
3.197 -
3.198 - else:
3.199 - print "Not overwriting page %r." % full_title
3.200 -
3.201 - else:
3.202 - print "Could not deduce dates from %r." % title
3.203 -
3.204 - event_details = {}
3.205 -
3.206 - elif node_type == xml.dom.pulldom.END_ELEMENT:
3.207 - if value.nodeName == "item":
3.208 - in_item = 0
3.209 -
3.210 - finally:
3.211 - feed.close()
3.212 -
3.213 - def text(self, element):
3.214 -
3.215 - "Return the text within the given 'element'."
3.216 -
3.217 - nodes = []
3.218 - for node in element.childNodes:
3.219 - if node.nodeType == node.TEXT_NODE:
3.220 - nodes.append(node.nodeValue)
3.221 - return "".join(nodes)
3.222 -
3.223 -# vim: tabstop=4 expandtab shiftwidth=4
4.1 --- a/setup.py Thu Mar 11 23:43:19 2010 +0100
4.2 +++ b/setup.py Sat Mar 13 15:59:30 2010 +0100
4.3 @@ -9,5 +9,5 @@
4.4 author_email = "paul@boddie.org.uk",
4.5 url = "http://moinmo.in/MacroMarket/EventAggregator",
4.6 version = "0.6",
4.7 - py_modules = ["EventAggregatorSupport"]
4.8 + py_modules = ["EventAggregatorSupport", "MoinMoin.script.import.eventfeed"]
4.9 )