Skip to content

Commit cf5af5c

Browse files
authored
Merge pull request #12 from exo-do/features/descriptive-error-messages
more descriptive error messages
2 parents 4b2103a + a85a69b commit cf5af5c

7 files changed

Lines changed: 92 additions & 44 deletions

ReputationManager.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ let ReputationManager = function (Config) {
2323
} catch (err) {
2424
throw {
2525
'allowed': false,
26-
'reason': err.reason
26+
'reason': err.reason,
27+
'params': err.params
2728
};
2829
}
2930
};
@@ -47,7 +48,8 @@ let ReputationManager = function (Config) {
4748
} catch (err) {
4849
throw {
4950
'allowed': false,
50-
'reason': err.reason
51+
'reason': err.reason,
52+
'params': err.params
5153
};
5254
}
5355
};

UserVotingPermissions.js

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@ let UserVotingPermissions = function(Config, db, user, post) {
44

55
this.hasEnoughPostsToUpvote = async function() {
66
let allowed = user.postcount >= Config.minPostToUpvote();
7-
if (!allowed) throw {'reason': 'notEnoughPosts'};
7+
if (!allowed) throw {
8+
'reason': 'notEnoughPosts',
9+
'params': [Config.minPostToUpvote()]
10+
};
811
};
912

1013
this.isOldEnoughToUpvote = async function() {
1114
let now = new Date();
1215
let xDaysAgo = now.getTime() - Config.minDaysToUpvote() * 24 * 60 * 60 * 1000;
1316

1417
let allowed = user.joindate < xDaysAgo;
15-
if (!allowed) throw {'reason': 'notOldEnough'};
18+
if (!allowed) throw {
19+
'reason': 'notOldEnough',
20+
'params': [Config.minDaysToUpvote()]
21+
};
1622
};
1723

1824
this.hasVotedTooManyPostsInThread = async function() {
@@ -24,7 +30,10 @@ let UserVotingPermissions = function(Config, db, user, post) {
2430
throw err;
2531
}
2632
let allowed = userVotesInThread < Config.maxVotesPerUserInThread();
27-
if (!allowed) throw {'reason': 'tooManyVotesInThread'};
33+
if (!allowed) throw {
34+
'reason': 'tooManyVotesInThread',
35+
'params': [Config.maxVotesPerUserInThread()]
36+
};
2837
};
2938

3039
this.hasVotedAuthorTooManyTimesThisMonth = async function() {
@@ -36,7 +45,10 @@ let UserVotingPermissions = function(Config, db, user, post) {
3645
throw err;
3746
}
3847
let allowed = votesToAuthor < Config.maxVotesToSameUserInMonth();
39-
if (!allowed) throw {'reason': 'tooManyVotesToSameUserThisMonth'};
48+
if (!allowed) throw {
49+
'reason': 'tooManyVotesToSameUserThisMonth',
50+
'params': [Config.maxVotesToSameUserInMonth()]
51+
};
4052
};
4153

4254
this.hasVotedTooManyTimesToday = async function() {
@@ -48,25 +60,37 @@ let UserVotingPermissions = function(Config, db, user, post) {
4860
throw err;
4961
}
5062
let allowed = votes < Config.maxVotesPerUser(user.reputation);
51-
if (!allowed) throw {'reason': 'tooManyVotesToday'};
63+
if (!allowed) throw {
64+
'reason': 'tooManyVotesToday',
65+
'params': [Config.maxVotesPerUser(user.reputation)]
66+
};
5267
};
5368

5469
this.hasEnoughPostsToDownvote = async function() {
5570
let allowed = user.postcount >= Config.minPostToDownvote();
56-
if (!allowed) throw {'reason': 'notEnoughPosts'};
71+
if (!allowed) throw {
72+
'reason': 'notEnoughPosts',
73+
'params': [Config.minPostToDownvote()]
74+
};
5775
};
5876

5977
this.isOldEnoughToDownvote = async function() {
6078
let now = new Date();
6179
let xDaysAgo = now.getTime() - Config.minDaysToDownvote() * 24 * 60 * 60 * 1000;
6280

6381
let allowed = user.joindate < xDaysAgo;
64-
if (!allowed) throw {'reason': 'notOldEnough'};
82+
if (!allowed) throw {
83+
'reason': 'notOldEnough',
84+
'params': [Config.minDaysToDownvote()]
85+
};
6586
};
6687

6788
this.hasEnoughReputationToDownvote = async function() {
6889
let allowed = user.reputation >= Config.minReputationToDownvote();
69-
if (!allowed) throw {'reason': 'notEnoughReputation'};
90+
if (!allowed) throw {
91+
'reason': 'notEnoughReputation',
92+
'params': [Config.minReputationToDownvote()]
93+
};
7094
};
7195

7296
this.votingAllowedInCategory = async function() {
@@ -81,7 +105,10 @@ let UserVotingPermissions = function(Config, db, user, post) {
81105

82106
let now = new Date();
83107
let postAgeDays = (now - post.timestamp)/24/60/60/1000;
84-
if (postAgeDays > Config.getMaxPostAgeDays()) throw {'reason': 'postTooOld'};
108+
if (postAgeDays > Config.getMaxPostAgeDays()) throw {
109+
'reason': 'postTooOld',
110+
'params': [Config.getMaxPostAgeDays()]
111+
};
85112
};
86113

87114
this.hasDownvotedTooManyTimesToday = async function() {
@@ -95,7 +122,10 @@ let UserVotingPermissions = function(Config, db, user, post) {
95122
throw err;
96123
}
97124
let allowed = downvotes < Config.maxDownvotesPerDay();
98-
if (!allowed) throw {'reason': 'tooManyDownvotesToday'};
125+
if (!allowed) throw {
126+
'reason': 'tooManyDownvotesToday',
127+
'params': [Config.maxDownvotesPerDay()]
128+
};
99129
};
100130

101131
async function countVotesInThread(userId, threadId) {

VoteFilter.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ let VoteFilter = function(ReputationManager, users) {
6161
winston.error(err.message);
6262
}
6363
let settings = await users.getSettings(data.user.uid);
64-
return translator.translate(err.reason, settings.userLang);
64+
return translator.translate(err.reason, err.params, settings.userLang);
6565
}
6666
};
6767

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"votingDisabledInCategory": "Voting has been disabled in this category",
3-
"notEnoughPosts": "Not enough messages to vote",
4-
"notOldEnough": "You are not an old enough member of this forum",
5-
"notEnoughReputation": "You don't have enough reputation",
6-
"tooManyVotesInThread": "You can't vote more messages in this thread",
7-
"tooManyVotesToSameUserThisMonth": "You can't vote this user again until next month",
8-
"tooManyVotesToday": "You can't vote more messages today",
9-
"tooManyDownvotesToday": "You can't downvote more messages today",
10-
"postTooOld": "You can't vote this message, it is too old",
3+
"notEnoughPosts": "You need to have at least <strong>%0</strong> posts to vote",
4+
"notOldEnough": "You have to be a member of this forum for <strong>%0</strong> days before you can vote",
5+
"notEnoughReputation": "You need at least <strong>%0</strong> reputation to vote",
6+
"tooManyVotesInThread": "You can't vote more messages in this thread, you already voted <strong>%0</strong> posts here",
7+
"tooManyVotesToSameUserThisMonth": "You already voted <strong>%0</strong> times for this user and this month, wait until next month",
8+
"tooManyVotesToday": "You can't vote more messages today, you already voted <strong>%0</strong> times",
9+
"tooManyDownvotesToday": "You can't downvote more messages today, you already downvoted <strong>%0</strong> posts",
10+
"postTooOld": "You can't vote messages older than <strong>%0</strong> days",
1111
"unknownError": "Error voting"
1212
}
Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"votingDisabledInCategory": "No se puede votar en esta sección",
3-
"notEnoughPosts": "No tienes suficientes mensajes",
4-
"notOldEnough": "Llevas poco tiempo registrado",
5-
"notEnoughReputation": "No tienes suficiente reputación",
6-
"tooManyVotesInThread": "No puedes votar más mensajes en este hilo",
7-
"tooManyVotesToSameUserThisMonth": "Ya has votado a este usuario este mes",
8-
"tooManyVotesToday": "No puedes votar más mensajes hoy",
9-
"tooManyDownvotesToday": "No puedes dar más negativos hoy",
10-
"postTooOld": "No puedes votar este mensaje, es muy antiguo",
3+
"notEnoughPosts": "Necesitas tener al menos <strong>%0</strong> para votar",
4+
"notOldEnough": "Debes llevar al menos <strong>%0</strong> días registrado en el foro para votar",
5+
"notEnoughReputation": "Necesitas al menos <strong>%0</strong> de reputación para votar",
6+
"tooManyVotesInThread": "No puedes votar más mensajes en este tema, ya has votado <strong>%0</strong> mensajes",
7+
"tooManyVotesToSameUserThisMonth": "Has votado <strong>%0</strong> mensajes de este usuario este mes, espera al mes siguiente para votarle de nuevo",
8+
"tooManyVotesToday": "No puedes votar más mensajes hoy, ya has votado <strong>%0</strong> veces",
9+
"tooManyDownvotesToday": "No puedes dar más negativos hoy, has llegado al máximo de <strong>%0</strong> en un día",
10+
"postTooOld": "No se pueden votar mensajes con más de <strong>%0</strong> días de antigüedad",
1111
"unknownError": "Error al votar"
1212
}

test/UserVotingPermissions.test.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ describe('UserVotingPermissions', function() {
3939
assert.fail('expected an error');
4040
} catch (err) {
4141
assert.strictEqual(err.reason, 'notEnoughPosts');
42+
assert.deepStrictEqual(err.params, [20]);
4243
}
4344
});
4445
});
@@ -66,6 +67,7 @@ describe('UserVotingPermissions', function() {
6667
assert.fail('expected an error');
6768
} catch (err) {
6869
assert.strictEqual(err.reason, 'notOldEnough');
70+
assert.deepStrictEqual(err.params, [6]);
6971
}
7072
});
7173
});
@@ -103,6 +105,7 @@ describe('UserVotingPermissions', function() {
103105
assert.fail('expected an error');
104106
} catch (err) {
105107
assert.strictEqual(err.reason, 'tooManyVotesInThread');
108+
assert.deepStrictEqual(err.params, [3]);
106109
}
107110
});
108111
});
@@ -140,6 +143,7 @@ describe('UserVotingPermissions', function() {
140143
assert.fail('expected an error');
141144
} catch (err) {
142145
assert.strictEqual(err.reason, 'tooManyVotesToSameUserThisMonth');
146+
assert.deepStrictEqual(err.params, [10]);
143147
}
144148
});
145149
});
@@ -175,6 +179,7 @@ describe('UserVotingPermissions', function() {
175179
assert.fail('expected an error');
176180
} catch (err) {
177181
assert.strictEqual(err.reason, 'tooManyVotesToday');
182+
assert.deepStrictEqual(err.params, [5]);
178183
}
179184
});
180185
});
@@ -202,6 +207,7 @@ describe('UserVotingPermissions', function() {
202207
assert.fail('expected an error');
203208
} catch (err) {
204209
assert.strictEqual(err.reason, 'notEnoughPosts');
210+
assert.deepStrictEqual(err.params, [20]);
205211
}
206212
});
207213
});
@@ -229,6 +235,7 @@ describe('UserVotingPermissions', function() {
229235
assert.fail('expected an error');
230236
} catch (err) {
231237
assert.strictEqual(err.reason, 'notOldEnough');
238+
assert.deepStrictEqual(err.params, [6]);
232239
}
233240
});
234241
});
@@ -256,6 +263,7 @@ describe('UserVotingPermissions', function() {
256263
assert.fail('expected an error');
257264
} catch (err) {
258265
assert.strictEqual(err.reason, 'notEnoughReputation');
266+
assert.deepStrictEqual(err.params, [20]);
259267
}
260268
});
261269
});
@@ -310,6 +318,7 @@ describe('UserVotingPermissions', function() {
310318
assert.fail('expected an error');
311319
} catch (err) {
312320
assert.strictEqual(err.reason, 'postTooOld');
321+
assert.deepStrictEqual(err.params, [30]);
313322
}
314323
});
315324

@@ -355,6 +364,7 @@ describe('UserVotingPermissions', function() {
355364
assert.fail('expected an error');
356365
} catch (err) {
357366
assert.strictEqual(err.reason, 'tooManyDownvotesToday');
367+
assert.deepStrictEqual(err.params, [5]);
358368
}
359369
});
360370

translator.js

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,31 @@ const fs = require.main.require("fs");
55
const LANGUAGE_DIR = __dirname + '/public/languages/';
66

77
let languages, texts = null;
8-
loadTexts();
8+
9+
function replaceParams(message, params) {
10+
if (!params) return message;
11+
12+
return message.replace(/%(\d+)/gi, (match, captured) => { return params[captured]; });
13+
}
14+
15+
function languageSupported(language) {
16+
return languages.indexOf(language) !== -1;
17+
}
918

1019
let translator = {
11-
translate(text, language, defaultLanguage) {
20+
translate(text, params, language, defaultLanguage) {
1221
if (!languageSupported(language)) {
1322
language = defaultLanguage || 'en_GB';
1423
}
1524

1625
if (texts[language][text]) {
17-
return texts[language][text];
26+
return replaceParams(texts[language][text], params);
1827
} else {
1928
return text;
2029
}
2130
}
2231
};
2332

24-
function loadTexts() {
25-
languages = [];
26-
texts = [];
27-
fs.readdirSync(LANGUAGE_DIR).forEach(function (langFolder) {
28-
languages.push(langFolder);
29-
texts[langFolder] = loadLanguageTexts(langFolder);
30-
});
31-
}
32-
3333
function loadLanguageTexts(language) {
3434
let allPhrases = {};
3535
fs.readdirSync(LANGUAGE_DIR + language).forEach(function (phrasesFile) {
@@ -41,8 +41,14 @@ function loadLanguageTexts(language) {
4141
return allPhrases;
4242
}
4343

44-
function languageSupported(language) {
45-
return languages.indexOf(language) !== -1;
44+
function loadTexts() {
45+
languages = [];
46+
texts = [];
47+
fs.readdirSync(LANGUAGE_DIR).forEach(function (langFolder) {
48+
languages.push(langFolder);
49+
texts[langFolder] = loadLanguageTexts(langFolder);
50+
});
4651
}
4752

48-
module.exports = translator;
53+
loadTexts();
54+
module.exports = translator;

0 commit comments

Comments
 (0)