Merge branch 'master' into styleguide

v1.18.x
Julian Lam 8 years ago
commit e71bd7a27f

@ -39,8 +39,8 @@
"markAsUnreadForAll.success": "すべてのスレッドを未読にしました。", "markAsUnreadForAll.success": "すべてのスレッドを未読にしました。",
"mark_unread": "未読としてマーク", "mark_unread": "未読としてマーク",
"mark_unread.success": "スレッドは未読にマークされました。", "mark_unread.success": "スレッドは未読にマークされました。",
"watch": "ウッチ", "watch": "ウッチ",
"unwatch": "ウッチ解除", "unwatch": "ウッチ解除",
"watch.title": "新しい投稿の通知を受ける", "watch.title": "新しい投稿の通知を受ける",
"unwatch.title": "このスレッドの通知を停止します", "unwatch.title": "このスレッドの通知を停止します",
"share_this_post": "投稿を共有", "share_this_post": "投稿を共有",
@ -107,7 +107,7 @@
"more_guests": "ゲストさんが%1人", "more_guests": "ゲストさんが%1人",
"users_and_others": "%1と他は%2", "users_and_others": "%1と他は%2",
"sort_by": "並び替え", "sort_by": "並び替え",
"oldest_to_newest": "古い\bものから新しい順", "oldest_to_newest": "古いものから新しい順",
"newest_to_oldest": "新しいものから古い順", "newest_to_oldest": "新しいものから古い順",
"most_votes": "最も投票された順", "most_votes": "最も投票された順",
"most_posts": "最も投稿された順", "most_posts": "最も投稿された順",

@ -51,7 +51,7 @@
"change_password": "パスワードを変更", "change_password": "パスワードを変更",
"change_password_error": "無効のパスワード!", "change_password_error": "無効のパスワード!",
"change_password_error_wrong_current": "現在のパスワードは正しくありません!", "change_password_error_wrong_current": "現在のパスワードは正しくありません!",
"change_password_error_length": "パスワードは短い過ぎです!", "change_password_error_length": "パスワードが短過ぎです!",
"change_password_error_match": "パスワードは一致しません!", "change_password_error_match": "パスワードは一致しません!",
"change_password_error_privileges": "パスワードを更新する権限はありません。", "change_password_error_privileges": "パスワードを更新する権限はありません。",
"change_password_success": "パスワードを更新しました!", "change_password_success": "パスワードを更新しました!",
@ -79,7 +79,7 @@
"digest_monthly": "マンスリー", "digest_monthly": "マンスリー",
"send_chat_notifications": "オンラインではない時に新しいチャットメッセージを受信した場合、通知メールを送信する。", "send_chat_notifications": "オンラインではない時に新しいチャットメッセージを受信した場合、通知メールを送信する。",
"send_post_notifications": "購読中のスレッドに返信があった場合、メールで通知する。", "send_post_notifications": "購読中のスレッドに返信があった場合、メールで通知する。",
"settings-require-reload": "変化がありましてブラウザを更新する必要があります。ここを押して、ページ更新します。", "settings-require-reload": "設定を変更するにはページを更新する必要があります。ここを押して、ページ更新します。",
"has_no_follower": "フォロワーはまだいません :(", "has_no_follower": "フォロワーはまだいません :(",
"follows_no_one": "フォロー中のユーザーはまだいません :(", "follows_no_one": "フォロー中のユーザーはまだいません :(",
"has_no_posts": "このユーザーはまだ一つも投稿していません", "has_no_posts": "このユーザーはまだ一つも投稿していません",
@ -106,7 +106,7 @@
"delay_image_loading": "画像読み込みを遅延させる", "delay_image_loading": "画像読み込みを遅延させる",
"image_load_delay_help": "有効の場合、スレッド内の画像はスクロールされるまで読み込みません", "image_load_delay_help": "有効の場合、スレッド内の画像はスクロールされるまで読み込みません",
"scroll_to_my_post": "返信を投稿した後、新しい投稿を表示する", "scroll_to_my_post": "返信を投稿した後、新しい投稿を表示する",
"follow_topics_you_reply_to": "あなたが返信するスレッドをウォッチ", "follow_topics_you_reply_to": "あなたが返信したスレッドをウォッチする",
"follow_topics_you_create": "あなたが作成したスレッドをウォッチする", "follow_topics_you_create": "あなたが作成したスレッドをウォッチする",
"grouptitle": "グループ題名", "grouptitle": "グループ題名",
"no-group-title": "グループ名がありません", "no-group-title": "グループ名がありません",

@ -3,29 +3,29 @@
"title": "Site Başlığı", "title": "Site Başlığı",
"title.name": "Topluluk İsmi", "title.name": "Topluluk İsmi",
"title.show-in-header": "Show Site Title in Header", "title.show-in-header": "Show Site Title in Header",
"browser-title": "Browser Title", "browser-title": "Tarayıcı Başlığı",
"browser-title-help": "If no browser title is specified, the site title will be used", "browser-title-help": "If no browser title is specified, the site title will be used",
"title-layout": "Title Layout", "title-layout": "Title Layout",
"title-layout-help": "Define how the browser title will be structured ie. {pageTitle} | {browserTitle}", "title-layout-help": "Define how the browser title will be structured ie. {pageTitle} | {browserTitle}",
"description.placeholder": "A short description about your community", "description.placeholder": "A short description about your community",
"description": "Site Açıklaması", "description": "Site Açıklaması",
"keywords": "Site Keywords", "keywords": "Site Anahtar Kelimeler",
"keywords-placeholder": "Keywords describing your community, comma-separated", "keywords-placeholder": "Keywords describing your community, comma-separated",
"logo": "Site Logo", "logo": "Site Logo",
"logo.image": "Image", "logo.image": "Görsel",
"logo.image-placeholder": "Path to a logo to display on forum header", "logo.image-placeholder": "Path to a logo to display on forum header",
"logo.upload": "Yükle", "logo.upload": "Yükle",
"logo.url": "URL", "logo.url": "URL",
"logo.url-placeholder": "The URL of the site logo", "logo.url-placeholder": "The URL of the site logo",
"logo.url-help": "When the logo is clicked, send users to this address. If left blank, user will be sent to the forum index.", "logo.url-help": "When the logo is clicked, send users to this address. If left blank, user will be sent to the forum index.",
"logo.alt-text": "Alt Text", "logo.alt-text": "Alt Yazı",
"log.alt-text-placeholder": "Alternative text for accessibility", "log.alt-text-placeholder": "Alternative text for accessibility",
"favicon": "Favicon", "favicon": "Favicon",
"favicon.upload": "Yükle", "favicon.upload": "Yükle",
"touch-icon": "Homescreen/Touch Icon", "touch-icon": "Homescreen/Touch Icon",
"touch-icon.upload": "Yükle", "touch-icon.upload": "Yükle",
"touch-icon.help": "Recommended size and format: 192x192, PNG format only. If no touch icon is specified, NodeBB will fall back to using the favicon.", "touch-icon.help": "Recommended size and format: 192x192, PNG format only. If no touch icon is specified, NodeBB will fall back to using the favicon.",
"outgoing-links": "Outgoing Links", "outgoing-links": "Harici Bağlantılar",
"outgoing-links.warning-page": "Use Outgoing Links Warning Page", "outgoing-links.warning-page": "Use Outgoing Links Warning Page",
"search-default-sort-by": "Search default sort by" "search-default-sort-by": "Aramada varsayılan sıralama"
} }

@ -77,7 +77,6 @@ app.cacheBuster = null;
require(['taskbar', 'helpers', 'forum/pagination'], function (taskbar, helpers, pagination) { require(['taskbar', 'helpers', 'forum/pagination'], function (taskbar, helpers, pagination) {
taskbar.init(); taskbar.init();
// templates.js helpers
helpers.register(); helpers.register();
pagination.init(); pagination.init();

@ -1,7 +1,14 @@
'use strict';
(function (exports) { (function (exports) {
var helpers = {}; 'use strict';
/* globals define, utils, config */
// export the class if we are in a Node-like system.
if (typeof module === 'object' && module.exports === exports) {
exports = module.exports/* = SemVer*/;
}
var helpers = exports;
helpers.displayMenuItem = function (data, index) { helpers.displayMenuItem = function (data, index) {
var item = data.navigation[index]; var item = data.navigation[index];

@ -32,17 +32,18 @@ groupsController.getGroupsFromSet = function (uid, sort, start, stop, callback)
set = 'groups:visible:createtime'; set = 'groups:visible:createtime';
} }
groups.getGroupsFromSet(set, uid, start, stop, function (err, groups) { async.waterfall([
if (err) { function (next) {
return callback(err); groups.getGroupsFromSet(set, uid, start, stop, next);
} },
function (groupsData, next) {
callback(null, { next(null, {
groups: groups, groups: groupsData,
allowGroupCreation: parseInt(meta.config.allowGroupCreation, 10) === 1, allowGroupCreation: parseInt(meta.config.allowGroupCreation, 10) === 1,
nextStart: stop + 1, nextStart: stop + 1,
}); });
}); },
], callback);
}; };
groupsController.details = function (req, res, callback) { groupsController.details = function (req, res, callback) {

@ -298,7 +298,7 @@ topicsController.teaser = function (req, res, next) {
var tid = req.params.topic_id; var tid = req.params.topic_id;
if (!utils.isNumber(tid)) { if (!utils.isNumber(tid)) {
return next(new Error('[[error:invalid-tid]]')); return next();
} }
async.waterfall([ async.waterfall([

@ -30,7 +30,7 @@ uploadsController.upload = function (req, res, filesIterator) {
deleteTempFiles(files); deleteTempFiles(files);
if (err) { if (err) {
return res.status(500).send(err.message); return res.status(500).json({ path: req.path, error: err.message });
} }
res.status(200).send(images); res.status(200).send(images);
@ -136,26 +136,24 @@ uploadsController.uploadThumb = function (req, res, next) {
} }
uploadsController.upload(req, res, function (uploadedFile, next) { uploadsController.upload(req, res, function (uploadedFile, next) {
file.isFileTypeAllowed(uploadedFile.path, function (err) { async.waterfall([
if (err) { function (next) {
return next(err); if (!uploadedFile.type.match(/image./)) {
} return next(new Error('[[error:invalid-file]]'));
if (!uploadedFile.type.match(/image./)) {
return next(new Error('[[error:invalid-file]]'));
}
var size = parseInt(meta.config.topicThumbSize, 10) || 120;
image.resizeImage({
path: uploadedFile.path,
extension: path.extname(uploadedFile.name),
width: size,
height: size,
}, function (err) {
if (err) {
return next(err);
} }
file.isFileTypeAllowed(uploadedFile.path, next);
},
function (next) {
var size = parseInt(meta.config.topicThumbSize, 10) || 120;
image.resizeImage({
path: uploadedFile.path,
extension: path.extname(uploadedFile.name),
width: size,
height: size,
}, next);
},
function (next) {
if (plugins.hasListeners('filter:uploadImage')) { if (plugins.hasListeners('filter:uploadImage')) {
return plugins.fireHook('filter:uploadImage', { return plugins.fireHook('filter:uploadImage', {
image: uploadedFile, image: uploadedFile,
@ -164,8 +162,8 @@ uploadsController.uploadThumb = function (req, res, next) {
} }
uploadFile(req.uid, uploadedFile, next); uploadFile(req.uid, uploadedFile, next);
}); },
}); ], next);
}, next); }, next);
}; };
@ -184,12 +182,14 @@ uploadsController.uploadGroupCover = function (uid, uploadedFile, callback) {
}, callback); }, callback);
} }
file.isFileTypeAllowed(uploadedFile.path, function (err) { async.waterfall([
if (err) { function (next) {
return callback(err); file.isFileTypeAllowed(uploadedFile.path, next);
} },
saveFileToLocal(uploadedFile, callback); function (next) {
}); saveFileToLocal(uploadedFile, next);
},
], callback);
}; };
function uploadFile(uid, uploadedFile, callback) { function uploadFile(uid, uploadedFile, callback) {
@ -228,17 +228,18 @@ function saveFileToLocal(uploadedFile, callback) {
filename = Date.now() + '-' + validator.escape(filename.replace(path.extname(uploadedFile.name) || '', '')).substr(0, 255) + extension; filename = Date.now() + '-' + validator.escape(filename.replace(path.extname(uploadedFile.name) || '', '')).substr(0, 255) + extension;
file.saveFileToLocal(filename, 'files', uploadedFile.path, function (err, upload) { async.waterfall([
if (err) { function (next) {
return callback(err); file.saveFileToLocal(filename, 'files', uploadedFile.path, next);
} },
function (upload, next) {
callback(null, { next(null, {
url: nconf.get('relative_path') + upload.url, url: nconf.get('relative_path') + upload.url,
path: upload.path, path: upload.path,
name: uploadedFile.name, name: uploadedFile.name,
}); });
}); },
], callback);
} }
function deleteTempFiles(files) { function deleteTempFiles(files) {

@ -1,6 +1,6 @@
'use strict'; 'use strict';
var async = require('async'); var async = require('async');
var winston = require('winston'); var winston = require('winston');
var _ = require('underscore'); var _ = require('underscore');
@ -137,7 +137,6 @@ module.exports = function (Groups) {
}; };
Groups.acceptMembership = function (groupName, uid, callback) { Groups.acceptMembership = function (groupName, uid, callback) {
// Note: For simplicity, this method intentially doesn't check the caller uid for ownership!
async.waterfall([ async.waterfall([
async.apply(db.setRemove, 'group:' + groupName + ':pending', uid), async.apply(db.setRemove, 'group:' + groupName + ':pending', uid),
async.apply(db.setRemove, 'group:' + groupName + ':invited', uid), async.apply(db.setRemove, 'group:' + groupName + ':invited', uid),
@ -146,7 +145,6 @@ module.exports = function (Groups) {
}; };
Groups.rejectMembership = function (groupName, uid, callback) { Groups.rejectMembership = function (groupName, uid, callback) {
// Note: For simplicity, this method intentially doesn't check the caller uid for ownership!
async.parallel([ async.parallel([
async.apply(db.setRemove, 'group:' + groupName + ':pending', uid), async.apply(db.setRemove, 'group:' + groupName + ':pending', uid),
async.apply(db.setRemove, 'group:' + groupName + ':invited', uid), async.apply(db.setRemove, 'group:' + groupName + ':invited', uid),

@ -62,13 +62,14 @@ module.exports = function (privileges) {
}; };
privileges.topics.can = function (privilege, tid, uid, callback) { privileges.topics.can = function (privilege, tid, uid, callback) {
topics.getTopicField(tid, 'cid', function (err, cid) { async.waterfall([
if (err) { function (next) {
return callback(err); topics.getTopicField(tid, 'cid', next);
},
function (cid, next) {
privileges.categories.can(privilege, cid, uid, next);
} }
], callback);
privileges.categories.can(privilege, cid, uid, callback);
});
}; };
privileges.topics.filterTids = function (privilege, tids, uid, callback) { privileges.topics.filterTids = function (privilege, tids, uid, callback) {

@ -1,6 +1,6 @@
'use strict'; 'use strict';
var async = require('async'); var async = require('async');
var groups = require('../groups'); var groups = require('../groups');
var meta = require('../meta'); var meta = require('../meta');
@ -77,7 +77,7 @@ function isOwner(next) {
isAdmin: async.apply(user.isAdministrator, socket.uid), isAdmin: async.apply(user.isAdministrator, socket.uid),
isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName), isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName),
}, function (err, results) { }, function (err, results) {
if (err || (!isOwner && !results.isAdmin)) { if (err || (!results.isOwner && !results.isAdmin)) {
return callback(err || new Error('[[error:no-privileges]]')); return callback(err || new Error('[[error:no-privileges]]'));
} }
next(socket, data, callback); next(socket, data, callback);
@ -141,22 +141,25 @@ SocketGroups.issueMassInvite = isOwner(function (socket, data, callback) {
if (!data || !data.usernames || !data.groupName) { if (!data || !data.usernames || !data.groupName) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
var usernames = data.usernames.split(','); var usernames = String(data.usernames).split(',');
usernames = usernames.map(function (username) { usernames = usernames.map(function (username) {
return username && username.trim(); return username && username.trim();
}); });
user.getUidsByUsernames(usernames, function (err, uids) {
if (err) {
return callback(err);
}
uids = uids.filter(function (uid) {
return !!uid && parseInt(uid, 10);
});
async.eachSeries(uids, function (uid, next) { async.waterfall([
groups.invite(data.groupName, uid, next); function (next) {
}, callback); user.getUidsByUsernames(usernames, next);
}); },
function (uids, next) {
uids = uids.filter(function (uid) {
return !!uid && parseInt(uid, 10);
});
async.eachSeries(uids, function (uid, next) {
groups.invite(data.groupName, uid, next);
}, next);
},
], callback);
}); });
SocketGroups.rescindInvite = isOwner(function (socket, data, callback) { SocketGroups.rescindInvite = isOwner(function (socket, data, callback) {
@ -181,12 +184,14 @@ SocketGroups.kick = isOwner(function (socket, data, callback) {
return callback(new Error('[[error:cant-kick-self]]')); return callback(new Error('[[error:cant-kick-self]]'));
} }
groups.ownership.isOwner(data.uid, data.groupName, function (err, isOwner) { async.waterfall([
if (err) { function (next) {
return callback(err); groups.ownership.isOwner(data.uid, data.groupName, next);
} },
groups.kick(data.uid, data.groupName, isOwner, callback); function (isOwner, next) {
}); groups.kick(data.uid, data.groupName, isOwner, next);
},
], callback);
}); });
SocketGroups.create = function (socket, data, callback) { SocketGroups.create = function (socket, data, callback) {
@ -198,32 +203,19 @@ SocketGroups.create = function (socket, data, callback) {
return callback(new Error('[[error:invalid-group-name]]')); return callback(new Error('[[error:invalid-group-name]]'));
} }
data.ownerUid = socket.uid; data.ownerUid = socket.uid;
groups.create(data, callback); groups.create(data, callback);
}; };
SocketGroups.delete = function (socket, data, callback) { SocketGroups.delete = isOwner(function (socket, data, callback) {
if (data.groupName === 'administrators' || if (data.groupName === 'administrators' ||
data.groupName === 'registered-users' || data.groupName === 'registered-users' ||
data.groupName === 'Global Moderators') { data.groupName === 'Global Moderators') {
return callback(new Error('[[error:not-allowed]]')); return callback(new Error('[[error:not-allowed]]'));
} }
async.parallel({ groups.destroy(data.groupName, callback);
isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName), });
isAdmin: async.apply(user.isAdministrator, socket.uid),
}, function (err, checks) {
if (err) {
return callback(err);
}
if (!checks.isOwner && !checks.isAdmin) {
return callback(new Error('[[error:no-privileges]]'));
}
groups.destroy(data.groupName, callback);
});
};
SocketGroups.search = function (socket, data, callback) { SocketGroups.search = function (socket, data, callback) {
data.options = data.options || {}; data.options = data.options || {};
@ -241,7 +233,7 @@ SocketGroups.search = function (socket, data, callback) {
SocketGroups.loadMore = function (socket, data, callback) { SocketGroups.loadMore = function (socket, data, callback) {
if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) { if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) {
return callback(); return callback(new Error('[[error:invalid-data]]'));
} }
var groupsPerPage = 9; var groupsPerPage = 9;
@ -260,13 +252,17 @@ SocketGroups.loadMoreMembers = function (socket, data, callback) {
return callback(new Error('[[error:invalid-data]]')); return callback(new Error('[[error:invalid-data]]'));
} }
data.after = parseInt(data.after, 10); data.after = parseInt(data.after, 10);
user.getUsersFromSet('group:' + data.groupName + ':members', socket.uid, data.after, data.after + 9, function (err, users) { async.waterfall([
if (err) { function (next) {
return callback(err); user.getUsersFromSet('group:' + data.groupName + ':members', socket.uid, data.after, data.after + 9, next);
} },
function (users, next) {
callback(null, { users: users, nextStart: data.after + 10 }); next(null, {
}); users: users,
nextStart: data.after + 10,
});
},
], callback);
}; };
SocketGroups.cover = {}; SocketGroups.cover = {};

@ -432,7 +432,6 @@ describe('Groups', function () {
var socketGroups = require('../src/socket.io/groups'); var socketGroups = require('../src/socket.io/groups');
var meta = require('../src/meta'); var meta = require('../src/meta');
it('should error if data is null', function (done) { it('should error if data is null', function (done) {
socketGroups.before({ uid: 0 }, 'groups.join', null, function (err) { socketGroups.before({ uid: 0 }, 'groups.join', null, function (err) {
assert.equal(err.message, '[[error:invalid-data]]'); assert.equal(err.message, '[[error:invalid-data]]');
@ -535,17 +534,186 @@ describe('Groups', function () {
}); });
}); });
it('should accept membership of user', function (done) { it('should reject membership of user', function (done) {
socketGroups.accept({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { socketGroups.reject({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) {
assert.ifError(err); assert.ifError(err);
Groups.isMember(testUid, 'PrivateCanJoin', function (err, isMember) { Groups.isInvited(testUid, 'PrivateCanJoin', function (err, invited) {
assert.ifError(err); assert.ifError(err);
assert(isMember); assert.equal(invited, false);
done(); done();
}); });
}); });
}); });
it('should error if not owner or admin', function (done) {
socketGroups.accept({ uid: 0 }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) {
assert.equal(err.message, '[[error:no-privileges]]');
done();
});
});
it('should accept membership of user', function (done) {
socketGroups.join({ uid: testUid }, { groupName: 'PrivateCanJoin' }, function (err) {
assert.ifError(err);
socketGroups.accept({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) {
assert.ifError(err);
Groups.isMember(testUid, 'PrivateCanJoin', function (err, isMember) {
assert.ifError(err);
assert(isMember);
done();
});
});
});
});
it('should reject/accept all memberships requests', function (done) {
function requestMembership(uids, callback) {
async.series([
function (next) {
socketGroups.join({ uid: uids.uid1 }, { groupName: 'PrivateCanJoin' }, next);
},
function (next) {
socketGroups.join({ uid: uids.uid2 }, { groupName: 'PrivateCanJoin' }, next);
},
], function (err) {
callback(err);
});
}
var uids;
async.waterfall([
function (next) {
async.parallel({
uid1: function (next) {
User.create({ username: 'groupuser1' }, next);
},
uid2: function (next) {
User.create({ username: 'groupuser2' }, next);
},
}, next);
},
function (results, next) {
uids = results;
requestMembership(results, next);
},
function (next) {
socketGroups.rejectAll({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, next);
},
function (next) {
Groups.getPending('PrivateCanJoin', next);
},
function (pending, next) {
assert.equal(pending.length, 0);
requestMembership(uids, next);
},
function (next) {
socketGroups.acceptAll({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, next);
},
function (next) {
Groups.isMembers([uids.uid1, uids.uid2], 'PrivateCanJoin', next);
},
function (isMembers, next) {
assert(isMembers[0]);
assert(isMembers[1]);
next();
},
], function (err) {
done(err);
});
});
it('should issue invite to user', function (done) {
User.create({ username: 'invite1' }, function (err, uid) {
assert.ifError(err);
socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) {
assert.ifError(err);
Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) {
assert.ifError(err);
assert(isInvited);
done();
});
});
});
});
it('should fail with invalid data', function (done) {
socketGroups.issueMassInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', usernames: null }, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should issue mass invite to users', function (done) {
User.create({ username: 'invite2' }, function (err, uid) {
assert.ifError(err);
socketGroups.issueMassInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', usernames: 'invite1, invite2' }, function (err) {
assert.ifError(err);
Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) {
assert.ifError(err);
assert(isInvited);
done();
});
});
});
});
it('should rescind invite', function (done) {
User.create({ username: 'invite3' }, function (err, uid) {
assert.ifError(err);
socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) {
assert.ifError(err);
socketGroups.rescindInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) {
assert.ifError(err);
Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) {
assert.ifError(err);
assert(!isInvited);
done();
});
});
});
});
});
it('should error if user is not invited', function (done) {
socketGroups.acceptInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin' }, function (err) {
assert.equal(err.message, '[[error:not-invited]]');
done();
});
});
it('should accept invite', function (done) {
User.create({ username: 'invite4' }, function (err, uid) {
assert.ifError(err);
socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) {
assert.ifError(err);
socketGroups.acceptInvite({ uid: uid }, { groupName: 'PrivateCanJoin' }, function (err) {
assert.ifError(err);
Groups.isMember(uid, 'PrivateCanJoin', function (err, isMember) {
assert.ifError(err);
assert(isMember);
done();
});
});
});
});
});
it('should reject invite', function (done) {
User.create({ username: 'invite5' }, function (err, uid) {
assert.ifError(err);
socketGroups.issueInvite({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: uid }, function (err) {
assert.ifError(err);
socketGroups.rejectInvite({ uid: uid }, { groupName: 'PrivateCanJoin' }, function (err) {
assert.ifError(err);
Groups.isInvited(uid, 'PrivateCanJoin', function (err, isInvited) {
assert.ifError(err);
assert(!isInvited);
done();
});
});
});
});
});
it('should grant ownership to user', function (done) { it('should grant ownership to user', function (done) {
socketGroups.grant({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { socketGroups.grant({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) {
assert.ifError(err); assert.ifError(err);
@ -568,6 +736,13 @@ describe('Groups', function () {
}); });
}); });
it('should fail to kick user with invalid data', function (done) {
socketGroups.kick({ uid: adminUid }, { groupName: 'PrivateCanJoin', uid: adminUid }, function (err) {
assert.equal(err.message, '[[error:cant-kick-self]]');
done();
});
});
it('should kick user from group', function (done) { it('should kick user from group', function (done) {
socketGroups.kick({ uid: adminUid }, { groupName: 'PrivateCanJoin', uid: testUid }, function (err) { socketGroups.kick({ uid: adminUid }, { groupName: 'PrivateCanJoin', uid: testUid }, function (err) {
assert.ifError(err); assert.ifError(err);
@ -578,6 +753,131 @@ describe('Groups', function () {
}); });
}); });
}); });
it('should fail to create group with invalid data', function (done) {
socketGroups.create({ uid: 0 }, {}, function (err) {
assert.equal(err.message, '[[error:no-privileges]]');
done();
});
});
it('should fail to create group if group creation is disabled', function (done) {
var oldValue = meta.config.allowGroupCreation;
meta.config.allowGroupCreation = 0;
socketGroups.create({ uid: 1 }, {}, function (err) {
assert.equal(err.message, '[[error:group-creation-disabled]]');
meta.config.allowGroupCreation = oldValue;
done();
});
});
it('should fail to create group if name is privilege group', function (done) {
var oldValue = meta.config.allowGroupCreation;
meta.config.allowGroupCreation = 1;
socketGroups.create({ uid: 1 }, { name: 'cid:1:privileges:groups:find' }, function (err) {
assert.equal(err.message, '[[error:invalid-group-name]]');
meta.config.allowGroupCreation = oldValue;
done();
});
});
it('should create/update group', function (done) {
var oldValue = meta.config.allowGroupCreation;
meta.config.allowGroupCreation = 1;
socketGroups.create({ uid: adminUid }, { name: 'createupdategroup' }, function (err, groupData) {
meta.config.allowGroupCreation = oldValue;
assert.ifError(err);
assert(groupData);
var data = {
groupName: 'createupdategroup',
values: {
name: 'renamedupdategroup',
description: 'cat group',
userTitle: 'cats',
userTitleEnabled: 1,
disableJoinRequests: 1,
hidden: 1,
private: 0,
},
};
socketGroups.update({ uid: adminUid }, data, function (err) {
assert.ifError(err);
Groups.get('renamedupdategroup', {}, function (err, groupData) {
assert.ifError(err);
assert.equal(groupData.name, 'renamedupdategroup');
assert.equal(groupData.userTitle, 'cats');
assert.equal(groupData.description, 'cat group');
assert.equal(groupData.hidden, true);
assert.equal(groupData.disableJoinRequests, true);
assert.equal(groupData.private, false);
done();
});
});
});
});
it('should delete group', function (done) {
socketGroups.delete({ uid: adminUid }, { groupName: 'renamedupdategroup' }, function (err) {
assert.ifError(err);
Groups.exists('renamedupdategroup', function (err, exists) {
assert.ifError(err);
assert(!exists);
done();
});
});
});
it('should fail to delete group if name is special', function (done) {
socketGroups.delete({ uid: adminUid }, { groupName: 'administrators' }, function (err) {
assert.equal(err.message, '[[error:not-allowed]]');
done();
});
});
it('should fail to delete group if name is special', function (done) {
socketGroups.delete({ uid: adminUid }, { groupName: 'registered-users' }, function (err) {
assert.equal(err.message, '[[error:not-allowed]]');
done();
});
});
it('should fail to delete group if name is special', function (done) {
socketGroups.delete({ uid: adminUid }, { groupName: 'Global Moderators' }, function (err) {
assert.equal(err.message, '[[error:not-allowed]]');
done();
});
});
it('should fail to load more groups with invalid data', function (done) {
socketGroups.loadMore({ uid: adminUid }, {}, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should load more groups', function (done) {
socketGroups.loadMore({ uid: adminUid }, { after: 0, sort: 'count' }, function (err, data) {
assert.ifError(err);
assert(Array.isArray(data.groups));
done();
});
});
it('should fail to load more members with invalid data', function (done) {
socketGroups.loadMoreMembers({ uid: adminUid }, {}, function (err) {
assert.equal(err.message, '[[error:invalid-data]]');
done();
});
});
it('should load more members', function (done) {
socketGroups.loadMoreMembers({ uid: adminUid }, { after: 0, groupName: 'PrivateCanJoin' }, function (err, data) {
assert.ifError(err);
assert(Array.isArray(data.users));
done();
});
});
}); });
describe('admin socket methods', function () { describe('admin socket methods', function () {
@ -815,6 +1115,13 @@ describe('Groups', function () {
}); });
}); });
it('should fail to remove cover if not logged in', function (done) {
socketGroups.cover.remove({ uid: 0 }, { groupName: 'Test' }, function (err) {
assert.equal(err.message, '[[error:no-privileges]]');
done();
});
});
it('should fail to remove cover if not owner', function (done) { it('should fail to remove cover if not owner', function (done) {
socketGroups.cover.remove({ uid: regularUid }, { groupName: 'Test' }, function (err) { socketGroups.cover.remove({ uid: regularUid }, { groupName: 'Test' }, function (err) {
assert.equal(err.message, '[[error:no-privileges]]'); assert.equal(err.message, '[[error:no-privileges]]');

@ -0,0 +1,55 @@
'use strict';
var async = require('async');
var assert = require('assert');
var db = require('./mocks/databasemock');
var helpers = require('../public/src/modules/helpers');
describe('helpers', function () {
it('should return false if item doesn\'t exist', function (done) {
var flag = helpers.displayMenuItem({navigation: []}, 0);
assert(!flag);
done();
});
it('should return false if route is /users and privateUserInfo is on and user is not logged in', function (done) {
var flag = helpers.displayMenuItem({
navigation: [{route: '/users'}],
privateUserInfo: true,
config: {
loggedIn: false
}
}, 0);
assert(!flag);
done();
});
it('should return false if route is /tags and privateTagListing is on and user is not logged in', function (done) {
var flag = helpers.displayMenuItem({
navigation: [{route: '/tags'}],
privateTagListing: true,
config: {
loggedIn: false
}
}, 0);
assert(!flag);
done();
});
it('should stringify object', function (done) {
var str = helpers.stringify({a: 'herp < derp > and & quote "'});
assert.equal(str, '{&quot;a&quot;:&quot;herp &lt; derp &gt; and &amp; quote \\&quot;&quot;}');
done();
});
it('should escape html', function (done) {
var str = helpers.escape('gdkfhgk < some > and &');
assert.equal(str, 'gdkfhgk &lt; some &gt; and &amp;');
done();
});
});

@ -10,6 +10,7 @@ var topics = require('../src/topics');
var categories = require('../src/categories'); var categories = require('../src/categories');
var User = require('../src/user'); var User = require('../src/user');
var groups = require('../src/groups'); var groups = require('../src/groups');
var helpers = require('./helpers');
var socketPosts = require('../src/socket.io/posts'); var socketPosts = require('../src/socket.io/posts');
describe('Topic\'s', function () { describe('Topic\'s', function () {
@ -19,7 +20,7 @@ describe('Topic\'s', function () {
before(function (done) { before(function (done) {
groups.resetCache(); groups.resetCache();
User.create({ username: 'admin' }, function (err, uid) { User.create({ username: 'admin', password: '123456' }, function (err, uid) {
if (err) { if (err) {
return done(err); return done(err);
} }
@ -669,26 +670,176 @@ describe('Topic\'s', function () {
}); });
}); });
it('should load topic', function (done) { describe('controller', function () {
topics.post({ var request = require('request');
uid: topic.userId, var topicData;
title: 'topic for controller test',
content: 'topic content', before(function (done) {
cid: topic.categoryId, topics.post({
thumb: 'http://i.imgur.com/64iBdBD.jpg', uid: topic.userId,
}, function (err, result) { title: 'topic for controller test',
assert.ifError(err); content: 'topic content',
assert.ok(result); cid: topic.categoryId,
var request = require('request'); thumb: 'http://i.imgur.com/64iBdBD.jpg',
request(nconf.get('url') + '/topic/' + result.topicData.slug, function (err, response, body) { }, function (err, result) {
assert.ifError(err);
assert.ok(result);
topicData = result.topicData;
done();
});
});
it('should load topic', function (done) {
request(nconf.get('url') + '/topic/' + topicData.slug, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 200);
assert(body);
done();
});
});
it('should 404 if post index is invalid', function (done) {
request(nconf.get('url') + '/topic/' + topicData.slug + '/derp', function (err, response) {
assert.ifError(err);
assert.equal(response.statusCode, 404);
done();
});
});
it('should 404 if topic does not exist', function (done) {
request(nconf.get('url') + '/topic/123123/does-not-exist', function (err, response) {
assert.ifError(err);
assert.equal(response.statusCode, 404);
done();
});
});
it('should 401 if not allowed to read as guest', function (done) {
var privileges = require('../src/privileges');
privileges.categories.rescind(['read'], topicData.cid, 'guests', function (err) {
assert.ifError(err);
request(nconf.get('url') + '/api/topic/' + topicData.slug, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 401);
assert(body);
privileges.categories.give(['read'], topicData.cid, 'guests', done);
});
});
});
it('should redirect to correct topic if slug is missing', function (done) {
request(nconf.get('url') + '/topic/' + topicData.tid + '/herpderp/1?page=2', function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 200);
assert(body);
done();
});
});
it('should redirect if post index is out of range', function (done) {
request(nconf.get('url') + '/api/topic/' + topicData.slug + '/-1', function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 308);
assert.equal(body, '"/topic/13/topic-for-controller-test"');
done();
});
});
it('should 404 if page is out of bounds', function (done) {
var meta = require('../src/meta');
meta.config.usePagination = 1;
request(nconf.get('url') + '/topic/' + topicData.slug + '?page=100', function (err, response) {
assert.ifError(err);
assert.equal(response.statusCode, 404);
done();
});
});
it('should mark topic read', function (done) {
helpers.loginUser('admin', '123456', function (err, jar) {
assert.ifError(err);
request(nconf.get('url') + '/topic/' + topicData.slug, {
jar: jar,
}, function (err, res) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
topics.hasReadTopics([topicData.tid], adminUid, function (err, hasRead) {
assert.ifError(err);
assert.equal(hasRead[0], true);
done();
});
});
});
});
it('should 404 if tid is not a number', function (done) {
request(nconf.get('url') + '/api/topic/teaser/nan', { json: true }, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 404);
done();
});
});
it('should 403 if cant read', function (done) {
request(nconf.get('url') + '/api/topic/teaser/' + 123123, { json: true }, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 403);
assert.equal(body, '[[error:no-privileges]]');
done();
});
});
it('should load topic teaser', function (done) {
request(nconf.get('url') + '/api/topic/teaser/' + topicData.tid, { json: true }, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 200);
assert(body);
assert.equal(body.tid, topicData.tid);
assert.equal(body.content, 'topic content');
assert(body.user);
assert(body.topic);
assert(body.category);
done();
});
});
it('should 404 if tid is not a number', function (done) {
request(nconf.get('url') + '/api/topic/pagination/nan', { json: true }, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 404);
done();
});
});
it('should 404 if tid does not exist', function (done) {
request(nconf.get('url') + '/api/topic/pagination/1231231', { json: true }, function (err, response, body) {
assert.ifError(err);
assert.equal(response.statusCode, 404);
done();
});
});
it('should load pagination', function (done) {
request(nconf.get('url') + '/api/topic/pagination/' + topicData.tid, { json: true }, function (err, response, body) {
assert.ifError(err); assert.ifError(err);
assert.equal(response.statusCode, 200); assert.equal(response.statusCode, 200);
assert(body); assert(body);
assert.deepEqual(body, {
prev: { page: 1, active: false },
next: { page: 1, active: false },
rel: [],
pages: [],
currentPage: 1,
pageCount: 1,
});
done(); done();
}); });
}); });
}); });
describe('infinitescroll', function () { describe('infinitescroll', function () {
var socketTopics = require('../src/socket.io/topics'); var socketTopics = require('../src/socket.io/topics');
var tid; var tid;

@ -87,6 +87,20 @@ describe('Upload Controllers', function () {
}); });
}); });
it('should resize and upload an image to a post', function (done) {
var oldValue = meta.config.maximumImageWidth;
meta.config.maximumImageWidth = 10;
helpers.uploadFile(nconf.get('url') + '/api/post/upload', path.join(__dirname, '../test/files/test.png'), { cid: cid }, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
assert(body[0].path);
assert(body[0].url);
meta.config.maximumImageWidth = oldValue;
done();
});
});
it('should upload a file to a post', function (done) { it('should upload a file to a post', function (done) {
meta.config.allowFileUploads = 1; meta.config.allowFileUploads = 1;
@ -99,6 +113,37 @@ describe('Upload Controllers', function () {
done(); done();
}); });
}); });
it('should fail if topic thumbs are disabled', function (done) {
helpers.uploadFile(nconf.get('url') + '/api/topic/thumb/upload', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 500);
assert.equal(body.error, '[[error:topic-thumbnails-are-disabled]]');
done();
});
});
it('should fail if file is not image', function (done) {
meta.config.allowTopicsThumbnail = 1;
helpers.uploadFile(nconf.get('url') + '/api/topic/thumb/upload', path.join(__dirname, '../test/files/503.html'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 500);
assert.equal(body.error, '[[error:invalid-file]]');
done();
});
});
it('should upload topic thumb', function (done) {
meta.config.allowTopicsThumbnail = 1;
helpers.uploadFile(nconf.get('url') + '/api/topic/thumb/upload', path.join(__dirname, '../test/files/test.png'), {}, jar, csrf_token, function (err, res, body) {
assert.ifError(err);
assert.equal(res.statusCode, 200);
assert(Array.isArray(body));
assert(body[0].path);
assert(body[0].url);
done();
});
});
}); });

Loading…
Cancel
Save