-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathpolluted-categories-4.js
executable file
·125 lines (111 loc) · 3.54 KB
/
polluted-categories-4.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env node
// Dependencies.
const argv = require('minimist')(process.argv.slice(2));
const MWBot = require('mwbot');
const mysql = require('mysql');
const util = require('util');
const credentials = require('./credentials'); // Load credentials from config.
const apiUrl = 'https://en.wikipedia.org/w/api.php';
const database = 'enwiki_p';
const reportPage = 'Wikipedia:Database reports/Polluted categories (4)';
const editSummary = 'Task 59: Update database report';
/**
* Log a message to stdout prepended with a timestamp.
* @param {String} message
*/
function log(message) {
const datestamp = new Date().toISOString().replace(/T/, ' ').replace(/\..+/, '');
console.log(`${datestamp}: ${message}`);
}
/**
* Connect to the replicas.
* @returns {Connection} A new MySQL connection.
*/
function getReplicaConnection() {
log('Establishing connection to the replicas (PC4)');
const connection = mysql.createConnection({
host: credentials.db_host,
port: credentials.db_port,
user: credentials.db_user,
password: credentials.db_password,
database: credentials.db_database
});
connection.connect();
return connection;
}
/**
* Query the replicas to get the polluted categories.
* @returns {Array} Result of query.
*/
async function getPollutedCategories() {
const connection = getReplicaConnection();
log('Running query to fetch polluted categories (4)');
const sql = `
SELECT cl_to AS category, COUNT(*) AS count
FROM ${database}.categorylinks
WHERE cl_to IN (
SELECT page_title
FROM page
LEFT JOIN categorylinks
ON page.page_id = categorylinks.cl_from
WHERE cl_to = 'Disambiguation_categories'
)
AND cl_type = 'page'
GROUP BY cl_to
ORDER BY COUNT(*) DESC, cl_to ASC`;
// Make database query synchronous.
const fn = util.promisify(connection.query).bind(connection);
return await fn(sql);
}
/**
* Create a wiki table for the results.
* @param {Array} results
* @returns {String} Wikitext.
*/
function getTableMarkup(results) {
let table = '{| class="wikitable sortable" \n! Category !! Pages';
results.forEach(row => {
table += `\n|-\n| [[:Category:${row.category.toString().replace(/_/g, ' ')}]] || ${row.count.toString()}`;
});
return table += '\n|}';
}
/**
* Update the report with the given content.
* @param {String} content
* @returns {Promise<void>}
*/
async function updateReport(content) {
// Login to the bot.
log(`Logging in to bot account`);
const bot = new MWBot({apiUrl});
await bot.loginGetEditToken({
apiUrl,
username: credentials.username,
password: credentials.password
});
// Edit the page.
log(`Writing to [[${reportPage}]]`);
await bot.edit(reportPage, content, editSummary).catch(err => {
const error = err.response && err.response.error ? err.response.error.code : 'Unknown';
log(`Failed to write to page: ${error}`);
});
}
/**
* Entry point for the bot task.
* @returns {Promise<void>}
*/
async function main() {
const results = await getPollutedCategories();
const content = 'Disambiguation categories that contain pages; ' +
'data as of <onlyinclude>~~~~~</onlyinclude>. Updated by ~~~.\n\n' +
getTableMarkup(results);
if (argv.dry) {
// Dry mode.
console.log(content);
} else {
await updateReport(content);
}
log('Task complete!');
process.exit();
}
main().catch(console.error);