A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

user.py 8.4 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. # -*- coding: utf-8 -*-
  2. from time import strptime
  3. from wiki.tools.constants import *
  4. from wiki.tools.exceptions import UserNotFoundError
  5. from wiki.tools.page import Page
  6. class User(object):
  7. """
  8. EarwigBot's Wiki Toolset: User Class
  9. Represents a User on a given Site. Has methods for getting a bunch of
  10. information about the user, such as editcount and user rights, methods for
  11. returning the user's userpage and talkpage, etc.
  12. Public methods:
  13. name -- returns the user's username
  14. exists -- returns True if the user exists, False if they do not
  15. userid -- returns an integer ID representing the user
  16. blockinfo -- returns information about a current block on the user
  17. groups -- returns a list of the user's groups
  18. rights -- returns a list of the user's rights
  19. editcount -- returns the number of edits made by the user
  20. registration -- returns the time the user registered as a time.struct_time
  21. emailable -- returns True if you can email the user, False if you cannot
  22. gender -- returns the user's gender ("male", "female", or "unknown")
  23. get_userpage -- returns a Page object representing the user's userpage
  24. get_talkpage -- returns a Page object representing the user's talkpage
  25. """
  26. def __init__(self, site, name):
  27. """Constructor for new User instances.
  28. Takes two arguments, a Site object (necessary for doing API queries),
  29. and the name of the user, preferably without "User:" in front, although
  30. this prefix will be automatically removed by the API if given.
  31. You can also use site.get_user() instead, which returns a User object,
  32. and is preferred.
  33. We won't do any API queries yet for basic information about the user -
  34. save that for when the information is requested.
  35. """
  36. self._site = site
  37. self._name = name
  38. def _get_attribute(self, attr, force):
  39. """Internally used to get an attribute by name.
  40. We'll call _load_attributes() to get this (and all other attributes)
  41. from the API if it is not already defined. If `force` is True, we'll
  42. re-load them even if they've already been loaded.
  43. Raises UserNotFoundError if a nonexistant user prevents us from
  44. returning a certain attribute.
  45. """
  46. if not hasattr(self, attr) or force:
  47. self._load_attributes()
  48. if self._exists is False:
  49. e = "User '{0}' does not exist.".format(self._name)
  50. raise UserNotFoundError(e)
  51. return getattr(self, attr)
  52. def _load_attributes(self):
  53. """Internally used to load all attributes from the API.
  54. Normally, this is called by _get_attribute() when a requested attribute
  55. is not defined. This defines it.
  56. """
  57. params = {"action": "query", "list": "users", "ususers": self._name,
  58. "usprop": "blockinfo|groups|rights|editcount|registration|emailable|gender"}
  59. result = self._site.api_query(params)
  60. res = result["query"]["users"][0]
  61. # normalize our username in case it was entered oddly
  62. self._name = res["name"]
  63. try:
  64. self._userid = res["userid"]
  65. except KeyError: # userid is missing, so user does not exist
  66. self._exists = False
  67. return
  68. self._exists = True
  69. try:
  70. self._blockinfo = {
  71. "by": res["blockedby"],
  72. "reason": res["blockreason"],
  73. "expiry": res["blockexpiry"]
  74. }
  75. except KeyError:
  76. self._blockinfo = False
  77. self._groups = res["groups"]
  78. self._rights = res["rights"].values()
  79. self._editcount = res["editcount"]
  80. reg = res["registration"]
  81. self._registration = strptime(reg, "%Y-%m-%dT%H:%M:%SZ")
  82. try:
  83. res["emailable"]
  84. except KeyError:
  85. self._emailable = False
  86. else:
  87. self._emailable = True
  88. self._gender = res["gender"]
  89. def name(self, force=False):
  90. """Returns the user's name.
  91. If `force` is True, we will load the name from the API and return that.
  92. This could potentially return a "normalized" version of the name - for
  93. example, without a "User:" prefix or without underscores. Unlike other
  94. attribute getters, this will never make an API query without `force`.
  95. Note that if another attribute getter, like exists(), has already been
  96. called, then the username has already been normalized.
  97. """
  98. if force:
  99. self._load_attributes()
  100. return self._name
  101. def exists(self, force=False):
  102. """Returns True if the user exists, or False if they do not.
  103. Makes an API query if `force` is True or if we haven't made one
  104. already.
  105. """
  106. if self._exists is None or force:
  107. self._load_attributes()
  108. return self._exists
  109. def userid(self, force=False):
  110. """Returns an integer ID used by MediaWiki to represent the user.
  111. Raises UserNotFoundError if the user does not exist. Makes an API query
  112. if `force` is True or if we haven't made one already.
  113. """
  114. return self._get_attribute("_userid", force)
  115. def blockinfo(self, force=False):
  116. """Returns information about a current block on the user.
  117. If the user is not blocked, returns False. If they are, returns a dict
  118. with three keys: "by" is the blocker's username, "reason" is the reason
  119. why they were blocked, and "expiry" is when the block expires.
  120. Raises UserNotFoundError if the user does not exist. Makes an API query
  121. if `force` is True or if we haven't made one already.
  122. """
  123. return self._get_attribute("_blockinfo", force)
  124. def groups(self, force=False):
  125. """Returns a list of groups this user is in, including "*".
  126. Raises UserNotFoundError if the user does not exist. Makes an API query
  127. if `force` is True or if we haven't made one already.
  128. """
  129. return self._get_attribute("_groups", force)
  130. def rights(self, force=False):
  131. """Returns a list of this user's rights.
  132. Raises UserNotFoundError if the user does not exist. Makes an API query
  133. if `force` is True or if we haven't made one already.
  134. """
  135. return self._get_attribute("_rights", force)
  136. def editcount(self, force=False):
  137. """Returns the number of edits made by the user.
  138. Raises UserNotFoundError if the user does not exist. Makes an API query
  139. if `force` is True or if we haven't made one already.
  140. """
  141. return self._get_attribute("_editcount", force)
  142. def registration(self, force=False):
  143. """Returns the time the user registered as a time.struct_time object.
  144. Raises UserNotFoundError if the user does not exist. Makes an API query
  145. if `force` is True or if we haven't made one already.
  146. """
  147. return self._get_attribute("_registration", force)
  148. def emailable(self, force=False):
  149. """Returns True if the user can be emailed, or False if they cannot.
  150. Raises UserNotFoundError if the user does not exist. Makes an API query
  151. if `force` is True or if we haven't made one already.
  152. """
  153. return self._get_attribute("_emailable", force)
  154. def gender(self, force=False):
  155. """Returns the user's gender.
  156. Can return either "male", "female", or "unknown", if they did not
  157. specify it.
  158. Raises UserNotFoundError if the user does not exist. Makes an API query
  159. if `force` is True or if we haven't made one already.
  160. """
  161. return self._get_attribute("_gender", force)
  162. def get_userpage(self):
  163. """Returns a Page object representing the user's userpage.
  164. No checks are made to see if it exists or not. Proper site namespace
  165. conventions are followed.
  166. """
  167. prefix = self._site.namespace_id_to_name(NS_USER)
  168. pagename = ''.join((prefix, ":", self._name))
  169. return Page(self._site, pagename)
  170. def get_talkpage(self):
  171. """Returns a Page object representing the user's talkpage.
  172. No checks are made to see if it exists or not. Proper site namespace
  173. conventions are followed.
  174. """
  175. prefix = self._site.namespace_id_to_name(NS_USER_TALK)
  176. pagename = ''.join((prefix, ":", self._name))
  177. return Page(self._site, pagename)