Jump to content

Topic on Extension talk:UserMerge

HackForLive (talkcontribs)

I would like to contribute with multiple user merge scripts. The motivation behind this approach is to merge a list of users without manually entering each user on Special:UserMerge page.

I spin up mediawiki using vagrant. It was running on localhost with administrator credentials (admin:vagrant). I created manually Testold, Testnew and Testold2,Testnew2 users. As a result Testold user should be merged to Testnew and Testold2 shoudl be merged to Testnew2.

Following steps are implemented in provided scripts:

  1. Retrieve login token via mediawiki API
  2. Logon as admin (or someone with usermerge privileges) using login token
  3. Retrieve csfr token via mediawiki API
  4. Loop over users to be merged and for each send post request using csfr token

ā€Ž

Tested on Mediawiki version 1.31.x and 1.39.x ā€Ž

Powershell:

$baseUrl = 'http://localhost:8080'
$resp = invoke-webrequest -method GET -uri "
${baseUrl}/w/api.php?action=query&meta=tokens&format=json&type=login" -ContentType "application/json" -SessionVariable session
$loginToken = ($resp.Content | ConvertFrom-Json).query.tokens.logintoken

$body = @{
   "action" = "clientlogin"
   "logintoken" = "${loginToken}"
   "username" = "admin"
   "password" = "vagrant"
}

$resp = Invoke-WebRequest -Method POST -Uri "${baseUrl}/w/api.php?action=clientlogin&loginreturnurl=${baseUrl}/&format=json" -Body $body -WebSession $session
Write-Host ($resp.Content)

$resp = invoke-webrequest -method GET -uri "${baseUrl}/w/api.php?action=query&meta=tokens&format=json" -ContentType "application/json" -WebSession $session
$csfrToken = ($resp.Content | ConvertFrom-Json).query.tokens.csrftoken

$users = @(
    @{
        olduser = 'Testold'
        newuser = 'Testnew'
        # Testold will not be deleted
		deleteOldUser = 0
    },
    @{
        olduser = 'Testold2'
        newuser = 'Testnew2'
		# Testold2 will be deleted
        deleteOldUser = 1
    }
)

foreach($user in $users){
    $body = @{
        wpolduser=$user['olduser']
        wpnewuser=$user['newuser']
        wpdelete=$user['deleteOldUser']
        wpEditToken=$csfrToken
        title='Special:UserMerge'
        redirectparams=
    }

    $resp = invoke-webrequest -method Post -uri "${baseUrl}/wiki/Special:UserMerge" -Body $body -WebSession $session
    Write-Host ($resp.ParsedHtml.getElementsByTagName('p') | select -Property innerHtml)
}

Python:

#!/usr/bin/python3

"""
    clientlogin.py

    MediaWiki UserMerge Code Sample
"""

import requests
from urllib.parse import urljoin
from bs4 import BeautifulSoup

def client_login(url, login_token, username, password):
    """ Send a post request along with login token, user information
    and return URL to the API to log in on a wiki """

    response = S.post(url=urljoin(url, 'w/api.php'), data={
        'action': "clientlogin",
        'username': username,
        'password': password,
        'loginreturnurl': url,
        'logintoken': login_token,
        'format': "json"
    })

    return response.json()

def fetch_login_token(url):
    """ Fetch login token via `tokens` module """

    response = S.get(
        url=urljoin(url, 'w/api.php'),
        params={
            'action': "query",
            'meta': "tokens",
            'type': "login",
            'format': "json"})
    data = response.json()
    return data['query']['tokens']['logintoken']

def fetch_csfr_token(url):
    """ Fetch csfr token via `tokens` module """

    response = S.get(
        url=urljoin(url, 'w/api.php'),
        params={
            'action': "query",
            'meta': "tokens",
            'format': "json"})
    data = response.json()
    return data['query']['tokens']['csrftoken']

def user_merge(url, users, csfr_token):
    """ User merge action """
    for user in users:
        response = S.post(
            url=urljoin(url, 'wiki/Special:UserMerge'),
            data={
                "wpolduser": user["oldUser"],
                "wpnewuser": user["newUser"],
                "wpdelete": user["deleteOldUser"],
                "wpEditToken": csfr_token,
                "title": "Special:UserMerge",
                "redirectparams": ""
            }
        )
        soup = BeautifulSoup(response.text, 'lxml')
        print(soup.find_all('p'))
    pass

if __name__ == "__main__":
    S = requests.Session()
    URL = "http://localhost:8080"
    
    login_token = fetch_login_token(URL)
    print(client_login(URL, login_token, 'admin', 'vagrant'))
    
    csfr_token = fetch_csfr_token(URL)
    print(csfr_token)
    users = [{'oldUser':'Testold', 'newUser':'Testnew', 'deleteOldUser': 0},
             {'oldUser':'Testold2', 'newUser':'Testnew2', 'deleteOldUser': 1}]
    user_merge(URL, users, csfr_token)
Reply to "User mass merge"