UNPKG

mwn

Version:

JavaScript & TypeScript MediaWiki bot framework for Node.js

441 lines 15.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = default_1; const error_1 = require("./error"); function default_1(bot) { class Page extends bot.Title { constructor(title, namespace) { // bot property is set by mwn#Page() method if (typeof title === 'string') { super(title, namespace); } else if (title.title && title.namespace) { super(title.title, title.namespace); } else { throw new Error('unknown constructor type for mwn Page'); } } /** * @override */ getTalkPage() { return new Page(super.getTalkPage()); } /** * @override */ getSubjectPage() { return new Page(super.getSubjectPage()); } /**** Get operations *****/ /** @inheritDoc */ exists() { return bot .query({ titles: this.toString(), }) .then((data) => { return data.query.pages[0].missing !== true; }); } /** @inheritDoc */ text() { return bot .query({ titles: this.toString(), prop: 'revisions', rvprop: 'content', rvslots: 'main', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].revisions[0].slots.main.content; }); } /** @inheritDoc */ categories() { return bot .query({ titles: this.toString(), prop: 'categories', cllimit: 'max', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].categories.map((e) => e.title); }); } /** @inheritDoc */ templates() { return bot .query({ titles: this.toString(), prop: 'templates', tllimit: 'max', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].templates.map((e) => e.title); }); } /** @inheritDoc */ links() { return bot .query({ titles: this.toString(), prop: 'links', pllimit: 'max', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].links.map((e) => e.title); }); } /** @inheritDoc */ backlinks() { return bot .continuedQuery({ action: 'query', prop: 'linkshere', titles: this.toString(), lhprop: 'title', lhlimit: 'max', }) .then((jsons) => { let pages = jsons.reduce((pages, json) => pages.concat(json.query.pages), []); return (pages[0].linkshere || []).map((pg) => pg.title); }); } /** @inheritDoc */ transclusions() { return bot .continuedQuery({ action: 'query', prop: 'transcludedin', titles: this.toString(), tiprop: 'title', tilimit: 'max', }) .then((jsons) => { let pages = jsons.reduce((pages, json) => pages.concat(json.query.pages), []); return (pages[0].transcludedin || []).map((pg) => pg.title); }); } /** @inheritDoc */ images() { return bot .query({ titles: this.toString(), prop: 'images', imlimit: 'max', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].images.map((e) => e.title); }); } /** @inheritDoc */ externallinks() { return bot .query({ titles: this.toString(), prop: 'extlinks', ellimit: 'max', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].extlinks.map((e) => e.url); }); } /** @inheritDoc */ subpages(options) { return bot .query({ list: 'allpages', apprefix: this.title + '/', apnamespace: this.namespace, aplimit: 'max', ...options, }) .then((data) => { return data.query.allpages.map((pg) => pg.title); }); } /** @inheritDoc */ isRedirect() { return this.getRedirectTarget().then((target) => { return this.toText() !== target; }); } /** @inheritDoc */ getRedirectTarget() { return bot .query({ titles: this.toString(), redirects: true, }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].title; }); } /** @inheritDoc */ getCreator() { return bot .query({ titles: this.toString(), prop: 'revisions', rvprop: 'user', rvlimit: 1, rvdir: 'newer', }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].revisions[0].user; }); } /** @inheritDoc */ getDeletingAdmin() { return bot .request({ action: 'query', list: 'logevents', leaction: 'delete/delete', letitle: this.toString(), lelimit: 1, }) .then((data) => { let logs = data.query.logevents; if (logs.length === 0) { return null; } return logs[0].user; }); } /** @inheritDoc */ getDescription(customOptions) { return bot .query({ prop: 'description', titles: this.toString(), ...customOptions, }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].description; }); } /** @inheritDoc */ history(props, limit = 50, customOptions) { return bot .query({ prop: 'revisions', titles: this.toString(), rvprop: props || 'ids|timestamp|flags|comment|user', rvlimit: limit || 50, ...customOptions, }) .then((data) => { this.throwIfPageMissing(data); return data.query.pages[0].revisions; }); } async *historyGen(props, customOptions) { let continuedQuery = bot.continuedQueryGen({ action: 'query', prop: 'revisions', titles: this.toString(), rvprop: props || 'ids|timestamp|flags|comment|user', rvlimit: 50, ...customOptions, }); for await (let json of continuedQuery) { for (let edit of json.query.pages[0].revisions) { yield edit; } } } /** @inheritDoc */ logs(props, limit, type, customOptions) { let logtypeObj = {}; if (type) { logtypeObj = { [type.includes('/') ? 'leaction' : 'letype']: type }; } return bot .request({ action: 'query', list: 'logevents', ...logtypeObj, leprop: props || 'title|type|user|timestamp|comment', letitle: this.toString(), lelimit: limit || 50, ...customOptions, }) .then((data) => { return data.query.logevents; }); } async *logsGen(props, type, customOptions) { let logtypeObj = {}; if (type) { logtypeObj = { [type.includes('/') ? 'leaction' : 'letype']: type }; } let continuedQuery = bot.continuedQueryGen({ action: 'query', list: 'logevents', ...logtypeObj, leprop: props || 'title|type|user|timestamp|comment', letitle: this.toString(), lelimit: 50, ...customOptions, }); for await (let json of continuedQuery) { for (let event of json.query.logevents) { yield event; } } } throwIfPageMissing(data) { if (data.query.pages[0].missing || data.query.pages[0].invalid) { throw new error_1.MwnMissingPageError(); } } /** @inheritDoc */ async pageViews(options = {}) { let project = bot.options.apiUrl.match(/.*\/(.*?)\.(?:org|com|net)/)?.[1]; if (!project) { throw new Error('Invalid API URL for using pageViews(). Only Wikimedia wikis are supported.'); } // Set defaults let { access, agent, granularity, start, end } = options; access = access || 'all-access'; agent = agent || 'all-agents'; granularity = granularity || 'monthly'; if (granularity === 'daily') { let date = new bot.Date(); date.setUTCDate(date.getUTCDate() - 1); start = start || date; end = end || new bot.Date(); } else if (granularity === 'monthly') { let date = new bot.Date(); date.setUTCDate(1); date.setUTCMonth(date.getUTCMonth() - 1); start = start || date; end = end || (function () { let d = new bot.Date(); d.setUTCDate(1); return d; })(); } let startString = new bot.Date(start).format('YYYYMMDD'), endString = new bot.Date(end).format('YYYYMMDD'); return bot .rawRequest({ url: `https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/${project}/${access}/${agent}/${encodeURIComponent(this.toString())}/${granularity}/${startString}/${endString}`, headers: { 'User-Agent': bot.options.userAgent, }, }) .then((response) => { return response.data.items; }); } /** @inheritDoc */ async queryAuthors() { let langcodematch = bot.options.apiUrl.match(/([^/]*?)\.wikipedia\.org/); if (!langcodematch || !langcodematch[1]) { throw new Error('WikiWho API is not supported for bot API URL. Re-check.'); } let json; try { json = await bot .rawRequest({ url: `https://wikiwho.wmflabs.org/${langcodematch[1]}/api/v1.0.0-beta/latest_rev_content/${encodeURIComponent(this.toString())}/?editor=true`, headers: { 'User-Agent': bot.options.userAgent, }, }) .then((response) => response.data); } catch (err) { throw new Error(err && err.response && err.response.data && err.response.data.Error); } const tokens = Object.values(json.revisions[0])[0].tokens; let data = { totalBytes: 0, users: [], }; let userdata = {}; for (let token of tokens) { data.totalBytes += token.str.length; let editor = token['editor']; if (!userdata[editor]) { userdata[editor] = { bytes: 0 }; } userdata[editor].bytes += token.str.length; if (editor.startsWith('0|')) { // IP userdata[editor].name = editor.slice(2); } } Object.entries(userdata).map(([userid, { bytes }]) => { userdata[userid].percent = bytes / data.totalBytes; if (userdata[userid].percent < 0.02) { delete userdata[userid]; } }); await bot .request({ action: 'query', list: 'users', ususerids: Object.keys(userdata).filter((us) => !us.startsWith('0|')), // don't lookup IPs }) .then((json) => { json.query.users.forEach((us) => { userdata[us.userid].name = us.name; }); }); data.users = Object.entries(userdata) .map(([userid, { bytes, name, percent }]) => { return { id: Number(userid), name: name, bytes: bytes, percent: percent, }; }) .sort((a, b) => { return a.bytes < b.bytes ? 1 : -1; }); return data; } /**** Post operations *****/ // Defined in bot.js edit(transform) { return bot.edit(this.toString(), transform); } save(text, summary, options) { return bot.save(this.toString(), text, summary, options); } newSection(header, message, additionalParams) { return bot.newSection(this.toString(), header, message, additionalParams); } move(target, summary, options) { return bot.move(this.toString(), target, summary, options); } delete(summary, options) { return bot.delete(this.toString(), summary, options); } undelete(summary, options) { return bot.undelete(this.toString(), summary, options); } purge(options) { return bot.purge(this.toString(), options); } } return Page; } //# sourceMappingURL=page.js.map