jenkins-bot has submitted this change and it was merged.

Change subject: Make protect.py more wiki-agnostic
......................................................................


Make protect.py more wiki-agnostic

- Removed most harcoded protection level and types
- Applies protection levels only if the make sense depending on
  Page.applicable_protections().

- The ProtectionRobot class extends pywikibot.Bot
    - 'protections' dict replaces 'edit', 'move' and 'create'
    - the 'always' switch is now a standard option

- Clarified "-unprotect" option and added "-default[:<level>]"
    If a protection type (e.g. "edit") is not defined, it
    chooses by default "sysop". "-default" overwrites this and
    "-unprotect" acts like "-default:none". Only "-default"
    will change only the explicitily set protection types.

- Fixed in Page.protect() that prompt only defaults to True if
  protections was None ("deprecated mode")

Bug: 55057 - implicitly enable the 'upload'-type protection
Change-Id: I41146fa0c161a242834ab0b1fe2954c7b89d7fd1
---
M pywikibot/page.py
M scripts/protect.py
2 files changed, 152 insertions(+), 109 deletions(-)

Approvals:
  John Vandenberg: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/pywikibot/page.py b/pywikibot/page.py
index 969d02b..7108a2b 100644
--- a/pywikibot/page.py
+++ b/pywikibot/page.py
@@ -1583,7 +1583,7 @@
 
     @deprecate_arg("throttle", None)
     def protect(self, edit=False, move=False, create=None, upload=None,
-                unprotect=False, reason=None, prompt=True, protections=None,
+                unprotect=False, reason=None, prompt=None, protections=None,
                 **kwargs):
         """(Un)protect a wiki page. Requires administrator status.
 
@@ -1596,7 +1596,8 @@
         @type  protections: dict
         @param reason: Reason for the action
         @type  reason: basestring
-        @param prompt: Whether to ask user for confirmation
+        @param prompt: Whether to ask user for confirmation (deprecated).
+                       Defaults to protections is None
         @type  prompt: bool
         """
         def deprecated(value, arg_name):
@@ -1637,6 +1638,8 @@
             protections = dict(
                 [(p_type, "") for p_type in self.applicable_protections()])
         answer = 'y'
+        if called_using_deprecated_arg and prompt is None:
+            prompt = True
         if prompt:
             pywikibot.bot.warning(u'"prompt" argument of protect() is '
                                   'deprecated')
diff --git a/scripts/protect.py b/scripts/protect.py
index d7a55b1..256d76b 100644
--- a/scripts/protect.py
+++ b/scripts/protect.py
@@ -1,41 +1,43 @@
 # -*- coding: utf-8 -*-
 """
 This script can be used to protect and unprotect pages en masse.
+
 Of course, you will need an admin account on the relevant wiki.
-
-
 These command line parameters can be used to specify which pages to work on:
 
 &params;
 
 Furthermore, the following command line parameters are supported:
 
--always:          Don't prompt to protect pages, just do it.
+-always           Don't prompt to protect pages, just do it.
 
--summary:         Supply a custom edit summary.
+-summary:         Supply a custom edit summary. Tries to generate summary from
+                  the page selector. If no summary is supplied or couldn't
+                  determine one from the selector it'll ask for one.
 
--unprotect:       Actually unprotect pages instead of protecting
+-unprotect        Acts like "default:none"
 
--edit:PROTECTION_LEVEL Set edit protection level to PROTECTION_LEVEL
+-default:         Sets the default protection level (default 'sysop'). If no
+                  level is defined it doesn't change unspecified levels.
 
--move:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL
+-[type]:[level]   Set [type] protection level to [level]
 
-## Without support ##
-## -create:PROTECTION_LEVEL Set move protection level to PROTECTION_LEVEL ##
+Usual values for [level] are: sysop, autoconfirmed, none; further levels may be
+provided by some wikis.
 
-Values for PROTECTION_LEVEL are: sysop, autoconfirmed, none.
-If an operation parameter (edit, move or create) is not specified, default
-protection level is 'sysop' (or 'none' if -unprotect).
+For all protection types (edit, move, etc.) it chooses the default protection
+level. This is "sysop" or "none" if -unprotect was selected. If multiple
+-unprotect or -default are used, only the last occurence is applied.
 
 Usage: python protect.py <OPTIONS>
 
 Examples:
 
-Protect everything in the category "To protect" prompting.
-    python protect.py -cat:"To protect" -always
+Protect everything in the category 'To protect' prompting.
+    python protect.py -cat:'To protect'
 
-Unprotect all pages listed in text file "unprotect.txt" without prompting.
-    python protect.py -file:unprotect.txt -unprotect
+Unprotect all pages listed in text file 'unprotect.txt' without prompting.
+    python protect.py -file:unprotect.txt -unprotect -always
 """
 
 #
@@ -50,8 +52,7 @@
 #
 
 import pywikibot
-from pywikibot import i18n
-from pywikibot import pagegenerators
+from pywikibot import i18n, pagegenerators, Bot
 
 # This is required for the text that is shown when you run this script
 # with the parameter -help.
@@ -60,141 +61,180 @@
 }
 
 
-class ProtectionRobot:
+class ProtectionRobot(Bot):
+
     """ This bot allows protection of pages en masse. """
 
-    def __init__(self, generator, summary, always=False, unprotect=False,
-                 edit='sysop', move='sysop', create='sysop'):
+    def __init__(self, generator, protections, **kwargs):
         """
-        Arguments:
-            * generator - A page generator.
-            * always - Protect without prompting?
-            * edit, move, create - protection level for these operations
-            * unprotect - unprotect pages (and ignore edit, move, create 
params)
+        Create a new ProtectionRobot.
 
+        @param generator: the page generator
+        @type generator: generator
+        @param protections: protections as a dict with "type": "level"
+        @type protections: dict
+        @param kwargs: additional arguments directly feed to Bot.__init__()
         """
+        self.availableOptions.update({
+            'summary': None,
+        })
+        super(ProtectionRobot, self).__init__(**kwargs)
         self.generator = generator
-        self.summary = summary
-        self.prompt = not always
-        self.unprotect = unprotect
-        self.edit = edit
-        self.move = move
+        self.protections = protections
 
     def run(self):
-        """ Start the bot's action.
-        Loop through everything in the page generator and (un)protect it.
+        """Start the bot's action.
 
+        Loop through everything in the page generator and apply the
+        protections.
         """
         for page in self.generator:
             pywikibot.output(u'Processing page %s' % page.title())
-            page.protect(unprotect=self.unprotect, reason=self.summary,
-                         prompt=self.prompt, edit=self.edit, move=self.move)
+            if not self.getOption('always'):
+                choice = pywikibot.inputChoice(
+                    u'Do you want to change the protection level of %s?'
+                    % page.title(asLink=True, forceInterwiki=True),
+                    ['yes', 'No', 'all'],
+                    ['y', 'N', 'a'],
+                    'n')
+                if choice == 'n':
+                    continue
+                elif choice == 'a':
+                    self.option['always'] = True
+            applicable = page.applicable_protections()
+            protections = dict(
+                [prot for prot in self.protections if prot[0] in applicable])
+            page.protect(reason=self.getOption('summary'),
+                         protections=protections)
 
 
-def choiceProtectionLevel(operation, default, protectionLevels):
-    """ Asks a valid protection level for "operation".
-    Returns the protection level chosen by user.
+def check_protection_level(operation, level, levels, default=None):
+    """Check if the protection level is valid or asks if necessary.
 
+    @return a valid protection level
+    @rtype string
     """
-    default = default[0]
-    firstChar = map(lambda level: level[0], protectionLevels)
-    choiceChar = pywikibot.inputChoice('Choice a protection level to %s:'
-                                       % operation,
-                                       protectionLevels, firstChar,
-                                       default=default)
-    for level in protectionLevels:
-        if level.startswith(choiceChar):
-            return level
+    if level not in levels:
+        first_char = []
+        default_char = None
+        num = 1
+        for level in levels:
+            for c in level:
+                if c not in first_char:
+                    first_char.append(c)
+                    break
+            else:
+                first_char.append(unicode(num))
+                num += 1
+            if level == default:
+                default_char = first_char[-1]
+        choice = pywikibot.inputChoice('Choice a protection level to %s:'
+                                       % operation, levels, first_char,
+                                       default=default_char)
+
+        return levels[first_char.index(choice)]
+    else:
+        return level
 
 
 def main(*args):
-    protectionLevels = ['sysop', 'autoconfirmed', 'none']
-
-    # This factory is responsible for processing command line arguments
-    # that are also used by other scripts and that determine on which pages
-    # to work on.
-    pageName = ''
-    summary = None
-    always = False
+    options = {}
+    message_properties = {}
     generator = None
-    edit = ''
-    move = ''
-    defaultProtection = 'sysop'
+    protections = {}
+    default_level = 'sysop'
+    default_summaries = {
+        'cat': 'category',
+        'links': 'links',
+        'ref': 'ref',
+        'imageused': 'images',
+        'file': 'simple',
+    }
 
     # read command line parameters
     local_args = pywikibot.handleArgs(*args)
     genFactory = pagegenerators.GeneratorFactory()
-    mysite = pywikibot.Site()
+    site = pywikibot.Site()
 
+    protection_levels = set(site.protection_levels())
+    protection_types = site.protection_types()
+    if '' in protection_levels:
+        protection_levels.remove('')
+        protection_levels.add('none')
     for arg in local_args:
         if arg == '-always':
-            always = True
+            options['always'] = True
         elif arg.startswith('-summary'):
             if len(arg) == len('-summary'):
-                summary = pywikibot.input(u'Enter a reason for the 
protection:')
+                # fill dummy value to prevent automatic generation
+                options['summary'] = None
             else:
-                summary = arg[len('-summary:'):]
+                options['summary'] = arg[len('-summary:'):]
         elif arg.startswith('-images'):
             pywikibot.output('\n\03{lightred}-image option is deprecated. '
                              'Please use -imagelinks instead.\03{default}\n')
             local_args.append('-imagelinks' + arg[7:])
         elif arg.startswith('-unprotect'):
-            defaultProtection = 'none'
-        elif arg.startswith('-edit'):
-            edit = arg[len('-edit:'):]
-            if edit not in protectionLevels:
-                edit = choiceProtectionLevel(
-                    'edit', defaultProtection, protectionLevels)
-        elif arg.startswith('-move'):
-            move = arg[len('-move:'):]
-            if move not in protectionLevels:
-                move = choiceProtectionLevel(
-                    'move', defaultProtection, protectionLevels)
-        elif arg.startswith('-create'):
-            create = arg[len('-create:'):]
-            if create not in protectionLevels:
-                create = choiceProtectionLevel(
-                    'create', defaultProtection, protectionLevels)
+            default_level = 'none'
+        elif arg.startswith('-default'):
+            if len(arg) == len('-default'):
+                default_level = None
+            else:
+                default_level = arg[len('-default:'):]
         else:
-            genFactory.handleArg(arg)
-            found = arg.find(':') + 1
-            if found:
-                pageName = arg[found:]
+            is_p_type = False
+            if arg.startswith('-'):
+                delimiter = arg.find(':')
+                if delimiter > 0:
+                    p_type = arg[1:delimiter]
+                    level = arg[delimiter + 1:]
+                    if p_type in protection_types:
+                        protections[p_type] = level
+                        is_p_type = True
+            if not is_p_type:
+                if not genFactory.handleArg(arg):
+                    raise ValueError('Unknown parameter "{}"'.format(arg))
+                found = arg.find(':') + 1
+                if found:
+                    message_properties.update({'cat': arg[found:],
+                                               'page': arg[found:]})
 
-        if not summary:
-            if pageName:
-                if arg.startswith('cat') or arg.startswith('subcats'):
-                    summary = i18n.twtranslate(mysite, 'protect-category',
-                                               {'cat': pageName})
-                elif arg.startswith('links'):
-                    summary = i18n.twtranslate(mysite, 'protect-links',
-                                               {'page': pageName})
-                elif arg.startswith('ref'):
-                    summary = i18n.twtranslate(mysite, 'protect-ref',
-                                               {'page': pageName})
-                elif arg.startswith('imageused'):
-                    summary = i18n.twtranslate(mysite, 'protect-images',
-                                               {'page': pageName})
-            elif arg.startswith('file'):
-                summary = i18n.twtranslate(mysite, 'protect-simple')
+                if 'summary' not in options:
+                    generator_type = arg[1:found] if found > 0 else arg[1:]
+                    if generator_type in default_summaries:
+                        message_type = default_summaries[generator_type]
+                        if message_type == 'simple' or message_properties:
+                            options['summary'] = i18n.twtranslate(
+                                site, 'protect-{}'.format(message_type),
+                                message_properties)
 
     generator = genFactory.getCombinedGenerator()
     # We are just protecting pages, so we have no need of using a preloading
     # page generator to actually get the text of those pages.
     if generator:
-        if summary is None:
-            summary = pywikibot.input(u'Enter a reason for the %sprotection:'
-                                      % ['', 'un'][protectionLevels == 'none'])
-        if not edit:
-            edit = defaultProtection
-        if not move:
-            move = defaultProtection
-        bot = ProtectionRobot(generator, summary, always, edit=edit, move=move)
+        if default_level:
+            default_level = check_protection_level('Default level',
+                                                   default_level,
+                                                   protection_levels)
+        # set the default value for all
+        # None (not the string 'none') will be ignored by Site.protect()
+        combined_protections = dict([
+            (p_type, default_level) for p_type in protection_types])
+        for p_type, level in protections.items():
+            level = check_protection_level(p_type, level, protection_levels,
+                                           default_level)
+            if level == 'none':
+                level = ''
+            combined_protections[p_type] = level
+        if not options.get('summary'):
+            options['summary'] = pywikibot.input(
+                u'Enter a reason for the protection change:')
+        bot = ProtectionRobot(generator, combined_protections, **options)
         bot.run()
     else:
         # Show help text from the top of this file
         pywikibot.showHelp()
 
 
-if __name__ == "__main__":
+if __name__ == '__main__':
     main()

-- 
To view, visit https://gerrit.wikimedia.org/r/149501
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I41146fa0c161a242834ab0b1fe2954c7b89d7fd1
Gerrit-PatchSet: 7
Gerrit-Project: pywikibot/core
Gerrit-Branch: master
Gerrit-Owner: Ricordisamoa <[email protected]>
Gerrit-Reviewer: John Vandenberg <[email protected]>
Gerrit-Reviewer: Ladsgroup <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Merlijn van Deen <[email protected]>
Gerrit-Reviewer: Multichill <[email protected]>
Gerrit-Reviewer: Ricordisamoa <[email protected]>
Gerrit-Reviewer: Russell Blau <[email protected]>
Gerrit-Reviewer: XZise <[email protected]>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
Pywikibot-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/pywikibot-commits

Reply via email to