-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathremindMe.js
More file actions
executable file
·206 lines (191 loc) · 5.4 KB
/
remindMe.js
File metadata and controls
executable file
·206 lines (191 loc) · 5.4 KB
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
#!/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';
/**
* 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}`);
}
/**
* Query the replicas to get the users opted in
* @returns {Array} Result of query.
*/
async function getUsers() {
log('Establishing connection to the replicas (RemindMe)');
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();
log('Running query for users opted in');
const sql = `
SELECT page_title AS user
FROM ${database}.page
JOIN ${database}.templatelinks
ON page.page_id = templatelinks.tl_from
WHERE tl_namespace = 10
AND tl_title = 'PleaseRemindMe'
AND tl_from_namespace IN (2, 3)`;
// Make database query synchronous.
const fn = util.promisify(connection.query).bind(connection);
return await fn(sql);
}
/**
* Get the bot object
* @returns {Promise<MWBot>}
*/
async function getBot(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
});
return bot;
}
/**
* Process a user
*
* TODO code
*
* @param {object} info
* @param {MWBot} bot
* @param {bool} dry
*/
async function remindUser( info, bot, dry ) {
const userName = info.user;
log(`Reminding user: ${userName}`);
const scheduledReminders = await getUserReminders( userName, bot );
console.log( scheduledReminders );
const forToday = getForToday( scheduledReminders );
console.log( forToday );
for ( var reminderNum = 0; reminderNum < forToday.length; reminderNum++ ) {
let reminderText = forToday[reminderNum];
if ( dry ) {
console.log(`Dry mode: Would send a reminder to ${userName}: ${reminderText}`);
} else {
await sendReminder( userName, reminderText, bot );
}
}
}
/**
* Get the JSON representing a user's scheduled reminders
* Cannot query database, text isn't available there; use the api
* @param {string} userName
* @param {MWBot} bot
* @return {Promise<array>}
*/
async function getUserReminders( userName, bot ) {
return new Promise((resolve) => {
let remindersTitle = 'User:' + userName + '/RemindMe.json';
bot.request( {
action: 'query',
prop: 'revisions',
titles: remindersTitle,
rvslots: 'main',
rvprop: 'content',
formatversion: 2
} ).then( response => {
console.log( response );
let pageInfo = response.query.pages[0];
let currentlyScheduled = [];
if ( !pageInfo.missing ) {
let rawJSON = pageInfo.revisions[0].slots.main.content;
currentlyScheduled = JSON.parse( rawJSON );
}
resolve( currentlyScheduled );
} ).catch(err => {
const error = err.response && err.response.error ? err.response.error.code : 'Unknown';
log(`Api failure: ${error}`);
resolve( [] )
});
});
}
/**
* Filter for today's reminders
*
* @param {array} allReminders
* @return array
*/
function getForToday( allReminders ) {
let forToday = [];
const today = new Date().toISOString().replace(/T.*/, '');
for ( let jjj = 0; jjj < allReminders.length; jjj++ ) {
let reminder = allReminders[jjj];
if ( reminder && reminder[0] && reminder[0] === today && reminder[1] ) {
console.log(`Reminder for today: ${reminder[1]}`);
forToday.push( reminder[1] );
} else {
console.log(`Not for today: ${reminder}`);
}
}
return forToday;
}
/**
* Send a reminder
*
* @param {string} userName
* @param {string} reminderText
* @param {MWBot} bot
*/
async function sendReminder( userName, reminderText, bot ) {
const today = new Date().toISOString().replace(/T.*/, '');
const sectionHeading = `Automatic reminder: ${today}`;
const talkPage = `User talk:${userName}`;
const editSummary = 'Task 68: Post scheduled reminder';
let messageContent = "Hello {{subst:BASEPAGENAME}}."
+ "\n\n"
+ "You have scheduled a reminder for yourself for today, shown below:"
+ "\n----\n"
+ reminderText
+ "\n----\n"
+ "You can now remove the reminder from your schedule at the /RemindMe.json subpage of your userpage."
+ "\n\n"
+ "Thanks, --~~~~";
log(`Sending reminder to ${userName}`);
const tokens = await bot.getEditToken();
await bot.request({
action: 'edit',
title: talkPage,
section: 'new',
sectiontitle: sectionHeading,
text: messageContent,
summary: editSummary,
notminor: true,
token: tokens.csrftoken
}).then(response => {
console.log( response );
}).catch(err => {
console.log( err );
const error = err.response && err.response.error ? err.response.error.code : 'Unknown';
log(`Failed to send reminder: ${error}`);
});
}
/**
* Entry point for the bot task.
* @returns {Promise<void>}
*/
async function main() {
const users = await getUsers();
const bot = await getBot();
for ( let iii = 0; iii < users.length; iii++ ) {
await remindUser(users[iii], bot, argv.dry);
}
log('Task complete!');
process.exit();
}
main().catch(console.error);