From 53107016d2b3611289099f00d030e922622c8b76 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Sat, 5 Dec 2015 03:41:49 -0600 Subject: [PATCH] First version of infobox_station.py --- README.md | 3 ++ tasks/infobox_station.py | 131 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 tasks/infobox_station.py diff --git a/README.md b/README.md index 635542d..197e139 100644 --- a/README.md +++ b/README.md @@ -95,3 +95,6 @@ Bot Tasks is in `tasks/schema/drn_clerkbot.sql`. - **image_display_resize**: resizes upscaled portraits in infoboxes. + +- **infobox_station**: replaces specific deprecated infoboxes following a + template discussion. diff --git a/tasks/infobox_station.py b/tasks/infobox_station.py new file mode 100644 index 0000000..bb8a54a --- /dev/null +++ b/tasks/infobox_station.py @@ -0,0 +1,131 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2015 Ben Kurtovic +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from __future__ import unicode_literals + +from earwigbot.tasks import Task +from earwigbot.wiki import constants + +import mwparserfromhell + +class InfoboxStation(Task): + """ + A task to replace ``{{Infobox China station}}`` and + ``{{Infobox Japan station}}`` with ``{{Infobox station}}``. + """ + name = "infobox_station" + number = 20 + + def setup(self): + self.site = self.bot.wiki.getsite() + self._targets = { + "China": ( + ["Infobox China station", "Infobox china station"], + "Infobox China station/sandbox", + "Infobox China station/sandbox/cats", + "Wikipedia:Templates for discussion/Log/2015 February 8#Template:Infobox China station" + ), + "Japan": ( + ["Infobox Japan station", "Infobox japan station"], + "Infobox Japan station/sandbox", + "Infobox Japan station/sandbox/cats", + "Wikipedia:Templates for discussion/Log/2015 May 9#Template:Infobox Japan station" + ), + } + self._replacement = "{{Infobox station}}" + self.summary = self.make_summary( + "Replacing {source} with {dest} per [[{discussion}|TfD]].") + + def run(self, **kwargs): + for name, args in self._targets.items(): + if self.shutoff_enabled(): + return + self._replace(name, args) + + def _replace(self, name, args): + """ + Replace a template in all pages that transclude it. + """ + self.logger.info("Replacing {0} infobox template".format(name)) + + count = 0 + for search in args[0]: + for title in self._get_transclusions(search): + count += 1 + if count % 10 == 0 and self.shutoff_enabled(): + return + page = self.site.get_page(title) + self._process_page(page, search, args) + + def _process_page(self, page, search, args): + """ + Process a single page to replace a template. + """ + self.logger.debug("Processing [[{0}]]".format(page.title)) + if not page.check_exclusion(): + self.logger.warn("Bot excluded from [[{0}]]".format(page.title)) + return + + code = mwparserfromhell.parse(page.get(), skip_style_tags=True) + for tmpl in code.filter_templates(): + if tmpl.name.matches(search): + tmpl.name = "subst:" + args[2] + self._add_cats(code, unicode(tmpl)) + tmpl.name = "subst:" + args[1] + break + + if code == page.get(): + msg = "Couldn't figure out what to edit in [[{0}]]" + self.logger.warn(msg.format(page.title)) + return + + summary = self.summary.format( + source="{{" + search + "}}", dest="{{" + self._replacement + "}}", + discussion=args[3]) + page.edit(unicode(code), summary, minor=True) + + def _add_cats(self, code, cats): + """Add category data (*cats*) to wikicode.""" + for link in code.ifilter_wikilinks(): + if link.title.lower().startswith("category:"): + code.insert_before(link, cats + "\n") + return + + for tmpl in code.filter_templates(): + if tmpl.name.lower().endswith("stub"): + prev = code.get(code.index(tmpl) - 1) + if prev.endswith("\n\n"): + code.replace(prev, prev[:-1]) + code.insert_before(tmpl, cats + "\n\n") + + def _get_transclusions(self, title): + """ + Return a list of mainspace translusions of the given template. + """ + query = """SELECT page_title + FROM templatelinks + LEFT JOIN page ON tl_from = page_id + WHERE tl_namespace = ? AND tl_title = ? AND tl_from_namespace = ?""" + + results = self.site.sql_query(query, ( + constants.NS_TEMPLATE, title.replace(" ", "_"), constants.NS_MAIN)) + return [title for (title,) in results]