Created
August 21, 2024 12:30
-
-
Save zbycz/d93b35d6d6c7fcff6f118c2f4758ddab to your computer and use it in GitHub Desktop.
Mediawiki API client with file upload (TypeScript)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import fetch from 'isomorphic-unfetch'; | |
import { | |
FORMAT, | |
getUploadBody, | |
cookieJar, | |
UploadParams, | |
WIKI_URL, | |
} from './utils'; | |
import { readFile } from 'node:fs/promises'; | |
type Params = Record<string, string>; | |
export const getMediaWikiSession = () => { | |
let sessionCookie: string | undefined; | |
const GET = async (action: string, params: Params) => { | |
const query = new URLSearchParams({ action, ...params, ...FORMAT }); | |
const response = await fetch(`${WIKI_URL}?${query}`, { | |
headers: { Cookie: sessionCookie }, | |
}); | |
sessionCookie = cookieJar(sessionCookie, response); | |
return response.json(); | |
}; | |
const POST = async (action: string, params: Params) => { | |
const query = new URLSearchParams({ action, ...params, ...FORMAT }); | |
const response = await fetch(WIKI_URL, { | |
method: 'POST', | |
headers: { Cookie: sessionCookie }, | |
body: query, | |
}); | |
sessionCookie = cookieJar(sessionCookie, response); | |
return response.json(); | |
}; | |
const UPLOAD = async (action: string, params: UploadParams) => { | |
const response = await fetch(WIKI_URL, { | |
method: 'POST', | |
headers: { Cookie: sessionCookie }, | |
body: getUploadBody({ action, ...params, ...FORMAT }), | |
}); | |
sessionCookie = cookieJar(sessionCookie, response); | |
return response.json(); | |
}; | |
const getLoginToken = async (): Promise<string> => { | |
const data = await GET('query', { meta: 'tokens', type: 'login' }); | |
return data.query.tokens.logintoken; | |
}; | |
const login = async (lgname: string, lgpassword: string) => { | |
const lgtoken = await getLoginToken(); | |
const data = await POST('login', { lgname, lgpassword, lgtoken }); | |
return data.login; | |
}; | |
const getCsrfToken = async () => { | |
const data = await GET('query', { meta: 'tokens', type: 'csrf' }); | |
console.log('getCsrfToken', data.query.tokens.csrftoken); | |
return data.query.tokens.csrftoken; | |
}; | |
const upload = async (filepath: string, filename: string, text: string) => { | |
const token = await getCsrfToken(); | |
const file = await readFile(filepath); | |
const blob = new Blob([file], { type: 'application/octet-stream' }); | |
const data = await UPLOAD('upload', { | |
file: blob, | |
filename, | |
text, | |
comment: 'Initial upload from OsmAPP.org', | |
token, | |
}); | |
return data; | |
}; | |
// https://github.com/multichill/toollabs/blob/master/bot/commons/geograph_uploader.py#L132 | |
const editClaims = async (pageId: string, claims) => { | |
const token = await getCsrfToken(); | |
const response = await POST('wbeditentity', { | |
id: pageId, | |
data: JSON.stringify({ claims }), | |
token, | |
}); | |
return await response.json(); | |
}; | |
return { | |
login, | |
upload, | |
editClaims, | |
}; | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { getMediaWikiSession } from './mediawiki'; | |
import { readFile } from 'node:fs/promises'; | |
(async () => { | |
const password = (await readFile('../../../../.env.local', 'utf-8')) | |
.split('\n')[0] | |
.split('=')[1]; | |
const session = getMediaWikiSession(); | |
console.log(await session.login('OsmappBot@osmapp-upload', password)); | |
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export const WIKI_URL = 'https://test.wikipedia.org/w/api.php'; | |
export const FORMAT = { format: 'json', formatversion: '2' }; | |
export type UploadParams = Record<string, string | Blob>; | |
export const getUploadBody = (params: UploadParams) => { | |
const formData = new FormData(); | |
Object.entries(params).forEach(([k, v]) => { | |
formData.append(k, v); | |
}); | |
return formData; | |
}; | |
export const cookieJar = (cookies: string, response: Response) => { | |
const oldCookies: Record<string, string> = | |
cookies?.split(';').reduce((acc, c) => { | |
const [name, value] = c.split('='); | |
return { ...acc, [name.trim()]: value.trim() }; | |
}, {}) ?? {}; | |
const headers = new Headers(response.headers); | |
headers.getSetCookie().forEach((cookie) => { | |
const [name, value] = cookie.split(';')[0].split('='); | |
oldCookies[name] = value; | |
}); | |
const out = Object.entries(oldCookies) | |
.map(([name, value]) => `${name}=${value}`) | |
.join('; '); | |
return out; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment