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:
- Retrieve login token via mediawiki API
- Logon as admin (or someone with usermerge privileges) using login token
- Retrieve csfr token via mediawiki API
- 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)