Additional IRC commands and bot tasks for EarwigBot https://en.wikipedia.org/wiki/User:EarwigBot
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.
 
 

190 řádky
8.3 KiB

  1. # -*- coding: utf-8 -*-
  2. #
  3. # Copyright (C) 2009-2013 Ben Kurtovic <ben.kurtovic@verizon.net>
  4. #
  5. # Permission is hereby granted, free of charge, to any person obtaining a copy
  6. # of this software and associated documentation files (the "Software"), to deal
  7. # in the Software without restriction, including without limitation the rights
  8. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. # copies of the Software, and to permit persons to whom the Software is
  10. # furnished to do so, subject to the following conditions:
  11. #
  12. # The above copyright notice and this permission notice shall be included in
  13. # all copies or substantial portions of the Software.
  14. #
  15. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  21. # SOFTWARE.
  22. import re
  23. from earwigbot.commands import Command
  24. class AFCStatus(Command):
  25. """Get the number of pending AfC submissions, open redirect requests, and
  26. open file upload requests."""
  27. name = "status"
  28. commands = ["status", "count", "num", "number"]
  29. hooks = ["join", "msg"]
  30. def check(self, data):
  31. if data.is_command and data.command in self.commands:
  32. return True
  33. try:
  34. if data.line[1] == "JOIN" and data.chan == "#wikipedia-en-afc":
  35. if data.nick != self.config.irc["frontend"]["nick"]:
  36. return True
  37. except IndexError:
  38. pass
  39. return False
  40. def process(self, data):
  41. self.site = self.bot.wiki.get_site()
  42. if data.line[1] == "JOIN":
  43. status = " ".join(("\x02Current status:\x0F", self.get_status()))
  44. self.notice(data.nick, status)
  45. return
  46. if data.args:
  47. action = data.args[0].lower()
  48. if action.startswith("sub") or action == "s":
  49. subs = self.count_submissions()
  50. msg = "There are \x0305{0}\x0F pending AfC submissions (\x0302WP:AFC\x0F)."
  51. self.reply(data, msg.format(subs))
  52. elif action.startswith("redir") or action == "r":
  53. redirs = self.count_redirects()
  54. msg = "There are \x0305{0}\x0F open redirect requests (\x0302WP:AFC/R\x0F)."
  55. self.reply(data, msg.format(redirs))
  56. elif action.startswith("file") or action == "f":
  57. files = self.count_redirects()
  58. msg = "There are \x0305{0}\x0F open file upload requests (\x0302WP:FFU\x0F)."
  59. self.reply(data, msg.format(files))
  60. elif action.startswith("agg") or action == "a":
  61. try:
  62. agg_num = int(data.args[1])
  63. except IndexError:
  64. agg_data = (self.count_submissions(),
  65. self.count_redirects(), self.count_files())
  66. agg_num = self.get_aggregate_number(agg_data)
  67. except ValueError:
  68. msg = "\x0303{0}\x0F isn't a number!"
  69. self.reply(data, msg.format(data.args[1]))
  70. return
  71. aggregate = self.get_aggregate(agg_num)
  72. msg = "Aggregate is \x0305{0}\x0F (AfC {1})."
  73. self.reply(data, msg.format(agg_num, aggregate))
  74. elif action.startswith("g13_e") or action.startswith("g13e"):
  75. g13_eli = self.count_g13_eligible()
  76. msg = "There are \x03{0}\x0F CSD:G13 eligible pages."
  77. self.reply(data, msg.format(g13_eli))
  78. elif action.startswith("g13_a") or action.startswith("g13a"):
  79. g13_noms = self.count_g13_active()
  80. msg = "There are \x03{0}\x0F active CSD:G13 nominations."
  81. self.reply(data, msg.format(g13_noms))
  82. elif action.startswith("nocolor") or action == "n":
  83. self.reply(data, self.get_status(color=False))
  84. else:
  85. msg = "Unknown argument: \x0303{0}\x0F. Valid args are " +\
  86. "'subs', 'redirs', 'files', 'agg', 'nocolor', " +\
  87. "'g13_eligible', 'g13_active'."
  88. self.reply(data, msg.format(data.args[0]))
  89. else:
  90. self.reply(data, self.get_status())
  91. def get_status(self, color=True):
  92. subs = self.count_submissions()
  93. redirs = self.count_redirects()
  94. files = self.count_files()
  95. agg_num = self.get_aggregate_number((subs, redirs, files))
  96. aggregate = self.get_aggregate(agg_num)
  97. if color:
  98. msg = "Articles for creation {0} (\x0302AFC\x0F: \x0305{1}\x0F; \x0302AFC/R\x0F: \x0305{2}\x0F; \x0302FFU\x0F: \x0305{3}\x0F)."
  99. else:
  100. msg = "Articles for creation {0} (AFC: {1}; AFC/R: {2}; FFU: {3})."
  101. return msg.format(aggregate, subs, redirs, files)
  102. def count_g13_eligible(self):
  103. """
  104. Returns the number of G13 Eligible AfC Submissions (count of
  105. Category:G13 eligible AfC submissions)
  106. """
  107. return self.site.get_category("G13 eligible AfC submissions").pages
  108. def count_g13_active(self):
  109. """
  110. Returns the number of active CSD:G13 nominations ( count of
  111. Category:Candidates for speedy deletion as abandoned AfC submissions)
  112. """
  113. catname = "Candidates for speedy deletion as abandoned AfC submissions"
  114. return self.site.get_category(catname).pages
  115. def count_submissions(self):
  116. """Returns the number of open AFC submissions (count of CAT:PEND)."""
  117. # Subtract two for [[Wikipedia:Articles for creation/Redirects]] and
  118. # [[Wikipedia:Files for upload]], which aren't real submissions:
  119. return self.site.get_category("Pending AfC submissions").pages - 2
  120. def count_redirects(self):
  121. """Returns the number of open redirect submissions. Calculated as the
  122. total number of submissions minus the closed ones."""
  123. title = "Wikipedia:Articles for creation/Redirects"
  124. content = self.site.get_page(title).get()
  125. total = len(re.findall("^\s*==(.*?)==\s*$", content, re.MULTILINE))
  126. closed = content.lower().count("{{afc-c|b}}")
  127. redirs = total - closed
  128. return redirs
  129. def count_files(self):
  130. """Returns the number of open WP:FFU (Files For Upload) requests.
  131. Calculated as the total number of requests minus the closed ones."""
  132. content = self.site.get_page("Wikipedia:Files for upload").get()
  133. total = len(re.findall("^\s*==(.*?)==\s*$", content, re.MULTILINE))
  134. closed = content.lower().count("{{ifu-c|b}}")
  135. files = total - closed
  136. return files
  137. def get_aggregate(self, num):
  138. """Returns a human-readable AFC status based on the number of pending
  139. AFC submissions, open redirect requests, and open FFU requests. This
  140. does not match {{AFC status}} directly because the algorithm factors in
  141. WP:AFC/R and WP:FFU while the template only looks at the main
  142. submissions. The reasoning is that AFC/R and FFU are still part of
  143. the project, so even if there are no pending submissions, a backlog at
  144. FFU (for example) indicates that our work is *not* done and the
  145. project-wide backlog is most certainly *not* clear."""
  146. if num == 0:
  147. return "is \x02\x0303clear\x0F"
  148. elif num <= 200:
  149. return "is \x0303almost clear\x0F"
  150. elif num <= 400:
  151. return "is \x0312normal\x0F"
  152. elif num <= 600:
  153. return "is \x0307lightly backlogged\x0F"
  154. elif num <= 900:
  155. return "is \x0304backlogged\x0F"
  156. elif num <= 1200:
  157. return "is \x02\x0304heavily backlogged\x0F"
  158. else:
  159. return "is \x02\x1F\x0304severely backlogged\x0F"
  160. def get_aggregate_number(self, (subs, redirs, files)):
  161. """Returns an 'aggregate number' based on the real number of pending
  162. submissions in CAT:PEND (subs), open redirect submissions in WP:AFC/R
  163. (redirs), and open files-for-upload requests in WP:FFU (files)."""
  164. num = subs + (redirs / 2) + (files / 2)
  165. return num