ویکیپدیا:درخواستهای ربات/بستن پروکسی باز/کتابخانه
این کتابخانه را امیر برای ویکیفا اصلاح و بومی کرده است.این فایل با نام userlib2.py در پوشه pywikipedia کپی گردد. <syntaxhighlight lang="python">
- -*- coding: utf-8 -*-
""" Library to work with users, their pages and talk pages. """
- (C) Pywikipedia bot team, 2008-2010
- Distributed under the terms of the MIT license.
__version__ = '$Id: userlib.py 9657 2011-10-24 06:39:01Z xqt $'
import re import wikipedia as pywikibot import query, config
class AutoblockUser(pywikibot.Error):
""" The class AutoblockUserError is an exception that is raised whenever an action is requested on a virtual autoblock user that's not available for him (i.e. roughly everything except unblock). """
class UserActionRefuse(pywikibot.Error): pass
class BlockError(UserActionRefuse): pass
class AlreadyBlocked(BlockError): pass
class UnblockError(UserActionRefuse): pass
class BlockIDError(UnblockError): pass
class AlreadyUnblocked(UnblockError): pass
- class InvalidUser(pywikibot.InvalidTitle):
- """The mediawiki API does not allow IP lookups."""
- pass
ip_regexp = re.compile(r'^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}' \
r'(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$')
class User(object):
"""A class that represents a Wiki user. """
def __init__(self, site, name): """Initializer for a User object.
Parameters: site - a pywikibot.Site object name - name of the user, without the trailing User: """ if len(name) > 1 and name[0] == u'#': self._isAutoblock = True else: self._isAutoblock = False if self._isAutoblock: # This user is probably being queried for purpose of lifting # an autoblock. pywikibot.output( "This is an autoblock ID, you can only use to unblock it.") if type(site) in [str, unicode]: self._site = pywikibot.getSite(site) else: self._site = site # None means not loaded self._name = name self._blocked = None self._groups = None self._registrationTime = -1 #if self.site().versionnumber() >= 16: # self._urToken = None
def site(self): return self._site
def name(self): return self.username
@property def username(self): return self._name
def isAnonymous(self): return ip_regexp.match(self.username) is not None
def __str__(self): return (u'%s:%s' % (self.site(), self.name())).encode(config.console_encoding, 'replace')
def __repr__(self): return self.__str__()
def _load(self): getall(self.site(), [self], force=True) return
def registrationTime(self, force=False): if not hasattr(self, '_registrationTime') or force: self._load() return self._registrationTime
def editCount(self, force=False): """ Return edit count for this user as int.
@param force: if True, forces reloading the data @type force: bool """ if not hasattr(self, '_editcount') or force: self._load() return self._editcount
def isBlocked(self, force=False): """ Return True if this user is currently blocked, False otherwise.
@param force: if True, forces reloading the data @type force: bool """ if not self._blocked or force: self._load() return self._blocked
def isEmailable(self, force=False): """ Return True if emails can be send to this user through mediawiki, False otherwise.
@param force: if True, forces reloading the data @type force: bool """ if not hasattr(self, '_mailable'): self._load() return self._mailable
def groups(self, force=False): """ Return a list of groups to wich this user belongs. The return value is guaranteed to be a list object, possibly empty.
@param force: if True, forces reloading the data @type force: bool """ if not self._groups or force: self._load() return self._groups
def getUserPage(self, subpage=u): """ Return a pywikibot.Page object corresponding to this user's main page, or a subpage of it if subpage is set.
@param subpage: subpage part to be appended to the main page title (optional) @type subpage: unicode """ if self._isAutoblock: #This user is probably being queried for purpose of lifting #an autoblock, so has no user pages per se. raise AutoblockUser("This is an autoblock ID, you can only use to unblock it.") if subpage: subpage = u'/' + subpage return pywikibot.Page(self.site(), self.name() + subpage, defaultNamespace=2)
def getUserTalkPage(self, subpage=u): """ Return a pywikibot.Page object corresponding to this user's main talk page, or a subpage of it if subpage is set.
@param subpage: subpage part to be appended to the main talk page title (optional) @type subpage: unicode """ if self._isAutoblock: #This user is probably being queried for purpose of lifting #an autoblock, so has no user talk pages per se. raise AutoblockUser("This is an autoblock ID, you can only use to unblock it.") if subpage: subpage = u'/' + subpage return pywikibot.Page(self.site(), self.name() + subpage, defaultNamespace=3)
def sendMail(self, subject=u, text=u, ccMe = False): """ Send an email to this user via mediawiki's email interface. Return True on success, False otherwise. This method can raise an UserActionRefuse exception in case this user doesn't allow sending email to him or the currently logged in bot doesn't have the right to send emails.
@param subject: the subject header of the mail @type subject: unicode @param text: mail body @type text: unicode @param ccme: if True, sends a copy of this email to the bot @type ccme: bool """ if not self.isEmailable(): raise UserActionRefuse('This user is not mailable') if not self.site().isAllowed('sendemail'): raise UserActionRefuse('You don\'t have permission to send mail')
if not self.site().has_api() or self.site().versionnumber() < 14: return self.sendMailOld(subject, text, ccMe)
params = { 'action': 'emailuser', 'target': self.name(), 'token': self.site().getToken(), 'subject': subject, 'text': text, } if ccMe: params['ccme'] = 1 maildata = query.GetData(params, self.site()) if 'error' in maildata: code = maildata['error']['code'] if code == u'usermaildisabled ': pywikibot.output(u'User mail has been disabled') elif 'emailuser' in maildata: if maildata['emailuser']['result'] == u'Success': pywikibot.output(u'Email sent.') return True return False
def sendMailOld(self, subject = u, text = u, ccMe = False): address = self.site().put_address('Special:EmailUser') predata = { "wpSubject" : subject, "wpText" : text, 'wpSend' : "Send", 'wpCCMe' : '0', } if ccMe: predata['wpCCMe'] = '1' predata['wpEditToken'] = self.site().getToken()
response, data = self.site().postForm(address, predata, sysop = False) if data: if 'var wgAction = "success";' in data: pywikibot.output(u'Email sent.') return True else: pywikibot.output(u'Email not sent.') return False else: pywikibot.output(u'No data found.') return False
@pywikibot.deprecated('contributions()') def editedPages(self, limit=500): """ Deprecated function that wraps 'contributions' for backwards compatibility. Yields pywikibot.Page objects that this user has edited, with an upper bound of 'limit'. Pages returned are not guaranteed to be unique.
@param limit: limit result to this number of pages. @type limit: int. """ for item in self.contributions(limit): yield item[0]
def contributions(self, limit=500, namespace=[]): """ Yield tuples describing this user edits with an upper bound of 'limit'. Each tuple is composed of a pywikibot.Page object, the revision id (int), the edit timestamp and the comment (unicode). Pages returned are not guaranteed to be unique.
@param limit: limit result to this number of pages @type limit: int @param namespace: only iterate links in these namespaces @type namespace: list """ if not self.site().has_api(): raise NotImplementedError
params = { 'action': 'query', 'list': 'usercontribs', 'ucuser': self.name(), 'ucprop': ['ids','title','timestamp','comment'],# 'size','flags'], 'uclimit': int(limit), 'ucdir': 'older', } if limit > pywikibot.config.special_page_limit: params['uclimit'] = pywikibot.config.special_page_limit if limit > 5000 and self.site().isAllowed('apihighlimits'): params['uclimit'] = 5000 if namespace: params['ucnamespace'] = namespace # An user is likely to contribute on several pages, # keeping track of titles nbresults = 0 while True: pywikibot.output(u'Retrieving %d user contributions from %s...' % (params['uclimit'], self.site())) result = query.GetData(params, self.site()) if 'error' in result: pywikibot.output('%s' % result) raise pywikibot.Error for contrib in result['query']['usercontribs']: ts = pywikibot.parsetime2stamp(contrib['timestamp']) yield (pywikibot.Page(self.site(), contrib['title'], defaultNamespace=contrib['ns']), contrib['revid'], ts, contrib.get('comment', None) ) nbresults += 1 if nbresults >= limit: break if 'query-continue' in result and nbresults < limit: params['ucstart'] = result['query-continue']['usercontribs']['ucstart'] else: break return
def uploadedImages(self, number=10): """ Yield tuples describing files uploaded by this user. Each tuple is composed of a pywikibot.Page, the timestamp comment (unicode) and a bool (always False...). Pages returned are not guaranteed to be unique.
@param total: limit result to this number of pages @type total: int """ if self.isAnonymous(): raise StopIteration if not self.site().has_api() or self.site().versionnumber() < 11: for c in self._uploadedImagesOld(number): yield c return
for item in self.site().logpages(number, mode='upload', user=self.username, dump=True): yield pywikibot.ImagePage(self.site(), item['title']), item['timestamp'], item['comment'], item['pageid'] > 0 return
def _uploadedImagesOld(self, number = 10): """Yield ImagePages from Special:Log&type=upload"""
regexp = re.compile('<li[^>]*>(?P<date>.+?)\s+<a href=.*?>(?P<user>.+?)</a> .* uploaded "<a href=".*?"(?P<new> class="new")? title="(Image|File):(?P<image>.+?)"\s*>(?:.*?(?P<comment>.*?))?', re.UNICODE)
path = self.site().log_address(number, mode = 'upload', user = self.name())
html = self.site().getUrl(path)
redlink_key = self.site().mediawiki_message('red-link-title')
redlink_tail_len = None
if redlink_key.startswith('$1 '):
redlink_tail_len = len(redlink_key[3:])
for m in regexp.finditer(html):
image = m.group('image')
deleted = False
if m.group('new'):
deleted = True
if redlink_tail_len:
image = image[0:0-redlink_tail_len]
date = m.group('date') comment = m.group('comment') or yield pywikibot.ImagePage(self.site(), image), date, comment, deleted
def block(self, expiry=None, reason=None, anon=True, noCreate=False, onAutoblock=False, banMail=False, watchUser=False, allowUsertalk=True, reBlock=False, hidename=False): """ Block the user by API.
Parameters (from http://en.wikipedia.org/w/api.php) expiry - Expiry time of block, may be a period of time or the block's expiry time If set to 'infinite', 'indefinite' or 'never', the block will never expire. reason - Reason for block anon - Block anonymous users only noCreate - Prevent account creation onAutoblock - Automatically block the last used IP address, and any subsequent IP addresses they try to login from banMail - Prevent user from sending e-mail through the wiki. hidename - Hide the username from the block log. (API only) allowUsertalk - Allow the user to edit their own talk page reBlock - If user is already blocked, overwrite the existing block watchUser - watch the user's user and talk pages (not used with API)
The default values for block options are set to as most unrestrictive """
if self._isAutoblock: #This user is probably being queried for purpose of lifting #an autoblock, so can't be blocked. raise AutoblockUser if self.isBlocked() and not reBlock: raise AlreadyBlocked() if not self.site().isAllowed('block', sysop=True): raise UserActionRefuse('You don\'t have permission to block') if not expiry: expiry = pywikibot.input(u'Please enter the expiry time for the block:') if not reason: reason = pywikibot.input(u'Please enter a reason for the block:')
if not self.site().has_api() or self.site().versionnumber() < 12: return self._blockOld(expiry, reason, anon, noCreate, onAutoblock, banMail, watchUser, allowUsertalk, reBlock) params = { 'action': 'block', 'user': self.name(), 'token': self.site().getToken(self, sysop = True), 'reason': reason, } if expiry: params['expiry'] = expiry if anon: params['anononly'] = 1 if noCreate: params['nocreate'] = 1 if onAutoblock: params['autoblock'] = 1 if banMail: params['noemail'] = 1 if hidename: params['hidename'] = 1 if allowUsertalk: params['allowusertalk'] = 1 if reBlock: params['reblock'] = 1
data = query.GetData(params, self.site(), sysop=True) if 'error' in data: #error occured errCode = data['error']['code'] if errCode == 'alreadyblocked': raise AlreadyBlocked() elif errCode == 'blockedasrange': raise AlreadyBlocked("Range Blocked") #elif errCode == 'invalidrange': # pass
elif errCode == 'invalidip': raise BlockError("IP is not valid I don't why!")
elif errCode == 'invalidexpiry': raise BlockError("Invaild expiry") elif errCode == 'pastexpiry ': raise BlockError("expiry time is the past") elif errCode == 'cantblock-email': raise BlockError("You don't have permission to ban mail")
elif 'block' in data: #success
pywikibot.output(u"HOOOOOOOOOOOOORAAAAAAAAAAA")
return True else: pywikibot.output("Unknown Error, result: %s" % data) raise BlockError raise False
def _blockOld(self, expiry, reason, anonOnly, noSignup, enableAutoblock, emailBan, watchUser, allowUsertalk): """ Internal use to block the user by web page. Don't use this function directly.
"""
token = self.site().getToken(self, sysop = True) pywikibot.output(u"Blocking User:%s..." % self.name()) boolStr = ['0','1'] predata = { 'wpBlockAddress': self.name(), 'wpBlockOther': expiry, 'wpBlockReasonList': reason, 'wpAnonOnly': boolStr[anonOnly], 'wpCreateAccount': boolStr[noSignup], 'wpEnableAutoblock': boolStr[enableAutoblock], 'wpEmailBan': boolStr[emailBan], 'wpWatchUser': boolStr[watchUser], 'wpAllowUsertalk': boolStr[allowUsertalk], 'wpBlock': 'Block this user', 'wpEditToken': token } address = self.site().block_address()
response, data = self.site().postForm(address, predata, sysop = True) if data: if self.site().mediawiki_message('ipb_already_blocked').replace('$1', self.name()) in data: raise AlreadyBlockedError
raise BlockError return True
def unblock(self, reason=None): """ Unblock the user.
Parameter: reason - reason for block """
if self.name()[0] == '#': blockID = self.name()[1:] else: blockID = self._getBlockID() self._unblock(blockID,reason)
def _getBlockID(self): pywikibot.output(u"Getting block id for User:%s..." % self.name()) address = u"http://fa.wikipedia.org/wiki/%D9%88%DB%8C%DA%98%D9%87:%D8%A8%D8%B3%D8%AA%D9%86_%D9%86%D8%B4%D8%A7%D9%86%DB%8C_%D8%A2%DB%8C%E2%80%8C%D9%BE%DB%8C/"+self.name() data = self.site().getUrl(address) bIDre = re.search(r'action=unblock&id=(\d+)', data) if not bIDre: pywikibot.output(data) raise BlockIDError return bIDre.group(1)
def _unblock(self, blockID, reason): pywikibot.output(u"Unblocking User:%s..." % self.name()) token = self.site().getToken(self, sysop = True) predata = { 'id': blockID, 'wpUnblockReason': reason, 'wpBlock': 'Unblock this address', 'wpEditToken': token, } address = self.site().unblock_address() response, data = self.site().postForm(address, predata, sysop = True) if response.code != 302: if self.site().mediawiki_message('ipb_cant_unblock').replace('$1',blockID) in data: raise AlreadyUnblockedError raise UnblockError, data return True
def getall(site, users, throttle=True, force=False):
"""Bulk-retrieve users data from site
Arguments: site = Site object users = iterable that yields User objects
""" users = list(users) # if pages is an iterator, we need to make it a list if len(users) > 1: pywikibot.output(u'Getting %d users data from %s...' % (len(users), site))
if len(users) > 250: # max load prevents HTTPError 400 for urg in range(0, len(users), 250): if urg == range(0, len(users), 250)[-1]: #latest k = users[urg:] _GetAllUI(site, k, throttle, force).run() users[urg:] = k else: k = users[urg:urg + 250] _GetAllUI(site, k, throttle, force).run() users[urg:urg + 250] = k else: _GetAllUI(site, users, throttle, force).run()
class _GetAllUI(object):
def __init__(self, site, users, throttle, force): self.site = site self.users = [] self.throttle = throttle self.force = force self.sleeptime = 15 for user in users: if not hasattr(user, '_editcount') or force: self.users.append(user) elif pywikibot.verbose: pywikibot.output(u"BUGWARNING: %s already done!" % user.name())
def run(self): if self.users: while True: try: data = self.getData() except Exception, e: # Print the traceback of the caught exception print e raise else: break for uj in self.users: try: x = data[uj.name()] except KeyError: break #uj._editcount = x['editcount'] if 'groups' in x: uj._groups = x['groups'] else: uj._groups = [] #if x['registration']: # uj._registrationTime = pywikibot.parsetime2stamp(x['registration']) #else: # uj._registrationTime = 0 uj._mailable = ("emailable" in x) uj._blocked = ('blockedby' in x)
print uj
#if self._blocked: #Get block ID
def getData(self): users = {} params = { 'action': 'query', 'list': 'users', 'usprop': ['blockinfo', 'groups', 'editcount', 'registration', 'emailable', 'gender'], 'ususers': u'|'.join([n.name() for n in self.users]), } data = query.GetData(params, self.site) for user in data['query']['users']: #if u'invalid' in user: # raise InvalidUser("User name '%s' is invalid. IP addresses are not supported." % user['name']) users[user['name']] = user return users
if __name__ == '__main__':
""" Simple testing code for the User:Example on the English pywikibot. """ pywikibot.output(""" This module is not for direct usage from the command prompt. In code, the usage is as follows:
>>> exampleUser = User("en", 'Example') >>> pywikibot.output(exampleUser.getUserPage().get()) >>> pywikibot.output(exampleUser.getUserPage('Lipsum').get()) >>> pywikibot.output(exampleUser.getUserTalkPage().get()) """) # unit tests import tests.test_userlib import unittest unittest.main(tests.test_userlib)