User:7SeriesBOT/code


 * 1) !/usr/bin/python
 * 2) -*- coding: utf-8 -*-

""" SpeedyBot: Complying pages are deleted; no confirmation is given to the requesting user - the delete just happens. Checks against the category are run every 30 seconds, so the average turn-around will be about 15 seconds.

G7: Any entry in Category:Candidates for speedy deletion by user is checked for simple compliance with CSD-G7: a single contributor talk page. Pages are required to have one of the appropriate templates - , ,, . Redirects created by moving pages or pages that are transcluded anywhere will not be deleted.

CSD-G7 allows for pages other than those with a single contributor to be deleted (no substantial contributions from others), but that requires judgment and so the bot will only delete those with a single contributor.

U1: Any entry in Category:Candidates for speedy deletion by user is checked for simple compliance with CSD-U1: a single contributor (Bot contributions are ignored) user page. Pages are required to have one of the appropriate templates -, etc. Redirects created by moving pages or pages that are transcluded anywhere will not be deleted. """

import time, re import wikipedia

__metaclass__ = type

g7_deletereason= u'Only one contributor who requested deletion under WP:CSD' u1_deletereason= u'User requested deletion under WP:CSD' db_g7_category= u'Category:Candidates for speedy deletion by user' logpage_text = u"\n*%s %s http://en.wikipedia.org/w/index.php?title=%s&action=history 10:47, 5 May 2013 (UTC)"

class SpeedyBot: def __init__(self, trial=False, site=None): if site is None: site = wikipedia.getSite self.site = site self.trial = trial self.number_to_fetch = 5000 # templates for deletion, which may take parameter(s) self.g7_regex = re.compile("""           \{\{     #start template            (        #one of the following templates:            [Cc]sd-g7|            [Cc]SD:G7|            G7|g7|            [Dd][bB]-self|            [Dd]b-blanked|            [Dd]b-authora|            [Dd]b-auth|            [Dd]b-author|            [Dd]b-[Gg]7            )            (        #one of the following character strings:            \|[^\}]*}}|     # a template with parameter(s)            }})             # a template without a parameter given            """, re.VERBOSE) self.u1_regex = re.compile("""           \{\{     #start template            (        #one of the following templates:            [Cc]sd-u1|            [Dd]b[-]user|            [Dd]b-owner|            [Ddb]-[Uu]serpage|            [Dd]b-u|            [Uu]serreq|            [Dd]b-userreq|            [Uu]1            )            (        #one of the following character strings:            \|[^\}]*}}|     # a template with parameter(s)            }})             # a template without a parameter given            """, re.VERBOSE)

def pages_in_category(self, category): """       Yield Page objects for all members of the category,         both as they exist at calltime and then as they are added to it        """ if not wikipedia.config.use_api or self.site.versionnumber < 11: print "Can't run against this site - configuration problem" return

# seen is used to prevent repeated re-processing seen = set start_timestamp = None while True: params = { 'action'    :'query', 'list'      :'categorymembers', 'cmtitle'   :category, 'cmlimit'   :self.number_to_fetch, 'cmprop'    :['ids', 'title', 'timestamp'], 'cmsort'    :'timestamp', 'cmdir'     :'asc', 'cmnamespace':'1|3|5|7|9|11|13|15|101|109', }           if start_timestamp: params['cmstart'] = start_timestamp

clcontinue = None done = False while not done: if clcontinue: params['clcontinue'] = clcontinue

# empty data in case we can't find the right structures data = result = wikipedia.query.GetData(params, self.site) if 'query' in result: if 'categorymembers' in result['query']: data = result['query']['categorymembers'] if 'query-continue' in data: clcontinue = data['query-continue']['categories']['clcontinue'] else: done = True for np in data: start_timestamp = np['timestamp'] if np['pageid'] not in seen: seen.add(np['pageid']) page = wikipedia.Page(self.site, np['title']) yield page time.sleep(30)

def get_all_bots(self): """       Loads a list of all flagged bots, and saves it to self.bots        """ params = { 'action'   :'query', 'list'     :'allusers', 'augroup'   :'bot' }       data = wikipedia.query.GetData(params,self.site)['query']['allusers'] all_bots = [p['name'] for p in data] del data self.bots = all_bots def owner_is_only_contributor(self, page): """       Given a wikipedia.Page object, it determines if the page is in the         proper namespace, and if there is one or zero non bot contributors,        and that any non-bot contributor is the owner.        """ result = False contributors = [con for con in page.contributingUsers \ if con not in self.bots]    #remove all bots if page.namespace not in [2,3]: # Mustn't delete outside userspace result = False elif len(contributors) == 0: # bot created page... presumably a bot requesting deletion too result = True elif len(contributors) == 1: # Check only the owner contributed if page.namespace == 2: print "checking %s against %s" % (contributors[0], page.title[5:]) result = contributors[0] == page.title[5:] elif page.namespace == 3: print "checking %s against %s" % (contributors[0], page.title[10:]) result = contributors[0] == page.title[10:] return result

def isTranscluded(self, page): for transclusion in page.getReferences(follow_redirects=True,            withTemplateInclusion=True, onlyTemplateInclusion=True): return True return False

def hasBeenMoved(self, page): if not wikipedia.config.use_api or self.site.versionnumber < 8: print "Can't run against this site - configuration problem" return

# retrive the edit comment for the first edit params = { 'action'   :'query', 'prop'     :'revisions', 'titles'   :page.title, 'rvprop'   :['comment'], 'rvdir'    :'newer', 'rvlimit'  :1, }       # empty data in case we can't find the right structures data = result = wikipedia.query.GetData(params, self.site) if 'query' in result: if 'pages' in result['query']: data = result['query']['pages']

for pageid in data: if 'revisions' in data[pageid]: for history_record in data[pageid]['revisions']: for record in history_record: if re.search("moved %s to" % page.title,                           history_record[record], re.IGNORECASE): return True return False def log(self, page, text): wikipedia.output(u"%s %s" % (page.title, text)) if self.trial: log_page = wikipedia.Page(self.site, u"User:7SeriesBOT/Dry-Run 2") try: old_text = log_page.get except wikipedia.NoPage: old_text = '' title = page.title.replace(" ","_") new_text = old_text + logpage_text % (page.title, text, title) wikipedia.showDiff(old_text, new_text) log_page.put(new_text, text)

def run(self): try: self.get_all_bots for page in self.pages_in_category(db_g7_category): if not page.isTalkPage: self.log(page, u"isn't a Talk page") continue try: if self.hasBeenMoved(page): self.log(page, u'was once moved') continue if self.isTranscluded(page): self.log(page, u'is transcluded') continue if self.g7_regex.search(page.get): if len(page.contributingUsers) != 1: self.log(page, u'has multiple contributors') continue if not self.trial: page.delete(reason=g7_deletereason, prompt=False,                                    throttle=False, mark=False) self.log(page, u'deleted') elif self.u1_regex.search(page.get): if not self.owner_is_only_contributor(page): self.log(page, u'has non-bot, non-owner contributors') continue if not page.isTalkPage: if not self.owner_is_only_contributor(page.toggleTalkPage): self.log(page, u'has talk page with non-bot, non-owner contributors') continue if not self.trial: page.delete(reason=u1_deletereason, prompt=False,                                    throttle=False, mark=False) self.log(page, u'deleted') else: self.log(page, u'missing template on page') continue except wikipedia.NoPage: wikipedia.output(u'"NoPage" error processing page: %s' % \                       page.title) except wikipedia.IsRedirectPage: wikipedia.output(u'"IsRedirectPage" error processing page: %s' % \                       page.title) except: wikipedia.output(u'Unhandled exception') except: wikipedia.stopme raise finally: wikipedia.stopme print 'Bot exits'

if __name__ == "__main__": print "Really deletes if run with parameter -R, otherwise in trial mode" print " - ctrl-C to kill program" trial = True for arg in wikipedia.handleArgs: if arg[:2].upper=='-R': print "** In production mode: Really deleting these pages **" trial = False if trial: print " - relax, we're in trial mode" bot = SpeedyBot(trial) bot.run print 'Main thread exits'
 * 1) MAIN