|
@@ -20,6 +20,8 @@ |
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
# SOFTWARE. |
|
|
# SOFTWARE. |
|
|
|
|
|
|
|
|
|
|
|
from datetime import datetime |
|
|
|
|
|
|
|
|
import mwparserfromhell |
|
|
import mwparserfromhell |
|
|
|
|
|
|
|
|
from earwigbot.tasks import Task |
|
|
from earwigbot.tasks import Task |
|
@@ -43,6 +45,13 @@ class AFCUndated(Task): |
|
|
self.aliases = {"submission": ["AFC submission"], "talk": ["WPAFC"]} |
|
|
self.aliases = {"submission": ["AFC submission"], "talk": ["WPAFC"]} |
|
|
|
|
|
|
|
|
def run(self, **kwargs): |
|
|
def run(self, **kwargs): |
|
|
|
|
|
try: |
|
|
|
|
|
self.statistics = self.bot.tasks.get("afc_statistics") |
|
|
|
|
|
except KeyError: |
|
|
|
|
|
err = "Requires afc_statistics task (from earwigbot_plugins)" |
|
|
|
|
|
self.logger.error(err) |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
self.site = self.bot.wiki.get_site() |
|
|
self.site = self.bot.wiki.get_site() |
|
|
category = self.site.get_category(self.category) |
|
|
category = self.site.get_category(self.category) |
|
|
logmsg = u"Undated category [[{0}]] has {1} members" |
|
|
logmsg = u"Undated category [[{0}]] has {1} members" |
|
@@ -51,7 +60,7 @@ class AFCUndated(Task): |
|
|
self.build_aliases() |
|
|
self.build_aliases() |
|
|
counter = 0 |
|
|
counter = 0 |
|
|
for page in category: |
|
|
for page in category: |
|
|
if counter % 10: |
|
|
|
|
|
|
|
|
if not counter % 10: |
|
|
if self.shutoff_enabled(): |
|
|
if self.shutoff_enabled(): |
|
|
return |
|
|
return |
|
|
self.process_page(page) |
|
|
self.process_page(page) |
|
@@ -63,23 +72,37 @@ class AFCUndated(Task): |
|
|
|
|
|
|
|
|
def process_page(self, page): |
|
|
def process_page(self, page): |
|
|
"""Date the necessary templates inside a page object.""" |
|
|
"""Date the necessary templates inside a page object.""" |
|
|
|
|
|
if not page.check_exclusion(): |
|
|
|
|
|
msg = u"Skipping [[{0}]]; bot excluded from editing" |
|
|
|
|
|
self.logger.info(msg.format(page.title)) |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
is_sub = page.namespace in self.namespaces["submission"] |
|
|
is_sub = page.namespace in self.namespaces["submission"] |
|
|
is_talk = page.namespace in self.namespaces["talk"] |
|
|
is_talk = page.namespace in self.namespaces["talk"] |
|
|
if is_sub: |
|
|
if is_sub: |
|
|
aliases = self.aliases["subission"] |
|
|
aliases = self.aliases["subission"] |
|
|
timestamp = self.get_timestamp(page) |
|
|
|
|
|
|
|
|
timestamps = {} |
|
|
elif is_talk: |
|
|
elif is_talk: |
|
|
aliases = self.aliases["talk"] |
|
|
aliases = self.aliases["talk"] |
|
|
timestamp, reviewer = self.get_talkdata(page) |
|
|
timestamp, reviewer = self.get_talkdata(page) |
|
|
else: |
|
|
else: |
|
|
msg = u"[[{0}]] is undated, but in a namespace we don't know how to process" |
|
|
|
|
|
|
|
|
msg = u"[[{0}]] is undated, but in a namespace I don't know how to process" |
|
|
self.logger.warn(msg.format(page.title)) |
|
|
self.logger.warn(msg.format(page.title)) |
|
|
return |
|
|
return |
|
|
|
|
|
if not timestamp: |
|
|
|
|
|
return |
|
|
|
|
|
|
|
|
code = mwparserfromhell.parse(page.get()) |
|
|
code = mwparserfromhell.parse(page.get()) |
|
|
changes = 0 |
|
|
changes = 0 |
|
|
for template in code.filter_templates(): |
|
|
for template in code.filter_templates(): |
|
|
if template.name.matches(aliases) and not template.has("ts"): |
|
|
if template.name.matches(aliases) and not template.has("ts"): |
|
|
|
|
|
if is_sub: |
|
|
|
|
|
status = self.get_status(template) |
|
|
|
|
|
if status in timestamps: |
|
|
|
|
|
timestamp = timestamps[status] |
|
|
|
|
|
else: |
|
|
|
|
|
timestamp = self.get_timestamp(page, status) |
|
|
|
|
|
timestamps[status] = timestamp |
|
|
template.add("ts", timestamp) |
|
|
template.add("ts", timestamp) |
|
|
if is_talk and not template.has("reviewer"): |
|
|
if is_talk and not template.has("reviewer"): |
|
|
template.add("reviewer", reviewer) |
|
|
template.add("reviewer", reviewer) |
|
@@ -93,9 +116,26 @@ class AFCUndated(Task): |
|
|
msg = u"[[{0}]] is undated, but I can't figure out what to replace" |
|
|
msg = u"[[{0}]] is undated, but I can't figure out what to replace" |
|
|
self.logger.warn(msg.format(page.title)) |
|
|
self.logger.warn(msg.format(page.title)) |
|
|
|
|
|
|
|
|
def get_timestamp(self, page): |
|
|
|
|
|
|
|
|
def get_status(self, template): |
|
|
|
|
|
"""Get the status code that corresponds to a given template.""" |
|
|
|
|
|
valid = ["P", "R", "T", "D"] |
|
|
|
|
|
if template.has(1): |
|
|
|
|
|
status = template.get(1).value.strip().upper() |
|
|
|
|
|
if status in valid: |
|
|
|
|
|
return status |
|
|
|
|
|
return "P" |
|
|
|
|
|
|
|
|
|
|
|
def get_timestamp(self, page, chart): |
|
|
"""Get the timestamp associated with a particular submission.""" |
|
|
"""Get the timestamp associated with a particular submission.""" |
|
|
return timestamp |
|
|
|
|
|
|
|
|
log = u"[[{0}]]: Getting timestamp for state {1}" |
|
|
|
|
|
self.logger.debug(log.format(page.title, chart)) |
|
|
|
|
|
search = self.statistics.search_history |
|
|
|
|
|
user, ts, revid = search(page.pageid, chart, chart, []) |
|
|
|
|
|
if not ts: |
|
|
|
|
|
log = u"Couldn't find timestamp in [[{0}]] with state {1}" |
|
|
|
|
|
self.logger.warn(log.format(page.title, chart)) |
|
|
|
|
|
return None |
|
|
|
|
|
return ts.strftime("%Y%m%d%H%M%S") |
|
|
|
|
|
|
|
|
def get_talkdata(self, page): |
|
|
def get_talkdata(self, page): |
|
|
"""Get the timestamp and reviewer associated with a talkpage. |
|
|
"""Get the timestamp and reviewer associated with a talkpage. |
|
@@ -103,4 +143,28 @@ class AFCUndated(Task): |
|
|
This is the mover for a normal article submission, and the uploader for |
|
|
This is the mover for a normal article submission, and the uploader for |
|
|
a file page. |
|
|
a file page. |
|
|
""" |
|
|
""" |
|
|
return timestamp, reviewer |
|
|
|
|
|
|
|
|
subject = page.toggle_talk() |
|
|
|
|
|
if subject.namespace == NS_FILE: |
|
|
|
|
|
return self.get_filedata(subject) |
|
|
|
|
|
self.logger.debug(u"[[{0}]]: Getting talkdata".format(page.title)) |
|
|
|
|
|
chart = self.statistics.CHART_ACCEPT |
|
|
|
|
|
user, ts, revid = self.statistics.get_special(subject.pageid, chart) |
|
|
|
|
|
if not ts: |
|
|
|
|
|
log = u"Couldn't get talkdata for [[{0}]]" |
|
|
|
|
|
self.logger.warn(log.format(page.title)) |
|
|
|
|
|
return None, None |
|
|
|
|
|
return ts.strftime("%Y%m%d%H%M%S"), user |
|
|
|
|
|
|
|
|
|
|
|
def get_filedata(self, page): |
|
|
|
|
|
"""Get the timestamp and reviewer associated with a file talkpage.""" |
|
|
|
|
|
self.logger.debug(u"[[{0}]]: Getting filedata".format(page.title)) |
|
|
|
|
|
result = self.site.api_query(action="query", prop="imageinfo", |
|
|
|
|
|
titles=page.title) |
|
|
|
|
|
data = result["query"]["pages"].values()[0] |
|
|
|
|
|
if "imageinfo" not in data: |
|
|
|
|
|
log = u"Couldn't get filedata for [[{0}]]" |
|
|
|
|
|
self.logger.warn(log.format(page.title)) |
|
|
|
|
|
return None, None |
|
|
|
|
|
info = data["imageinfo"][0] |
|
|
|
|
|
ts = datetime.strptime(info["timestamp", "%Y-%m-%dT%H:%M:%SZ") |
|
|
|
|
|
return ts.strftime("%Y%m%d%H%M%S"), info["user"] |