A Python robot that edits Wikipedia and interacts with people over IRC https://en.wikipedia.org/wiki/User:EarwigBot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

afc_status.py 6.5 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. # -*- coding: utf-8 -*-
  2. import re
  3. from classes import BaseCommand
  4. import config
  5. import wiki
  6. class Command(BaseCommand):
  7. """Get the number of pending AfC submissions, open redirect requests, and
  8. open file upload requests."""
  9. name = "status"
  10. hooks = ["join", "msg"]
  11. def check(self, data):
  12. commands = ["status", "count", "num", "number"]
  13. if data.is_command and data.command in commands:
  14. return True
  15. try:
  16. if data.line[1] == "JOIN" and data.chan == "#wikipedia-en-afc":
  17. if data.nick != config.irc["frontend"]["nick"]:
  18. return True
  19. except IndexError:
  20. pass
  21. return False
  22. def process(self, data):
  23. self.site = wiki.get_site()
  24. self.site._maxlag = None
  25. if data.line[1] == "JOIN":
  26. notice = self.get_join_notice()
  27. self.connection.notice(data.nick, notice)
  28. return
  29. if data.args:
  30. action = data.args[0].lower()
  31. if action.startswith("sub") or action == "s":
  32. subs = self.count_submissions()
  33. msg = "there are currently {0} pending AfC submissions."
  34. self.connection.reply(data, msg.format(subs))
  35. elif action.startswith("redir") or action == "r":
  36. redirs = self.count_redirects()
  37. msg = "there are currently {0} open redirect requests."
  38. self.connection.reply(data, msg.format(redirs))
  39. elif action.startswith("file") or action == "f":
  40. files = self.count_redirects()
  41. msg = "there are currently {0} open file upload requests."
  42. self.connection.reply(data, msg.format(files))
  43. elif action.startswith("agg") or action == "a":
  44. try:
  45. agg_num = int(data.args[1])
  46. except IndexError:
  47. agg_data = (self.count_submissions(),
  48. self.count_redirects(), self.count_files())
  49. agg_num = self.get_aggregate_number(agg_data)
  50. except ValueError:
  51. msg = "\x0303{0}\x0301 isn't a number!"
  52. self.connection.reply(data, msg.format(data.args[1]))
  53. return
  54. aggregate = self.get_aggregate(agg_num)
  55. msg = "aggregate is currently {0} (AfC {1})."
  56. self.connection.reply(data, msg.format(agg_num, aggregate))
  57. elif action.startswith("join") or action == "j":
  58. notice = self.get_join_notice()
  59. self.connection.reply(data, notice)
  60. else:
  61. msg = "unknown argument: \x0303{0}\x0301. Valid args are 'subs', 'redirs', 'files', 'agg', and 'join'."
  62. self.connection.reply(data, msg.format(data.args[0]))
  63. else:
  64. subs = self.count_submissions()
  65. redirs = self.count_redirects()
  66. files = self.count_files()
  67. msg = "there are currently {0} pending submissions, {1} open redirect requests, and {2} open file upload requests."
  68. self.connection.reply(data, msg.format(subs, redirs, files))
  69. def get_join_notice(self):
  70. subs = self.count_submissions()
  71. redirs = self.count_redirects()
  72. files = self.count_files()
  73. agg_num = self.get_aggregate_number((subs, redirs, files))
  74. aggregate = self.get_aggregate(agg_num)
  75. msg = "\x02Current status:\x0F Articles for Creation {0} (\x0302AFC\x0301: \x0305{1}\x0301; \x0302AFC/R\x0301: \x0305{2}\x0301; \x0302FFU\x0301: \x0305{3}\x0301)"
  76. return msg.format(aggregate, subs, redirs, files)
  77. def count_submissions(self):
  78. """Returns the number of open AFC submissions (count of CAT:PEND)."""
  79. cat = self.site.get_category("Pending AfC submissions")
  80. subs = len(cat.members(limit=500))
  81. # Remove [[Wikipedia:Articles for creation/Redirects]] and
  82. # [[Wikipedia:Files for upload]], which aren't real submissions:
  83. subs -= 2
  84. return subs
  85. def count_redirects(self):
  86. """Returns the number of open redirect submissions. Calculated as the
  87. total number of submissions minus the closed ones."""
  88. title = "Wikipedia:Articles for creation/Redirects"
  89. content = self.site.get_page(title).get()
  90. total = len(re.findall("^\s*==(.*?)==\s*$", content, re.MULTILINE))
  91. closed = content.lower().count("{{afc-c|b}}")
  92. redirs = total - closed
  93. return redirs
  94. def count_files(self):
  95. """Returns the number of open WP:FFU (Files For Upload) requests.
  96. Calculated as the total number of requests minus the closed ones."""
  97. content = self.site.get_page("Wikipedia:Files for upload").get()
  98. total = len(re.findall("^\s*==(.*?)==\s*$", content, re.MULTILINE))
  99. closed = content.lower().count("{{ifu-c|b}}")
  100. files = total - closed
  101. return files
  102. def get_aggregate(self, num):
  103. """Returns a human-readable AFC status based on the number of pending
  104. AFC submissions, open redirect requests, and open FFU requests. This
  105. does not match {{AFC status}} directly because my algorithm factors in
  106. WP:AFC/R and WP:FFU while the template only looks at the main
  107. submissions. My reasoning is that AFC/R and FFU are still part of
  108. the project, so even if there are no pending submissions, a backlog at
  109. FFU (for example) indicates that our work is *not* done and the
  110. project-wide backlog is most certainly *not* clear."""
  111. if num == 0:
  112. return "is \x02\x0303clear\x0301\x0F"
  113. elif num < 125: # < 25 subs
  114. return "is \x0303almost clear\x0301"
  115. elif num < 200: # < 40 subs
  116. return "is \x0312normal\x0301"
  117. elif num < 275: # < 55 subs
  118. return "is \x0307lightly backlogged\x0301"
  119. elif num < 350: # < 70 subs
  120. return "is \x0304backlogged\x0301"
  121. elif num < 500: # < 100 subs
  122. return "is \x02\x0304heavily backlogged\x0301\x0F"
  123. else: # >= 100 subs
  124. return "is \x02\x1F\x0304severely backlogged\x0301\x0F"
  125. def get_aggregate_number(self, (subs, redirs, files)):
  126. """Returns an 'aggregate number' based on the real number of pending
  127. submissions in CAT:PEND (subs), open redirect submissions in WP:AFC/R
  128. (redirs), and open files-for-upload requests in WP:FFU (files)."""
  129. num = (subs * 5) + (redirs * 2) + (files * 2)
  130. return num