ویکیپیڈیا:درخواست منتقلی زمرہ جات/ترتیبات/کوڈ

#!/usr/bin/python
# -*- coding: utf-8  -*-
"""
dar.py - a script to move categories by request

useage:
    python pwb.py dar [OPTIONS]
"""
# (C) Reza (w:fa:User:Reza1615), 2015
# (C) Amir (w:fa:User:Ladsgroup), 2015
# (C) Huji (w:fa:User:Huji), 2016
# (C) Mohib (w:ur:User:mohibalvi), 2024
# Distributed under the terms of MIT License (MIT)

from __future__ import absolute_import, unicode_literals

import pywikibot
from pywikibot import pagegenerators
from pywikibot import config
import sys
import json
import re
from scripts import category
import pathlib


class CatMoveBot:
    def __init__(self, logPage=None, project='wikipedia'):
        if logPage is None:
            raise ValueError('Log page must be specified')
        self.logPage = logPage
        self.site = pywikibot.Site('ur', project)
        self.redirTemplate = 'زمرہ رجوع مکرر'
        
        # Initialize summary template without .format()
        self.summary = '[[وپ:دمز|خودکار: منتقلی زمرہ]] بدرخواست [[User:%s|%s]]'

    def move(self, origin, destination, user):
        """
        Plans moving pages from one category to the other, and updates the category
        pages to reflect this move.

        @param task: A list with two elements; the first element is the name of the
            origin category, and the second is the name of, family=project the destination category
        @param user: Name of the user on whose behalf the category move is done
        """
        # Adjust summary based on whether origin and destination start with "زمرہ:"
        summary = f'[[وپ:دمز|خودکار: منتقلی زمرہ]] بدرخواست [[User:{user}|{user}]]'

        if origin.startswith("زمرہ:") and destination.startswith("زمرہ:"):
            summary += f' از [[{origin}]] > [[{destination}]]'
        elif origin.startswith("زمرہ:"):
            summary += f' از [[{origin}]] > [[زمرہ:{destination}]]'
        elif destination.startswith("زمرہ:"):
            summary += f' از [[زمرہ:{origin}]] > [[{destination}]]'
        else:
            summary += f' از [[زمرہ{origin}]] > [[زمرہ{destination}]]'
        
        comment = summary
        
        cat = category.CategoryMoveRobot(
            origin, destination, batch=True,
            comment=comment, inplace=False, move_oldcat=True,
            delete_oldcat=True, title_regex=None, history=False)
        cat.run()

    def run(self, task, user):
        origin = task[0]
        destination = task[1]
        # Title of the destination page, without prefix
        destTitle = re.sub('^(زمرہ|[Cc]ategory)\:', '', destination)

        originPage = pywikibot.Page(self.site, origin)
        destinationPage = pywikibot.Page(self.site, destination)
        
        #originPageText = ''
        #destinationPageText = ''

        if originPage:
            try:
                originPageText = originPage.get()
                # Replace contents with the {{Category redirect}} template
                originPage.put(
                    '{{' + self.redirTemplate + '|' + destTitle + '}}',
                    self.summary % (user, user, origin, destination))  # corrected and replaced "destinatino" with destination
            # Added Exception as err code for modern error handling
            except Exception as err:  
                # Failed to fetch page contents, changed pass to print(err) to print the error
                print(err)  

        if destinationPage:
            try:
                originPageText = originPage.get()
                # TODO: Remove old {{Category redirect}}
            except Exception as err:  
                print(err)  # changed pass to print(err) to print the error


        self.move(origin, destination, user)
        originPage = pywikibot.Page(self.site, origin)


class CatMoveInput:
    def __init__(self, cacheFile=None, project='wikipedia', threshold=3000):
        """
        @param cacheFile: path to the local cache of previously validated users
        """
        if cacheFile is None:
            raise ValueError('Cache file location must be specified')
        else:
            self.cacheFile = cacheFile
        self.cache = self.loadCache()
        self.site = pywikibot.Site('ur', project)
        self.tasksPageDefault = '{{/بالا}}'
        self.moverBots = ['ZumraBot']
        self.threshold = threshold
        self.successSummary = 'خودکار : منتقلی زمرہ مکمل!'

    def loadCache(self):
        f = open(self.cacheFile, 'r', encoding='utf-8')  # removed codecs as open now supports utf-8 encoding
        txt = f.read().strip()
        f.close()

        if txt == '':
            # Brand new cache file will fail json.loads(), return an empty dictionary instead
            cache = {}
        else:
            cache = json.loads(txt)
        return cache


    def updateCache(self, cache):
        fh = open(self.cacheFile, 'w', encoding='utf-8')
        fh.write(json.dumps(cache))
        fh.close()


    def verifyUser(self, username):
        username = username.replace(' ', '_')

        # If we have already established that this user qualifies then don't verify the user again
        if self.cache.get(username):
            return True

        # Only users whose edit count is larger than self.threshold can request category moves
        params = {
            'action': 'query',
            'list': 'users',
            'ususers': username,
            'usprop': 'editcount'
        }

        try:
            req = pywikibot.data.api.Request(site=self.site, **params)
            query = req.submit()
            if query['query']['users'][0]['editcount'] > self.threshold:
                self.cache[username] = True
                self.updateCache(self.cache)
                return True
            else:
                return False
        except:
            return False

    
    def processInput(self, tasksPageName):
        tasksPage = pywikibot.Page(self.site, tasksPageName)
        
        try:
            pageText = tasksPage.get()
            # replaced getVersionHistory() with revisions()
            #revisions   = tasksPage.revisions()                            
            #pageHistory = list(revisions)
            #lastUser    = pageHistory[-1]['user']

            # Fetch only the latest revision
            ver_history = tasksPage.revisions(reverse=True,total=1)  
            # ver_history is a generator, use next method to get iterator
            last_revision = next(ver_history)                        
            lastUser = last_revision['user']
        # replaced IsRedirectPage() to isRedirectPage()
        except pywikibot.isRedirectPage:                             
            tasksPage = tasksPage.getRedirectTarget()
            try:
                pageText = tasksPage.get()
                # Fetch only the latest revision
                ver_history = tasksPage.revisions(reverse=True,total=1)  
                last_revision = next(ver_history)                        
                lastUser = last_revision['user']
            except:
                raise ValueError('Task list page not found!')
        except:
            raise ValueError('Task list page not found!')

        if lastUser in self.moverBots:
            print(json.dumps({
                'result': 'Last edit was by a mover bot. Request ignored.'
            }))

            return False
        elif self.verifyUser(lastUser):
            print(json.dumps({ 'result': 'User verified. Processing task list.'  }))
            tasks = self.getTaskList(pageText)
            tasksPage.put(self.tasksPageDefault, self.successSummary)
            
            return {'tasks': tasks, 'user': lastUser}
        else:
            print(json.dumps({
                'result': 'Last editor was not qualified. Request ignored.' }))

            return False

    def getTaskList(self, taskText):
        """ 
        Returns a list of lists, where each inner lists describe one category move request (i.e. [origin, destination]).
        @param taskText: wikicode of the page containing category move requests 
        """

        # Commenting out text replacement as bala template is required
        lines = taskText.split('\n')
        wikiText = [line for line in lines if line.strip()]
        #taskText = taskText.replace('{{/بالا}}','').replace('\r','').replace('\n\n','\n').strip()
        taskList = []


        for line in wikiText:
            # change from line == '*' to line.startswith('*)
            if line.startswith('*'):     
                # Remove the * and any immediately following spaces
                line = re.sub('^\* *', '', line)

                # Unlink category links
                if '[[' in line:
                    line = re.sub('\[\[\:(زمرہ|[Cc]ategory)\:([^\]]+)\]\]',
                                  '\\1:\\2', line)
                
                # Split by '>' or '@' (optionally surrounded by spaces)
                if '>' in line or '@' in line:
                    pieces = re.split(' *[>@] *', line)
                
                    # Clean up category mentions
                    for i in range(0, len(pieces)):
                
                        # Make edit summaries more beautiful!
                        pieces[i] = pieces[i].replace('_', ' ')
                
                        # Add missing `Category` prefix
                        if (
                            re.search('^[Cc]ategory\:', pieces[i]) is None and
                            re.search('^زمرہ\:', pieces[i]) is None
                        ):
                            pieces[i] = ':' + pieces[i]
                    
                    # Add the pair to our task list
                    taskList.append(pieces)
                else:
                    # Mention @ or > not found in the line 
                    print('No ">" or "@" characters in the line')
        return taskList


def main():
    from pathlib import Path
    BASE_DIR = Path(__file__).resolve().parent
    cacheFile = BASE_DIR / 'cache_dar.txt'      # changed it to run locally 
    #cacheFile = '/data/project/zumraband/cache_dar.txt'

    # if 'wikiquote' in sys.argv:
    #     project = 'wikiquote'
    #     page_name = 'ویکی اقتباسات:درخواست منتقلی زمرہ جات'
    #     limit = 750
    #     config.family = project
    # else:

    project = 'wikipedia'
    page_name = 'ویکیپیڈیا:درخواست منتقلی زمرہ جات'
    limit = 3000

    vBot = CatMoveInput(cacheFile, project, limit)
    req = vBot.processInput(page_name)

    for task in req['tasks']:
        mBot = CatMoveBot(page_name, project)
        mBot.run(task, req['user'])

if __name__ == '__main__':
    main()