diff --git a/bin/init-category b/bin/init-category new file mode 100755 index 0000000..6a63d95 --- /dev/null +++ b/bin/init-category @@ -0,0 +1,21 @@ +#!/bin/bash + +source $(dirname $0)/vars.sh + +CATEGORY=$1 + +if [ -z "${CATEGORY}" ] ; then + echo 'Usage: bin/init-category ' + exit 1 +fi + +# Populate the initial list +${BIN}/python3 ${DIR}/make-list.py + +# No list should have been populated, but if they were, discard +rm ${DIR}/lists/*.txt + +# Only inform users of files that were nominated after the bot started running. +# Mark all existing files as handled to achieve that. +echo "UPDATE commons_deletions SET state='notified' WHERE deletion_type='${CATEGORY}';" | mysql --defaults-file=${DIR}/my.cnf + diff --git a/commonsbot/formatters.py b/commonsbot/formatters.py index 2beaacf..df5137a 100644 --- a/commonsbot/formatters.py +++ b/commonsbot/formatters.py @@ -138,17 +138,11 @@ def format_body(self, files): return result -class SpeedyFormatter(Formatter): +class PageTagFormatter(Formatter): """ - Formats messages about speedy deletion nominations + Base class for template-based deletion formatters """ - def __init__(self, i18n): - """ - @type i18n: commonsbot.i18n.I18n - """ - Formatter.__init__(self, 'speedy', i18n) - def format_body(self, files): result = self.msg('body-start', len(files)) + '\n' @@ -158,3 +152,27 @@ def format_body(self, files): result += self.msg('body-end', len(files)) return result + + +class SpeedyFormatter(PageTagFormatter): + """ + Formats messages about speedy deletion nominations + """ + + def __init__(self, i18n): + """ + @type i18n: commonsbot.i18n.I18n + """ + Formatter.__init__(self, 'speedy', i18n) + + +class NoPermissionFormatter(PageTagFormatter): + """ + Formats messages about missing permissions + """ + + def __init__(self, i18n): + """ + @type i18n: commonsbot.i18n.I18n + """ + Formatter.__init__(self, 'nopermission', i18n) diff --git a/commonsbot/i18n.py b/commonsbot/i18n.py index c99a203..4c19b13 100644 --- a/commonsbot/i18n.py +++ b/commonsbot/i18n.py @@ -66,6 +66,15 @@ def language_has_all_messages(code): return result +class MessageNotFound(Exception): + """ + Exception thrown when a message is not found + """ + + def __init__(self, lang_code, message_key): + super.__init__("Language %s misses message '%s'" % (lang_code, message_key)) + + class I18n(object): """ Represents a set of localisation messages in a single language @@ -105,6 +114,8 @@ def __init__(self, language): file.close() def msg(self, key, params=()): + if key not in self.data: + raise MessageNotFound(self.language, key) if type(params) != tuple: params = (params,) return format(self.data[key], params) diff --git a/config.json b/config.json index d1a61b3..c63de15 100644 --- a/config.json +++ b/config.json @@ -5,10 +5,21 @@ "minoredit": false, "markasbot": false, "tags": null, - "language": null + "language": null, + "notification_types": [ + "speedy", + "discussion" + ] }, "enwiki": { "markasbot": false + }, + "testwiki": { + "notification_types": [ + "speedy", + "discussion", + "nopermission" + ] } } } diff --git a/i18n/en.json b/i18n/en.json index 7cf2e83..e6b4878 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -8,5 +8,9 @@ "commtech-commons-discussion-body-end-matching": "Participate in the deletion discussion at the [[$1|nomination page]].", "commtech-commons-discussion-body-end-mismatching": "Participate in the deletion {{PLURAL:$1|discussions}} at the nomination {{PLURAL:$1|pages}} linked above.", "commtech-commons-discussion-summary": "Files used on this page are up for deletion", - "commtech-commons-discussion-line": "[[$1]] ([[$2|discussion]])" + "commtech-commons-discussion-line": "[[$1]] ([[$2|discussion]])", + "commtech-commons-nopermission-header": "{{PLURAL:$1|A Commons file|Commons files}} used on this page {{PLURAL:$1|has|have}} is missing permission", + "commtech-commons-nopermission-body-start": "The following Wikimedia Commons {{PLURAL:$1|file|files}} used on this page {{PLURAL:$1|is|are}} missing permission information and may be deleted:", + "commtech-commons-nopermission-body-end": "You can see the details at the file description {{PLURAL:$1|page|pages}} linked above.", + "commtech-commons-nopermission-summary": "Files used on this page are missing permission" } diff --git a/i18n/qqq.json b/i18n/qqq.json index 839c0d3..48a138a 100644 --- a/i18n/qqq.json +++ b/i18n/qqq.json @@ -9,5 +9,9 @@ "commtech-commons-discussion-body-end-matching": "Second part of messages left by Community Tech bot on talk pages of articles that have Commons images nominated for deletion. It's used when all pages listed are nominated in the same discussion and is preceded by a list of files and {{msg-intuition|commtech-commons-discussion-body-start}} before it. Parameter:\n* $1 - title of deletion discussion page on Commons", "commtech-commons-discussion-body-end-mismatching": "Second part of messages left by Community Tech bot on talk pages of articles that have Commons images nominated for deletion. It's used when pages listed are nominated in more than one discussiion and is preceded by a list of files and {{msg-intuition|commtech-commons-discussion-body-start}} before it. Parameter:\n* $1 - number of files nominated for deletion for {{PLURAL}}", "commtech-commons-discussion-summary": "Edit summary for messages left by Community Tech bot on talk pages of articles that have Commons images nominated for deletion", - "commtech-commons-discussion-line": "Line listing a Commons file nominated for deletion. Parameters:\n* $1 - file name\n* $2 - title of deletion discussion page" + "commtech-commons-discussion-line": "Line listing a Commons file nominated for deletion. Parameters:\n* $1 - file name\n* $2 - title of deletion discussion page", + "commtech-commons-nopermission-header": "Header for messages left by Community Tech bot on talk pages of articles that have Commons images missing permission information. Parameter:\n* $1 - number of files nominated for deletion for {{PLURAL}}", + "commtech-commons-nopermission-body-start": "First part of messages left by Community Tech bot on talk pages of articles that have Commons images missing permission information. It will be followed by a list of files and {{msg-intuition|commtech-commons-nopermission-body-end}}. Parameter:\n* $1 - number of files missing permisssion information for {{PLURAL}}", + "commtech-commons-nopermission-body-end": "Second part of messages left by Community Tech bot on talk pages of articles that have Commons images missing permission information. It's preceded by a list of files and {{msg-intuition|commtech-commons-nopermission-body-start}} before it. Parameter:\n* $1 - number of files missing permisssion information for {{PLURAL}}", + "commtech-commons-nopermission-summary": "Edit summary for messages left by Community Tech bot on talk pages of articles that have Commons images missing permission information" } diff --git a/make-list.py b/make-list.py index f912996..37367ba 100644 --- a/make-list.py +++ b/make-list.py @@ -67,3 +67,4 @@ def make_list(type, categories, depth, delay): 'Candidates for speedy deletion', 'Copyright violations', ], depth=False, delay=60 * 15) +make_list('nopermission', ['Media missing permission'], depth=1, delay=60 * 60) diff --git a/post-notifs.py b/post-notifs.py index f7699af..dc2901a 100644 --- a/post-notifs.py +++ b/post-notifs.py @@ -3,9 +3,9 @@ import sys from commonsbot import mysql, config from commonsbot.state import DeletionStateStore, DeletionState -from commonsbot.i18n import I18n, language_has_all_messages +from commonsbot.i18n import I18n, language_has_all_messages, MessageNotFound from commonsbot.utils import PerWikiMapper, check_already_posted -from commonsbot.formatters import SpeedyFormatter, DiscussionFormatter +from commonsbot.formatters import SpeedyFormatter, DiscussionFormatter, NoPermissionFormatter import pywikibot from pywikibot import Site, Page, FilePage from pywikibot.site import Namespace @@ -48,11 +48,15 @@ def spam_notifications(notif_type, formatter_class, talk_page, files): assert len(files) > 0 wiki_options = config.for_wiki(talk_page.site.dbName()) + + if notif_type not in wiki_options['notification_types']: + return + lang_code = wiki_options['language'] if lang_code is None: lang_code = talk_page.site.code - if not language_has_all_messages(lang_code): - return + # if not language_has_all_messages(lang_code): + # return i18n = I18n.factory(lang_code) try: @@ -73,9 +77,13 @@ def spam_notifications(notif_type, formatter_class, talk_page, files): ourlist.sort(key=lambda file: file.file_name) - formatter = formatter_class(i18n) - talk_page.text = text + formatter.format(ourlist) - summary = formatter.format_summary() + try: + formatter = formatter_class(i18n) + talk_page.text = text + formatter.format(ourlist) + summary = formatter.format_summary() + except MessageNotFound as e: + print(str(e), file=sys.stderr) + return if config.dry_run: print('DRY RUN: not posting about %d %s files to %s' % (len(ourlist), notif_type, talk_page)) @@ -177,4 +185,5 @@ def save(store): process_list('discussion', DiscussionFormatter) process_list('speedy', SpeedyFormatter) +process_list('nopermission', NoPermissionFormatter) with_store(lambda store: store.expire_failed()) diff --git a/sql/patch-nopermission.sql b/sql/patch-nopermission.sql new file mode 100644 index 0000000..6ec6b3a --- /dev/null +++ b/sql/patch-nopermission.sql @@ -0,0 +1 @@ +ALTER TABLE commons_deletions MODIFY COLUMN deletion_type ENUM('speedy', 'discussion', 'nopermission'); diff --git a/sql/schema.sql b/sql/schema.sql index 8566b06..2d72248 100644 --- a/sql/schema.sql +++ b/sql/schema.sql @@ -1,6 +1,6 @@ CREATE TABLE IF NOT EXISTS commons_deletions ( title VARCHAR(255) BINARY NOT NULL, - deletion_type ENUM('speedy', 'discussion') NOT NULL, + deletion_type ENUM('speedy', 'discussion', 'nopermission') NOT NULL, state ENUM('new', 'notifying', 'failed', 'notified', 'maybe gone', 'gone') NOT NULL DEFAULT 'new', state_time DATETIME NOT NULL DEFAULT now(), retries INT NOT NULL DEFAULT 0,