#!/usr/bin/env python # -*- coding: utf-8 -*- from __future__ import division import wikipedia, pagegenerators import oursql, re, time, urllib import cgitb; cgitb.enable(logdir='tracebacks') def colorValue(subset, total, revert = False): v = min(255 * subset // max(subset, total), 255) if (revert): v = 255 - v; blue = 00 if (v < 128): # Red to Yellow red = 255 green = 2 * v else: # Yellow to Green red = 2 * (255 - v) green = 255 return "#%02X%02X%02X" % (red, green, blue) connections = {} def getConn(wiki): if not wiki.endswith('_p'): wiki+='_p' if wiki not in connections: connections[wiki] = oursql.connect( db=wiki, host=wiki.replace('_', '-')+'.rrdb.toolserver.org', read_default_file='/home/dispenser/.my.cnf', charset='utf8', use_unicode=False ) return connections[wiki] class UserActivity: def __init__(self): self.page = wikipedia.MyPage self.days = 365 def main(self): site = wikipedia.getSite() action = 0 for arg in wikipedia.handleArgs(): if arg.startswith('-page:'): self.page = wikipedia.Page(site, arg[6:]) site = self.page.site() elif arg.startswith('-inactivetime:'): pass elif arg.startswith('-view:edit'): action = 2 elif arg.startswith('-days:'): try: self.days = int(arg[6:]) except: pass print '
' print '
Member activity check' print ':
' % (self.page.title().encode('utf-8'),) print ' days (0 to disable)
'%self.days print '
' print '' print '
' if not self.page.title(): return self.dbname = site.dbName() self.domain = site.hostname() conn = getConn(site.dbName()) self.cursor = conn.cursor() self.cursor.execute(""" SELECT page_is_redirect, CONCAT(ns_name, ':', rd_title) FROM page LEFT JOIN redirect ON rd_from=page_id LEFT JOIN toolserver.namespacename ON ns_id=rd_namespace AND ns_is_favorite=1 AND dbname=(SELECT DATABASE()) WHERE page_namespace=? AND page_title=?""", (self.page.namespace(), self.page.titleWithoutNamespace(underscore=True).encode('utf-8'),) ) exists = self.cursor.fetchall() if not exists: wikipedia.output("%s does not exist"%self.page.aslink()) return elif 1 in exists[0]: print '#REDIRECT %s'% ( wikipedia.escape(exists[0][1]), wikipedia.escape(exists[0][1]), ) return else: pass #self.cursor.execute("CREATE DATABASE IF NOT EXISTS u_dispenser_p") self.cursor.execute('SET @ThirtyDays = (SELECT DATE_FORMAT(NOW()-INTERVAL 30 DAY, "%Y%m%d"))') self.cursor.execute("""/* useractivity LIMIT:300 */ CREATE TEMPORARY TABLE u_dispenser_p.userlist ( pl_title VARBINARY(255) NOT NULL, pl_user VARBINARY(255) NOT NULL, last_edit DATETIME NULL, PRIMARY KEY (`pl_title`) ) ENGINE=MyISAM AS SELECT DISTINCT pl_title, REPLACE(pl_title, "_", " ") AS pl_user, NULL AS last_edit FROM page AS list JOIN pagelinks ON list.page_id=pl_from WHERE list.page_namespace=? AND list.page_title=? AND pl_namespace IN (2,3) AND pl_title NOT LIKE "%/%" """, (self.page.namespace(), self.page.titleWithoutNamespace(underscore=True).encode('utf-8'),)) # Do this seperate since MySQL's optimizer screws it up self.cursor.execute("SELECT pl_user FROM u_dispenser_p.userlist;") for (pl_user,) in self.cursor: self.cursor.execute("""/* useractivity LIMIT:300 */ UPDATE u_dispenser_p.userlist SET last_edit=TIMESTAMP((SELECT MAX(rev_timestamp) FROM revision WHERE rev_user_text=?)) WHERE pl_user=? """, (pl_user, pl_user,)) self.cursor.execute("""/* useractivity LIMIT:300 */ SELECT SQL_NO_CACHE REPLACE(pl_title,"_"," ") AS user_name, pl_title AS user_title, rd_title AS renamed, user_editcount, IFNULL(DATE_FORMAT(user_registration, "%Y-%m-%d"), "") AS user_reg_text, user_registration, ipb_expiry, ipb_reason, user_email_authenticated, mail.up_value AS disablemail, IFNULL(gndr.up_value, '') AS user_gender, COUNT(wl_namespace) AS watchers, SUM(ts_wl_user_touched_cropped>=@ThirtyDays), last_edit, (SELECT TIMESTAMPDIFF(DAY, last_edit, NOW())) AS days_since, (SELECT tl_title FROM templatelinks WHERE tl_namespace=10 AND tl_from=page_id AND tl_title IN ("Retired", "Grounded") ) AS tl_title FROM u_dispenser_p.userlist LEFT JOIN page ON page_namespace=2 AND page_title=pl_title LEFT JOIN redirect ON rd_from=page_id AND rd_namespace=2 LEFT JOIN user ON user_name = pl_user /* for performance we do not use ipb_address */ LEFT JOIN ipblocks ON ipb_user=user_id LEFT JOIN user_properties AS gndr ON gndr.up_user=user_id AND gndr.up_property="gender" LEFT JOIN user_properties AS mail ON mail.up_user=user_id AND mail.up_property="disablemail" LEFT JOIN watchlist ON wl_namespace=2 AND wl_title=pl_title GROUP BY pl_title ORDER BY pl_title """) if action == 0: self.infoTable() else: self.updatePage() def get_last_edit_timestamp(self, user): ''' ''' return cursor.fetchall() def updatePage(self): try: self.page.get() # first call, handles errors! except wikipedia.NoPage as errmsg: wikipedia.output('NoPage error encountered
%s', (errmsg,)) return except wikipedia.IsRedirectPage: target = wikipedia.Page(site, self.page._redirarg) print('#REDIRECT %s' % (target.title(asUrl=True, allowInterwiki=True), wikipedia.escape(target.title().encode('utf-8')),)) return # text = re.sub(r'\[\[([^:]+:([^[\]{|}\n]*?))\|\2\]\](?![^<]*)', r'[[\1|]]', self.page.get()) old_text = text msg_commented = 0 msg_removed = 0 msg_renamed = 0 msg_blocked = 0 for user_name, user_title, user_rd, user_editcount, userreg, user_registration, ipb_expiry, ipb_reason, user_email_authenticated, disablemail, gender, watchers, active_watchers, last_edit, days_since, notes in self.cursor: from dabfix import wikilinkregex p = re.compile(ur'(^(?:[#*;:|].*|)(?:\[\[|\{\{)(?:User|User[ _]talk)[:|] *)(%s)( *(?=[]{|}[]).*)' % wikilinkregex(user_name), re.M | re.I | re.U) n = 0 # List update logic if user_editcount < 32 and user_rd: user_rd = user_rd.replace('_', ' ').decode('utf-8') wikipedia.output(u'Renaming [[User:%s]] → [[User:%s]]'%(user_name.decode('utf-8'), user_rd,)) text, n = p.subn(r'\g<1>%s\g<3>'%user_rd, text) msg_renamed += n elif user_editcount == 1 and days_since > 180: wikipedia.output('Comment out [[User:%s]] single edit account (%d months inactive)'%(user_name.decode('utf-8'), days_since//30)) text, n = p.subn(r'', text) msg_commented += n elif user_editcount == 0: if not last_edit: wikipedia.output(u'Removing [[User:%s]] - No edits, possible [[wp:vanish]]ed'%user_name.decode('utf-8')) text, n = p.subn(r'', text) msg_removed += n else: n = -1 wikipedia.output(u'Bad edit info for [[User:%s]]'%user_name.decode('utf-8')) elif ipb_expiry == "infinity": wikipedia.output(u'[[User:%s]] is indefinitely blocked: \03{lightblue}%s\03{default}'%(user_name.decode('utf-8'), ipb_reason.decode('utf-8'),)) text, n = p.subn(r'', text) msg_blocked += n elif ipb_expiry: wikipedia.output(u'[[User:%s]] is blocked until %s: %s'%(user_name.decode('utf-8'), ipb_expiry, ipb_reason.decode('utf-8'), )) n = -1 elif days_since > self.days: #if min(user_editcount/day_begun, 20) >= days_since * 1.5: #if days_since/user_editcount >= user_editcount/day_begun * 0.20: wikipedia.output('Comment out [[User:%s]] (%d edits, %d months inactive)' % (user_name.decode('utf-8'), user_editcount or -1, days_since and days_since//30, )) text, n = p.subn(last_edit.strftime(r""), text) msg_commented += n else: n = -1 pass if n == 0: wikipedia.output(u"\03{lightred}NOT successful\03{default}") wikipedia.showDiff(old_text, text) wikipedia.setAction(self.summary(parts={ 'remove':msg_removed, 'renaming':msg_renamed, 'comment out':msg_commented, 'blocked': msg_blocked })) self.page.put(text) def summary(self, parts): msg = [] advert = " with [[tools:~dispenser/cgi-bin/useractivity.py|Useractivity]]" wordform = ('user', 'users') for key, value in parts.iteritems(): if key and value: msg.append("%s %s" % (key, wordform[0],) if value==1 else "%s %d %s" % (key, value, wordform[1],)) if len(msg) == 0: return '' elif len(msg) < 3: return ' and '.join(msg).capitalize() + advert else: return (', '.join(msg[:-1]) + ', and '+msg[-1]).capitalize() + advert def infoTable(self): print '' print '' count = 0 for user_name, user_title, user_rd, user_editcount, userreg, user_registration, ipb_expiry, ipb_reason, user_email_authenticated, disablemail, gender, watchers, active_watchers, last_edit, days_since, notes in self.cursor: css = ' style="background:black; color:silver;"' if days_since and self.days and user_editcount and days_since > self.days and days_since/user_editcount >= 7 else ' class="timeline"' count += 1 dbname = self.dbname host = '//%s' % self.domain user_enc = urllib.quote(user_name) ipb_expiry='%s'%(wikipedia.escape(ipb_reason), ipb_expiry,) if ipb_expiry else '' if last_edit: last_active = '%s' % (last_edit.strftime("%Y-%m-%d"), colorValue(days_since, self.days or 1, revert=True), ) else: last_active = '' if user_email_authenticated: mailable = '' if disablemail else '' else: mailable = '' if watchers < 20: watchers = '' if active_watchers < 20: active_watchers = '' print '''%(user_editcount)s %(mailable)s ''' % locals() print '
', ''.join( 'User,Timeline,Registered,Blocks,Stalkers,Active,Gender,Email,Last edit'.split(',') ), '
DisabledYesNo
%(userreg)s %(ipb_expiry)s %(watchers)s %(active_watchers)s %(gender)s%(last_active)s
' print "Displaying %d users" % count if __name__ == "__main__" and wikipedia.handleUrlAndHeader(): try: wikipedia.startContent(form=False, head=r"""""") ua = UserActivity() ua.main() finally: wikipedia.endContent() wikipedia.stopme()