mirror of
https://github.com/NodeBB/NodeBB.git
synced 2025-10-30 02:25:55 +01:00
Merge branch 'master' into styleguide
This commit is contained in:
@@ -39,8 +39,8 @@
|
||||
"markAsUnreadForAll.success": "すべてのスレッドを未読にしました。",
|
||||
"mark_unread": "未読としてマーク",
|
||||
"mark_unread.success": "スレッドは未読にマークされました。",
|
||||
"watch": "ウオッチ",
|
||||
"unwatch": "ウオッチ解除",
|
||||
"watch": "ウォッチ",
|
||||
"unwatch": "ウォッチ解除",
|
||||
"watch.title": "新しい投稿の通知を受ける",
|
||||
"unwatch.title": "このスレッドの通知を停止します",
|
||||
"share_this_post": "投稿を共有",
|
||||
@@ -107,7 +107,7 @@
|
||||
"more_guests": "ゲストさんが%1人",
|
||||
"users_and_others": "%1と他は%2",
|
||||
"sort_by": "並び替え",
|
||||
"oldest_to_newest": "古い\bものから新しい順",
|
||||
"oldest_to_newest": "古いものから新しい順",
|
||||
"newest_to_oldest": "新しいものから古い順",
|
||||
"most_votes": "最も投票された順",
|
||||
"most_posts": "最も投稿された順",
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
"change_password": "パスワードを変更",
|
||||
"change_password_error": "無効のパスワード!",
|
||||
"change_password_error_wrong_current": "現在のパスワードは正しくありません!",
|
||||
"change_password_error_length": "パスワードは短い過ぎです!",
|
||||
"change_password_error_length": "パスワードが短過ぎです!",
|
||||
"change_password_error_match": "パスワードは一致しません!",
|
||||
"change_password_error_privileges": "パスワードを更新する権限はありません。",
|
||||
"change_password_success": "パスワードを更新しました!",
|
||||
@@ -79,7 +79,7 @@
|
||||
"digest_monthly": "マンスリー",
|
||||
"send_chat_notifications": "オンラインではない時に新しいチャットメッセージを受信した場合、通知メールを送信する。",
|
||||
"send_post_notifications": "購読中のスレッドに返信があった場合、メールで通知する。",
|
||||
"settings-require-reload": "変化がありましてブラウザを更新する必要があります。ここを押して、ページ更新します。",
|
||||
"settings-require-reload": "設定を変更するにはページを更新する必要があります。ここを押して、ページを更新します。",
|
||||
"has_no_follower": "フォロワーはまだいません :(",
|
||||
"follows_no_one": "フォロー中のユーザーはまだいません :(",
|
||||
"has_no_posts": "このユーザーはまだ一つも投稿していません",
|
||||
@@ -106,7 +106,7 @@
|
||||
"delay_image_loading": "画像読み込みを遅延させる",
|
||||
"image_load_delay_help": "有効の場合、スレッド内の画像はスクロールされるまで読み込みません",
|
||||
"scroll_to_my_post": "返信を投稿した後、新しい投稿を表示する",
|
||||
"follow_topics_you_reply_to": "あなたが返信するスレッドをウォッチ",
|
||||
"follow_topics_you_reply_to": "あなたが返信したスレッドをウォッチする",
|
||||
"follow_topics_you_create": "あなたが作成したスレッドをウォッチする",
|
||||
"grouptitle": "グループ題名",
|
||||
"no-group-title": "グループ名がありません",
|
||||
|
||||
@@ -3,29 +3,29 @@
|
||||
"title": "Site Başlığı",
|
||||
"title.name": "Topluluk İsmi",
|
||||
"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",
|
||||
"title-layout": "Title Layout",
|
||||
"title-layout-help": "Define how the browser title will be structured ie. {pageTitle} | {browserTitle}",
|
||||
"description.placeholder": "A short description about your community",
|
||||
"description": "Site Açıklaması",
|
||||
"keywords": "Site Keywords",
|
||||
"keywords": "Site Anahtar Kelimeler",
|
||||
"keywords-placeholder": "Keywords describing your community, comma-separated",
|
||||
"logo": "Site Logo",
|
||||
"logo.image": "Image",
|
||||
"logo.image": "Görsel",
|
||||
"logo.image-placeholder": "Path to a logo to display on forum header",
|
||||
"logo.upload": "Yükle",
|
||||
"logo.url": "URL",
|
||||
"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.alt-text": "Alt Text",
|
||||
"logo.alt-text": "Alt Yazı",
|
||||
"log.alt-text-placeholder": "Alternative text for accessibility",
|
||||
"favicon": "Favicon",
|
||||
"favicon.upload": "Yükle",
|
||||
"touch-icon": "Homescreen/Touch Icon",
|
||||
"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.",
|
||||
"outgoing-links": "Outgoing Links",
|
||||
"outgoing-links": "Harici Bağlantılar",
|
||||
"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) {
|
||||
taskbar.init();
|
||||
|
||||
// templates.js helpers
|
||||
helpers.register();
|
||||
|
||||
pagination.init();
|
||||
|
||||
@@ -1,7 +1,14 @@
|
||||
(function (exports) {
|
||||
'use strict';
|
||||
|
||||
(function (exports) {
|
||||
var helpers = {};
|
||||
/* 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) {
|
||||
var item = data.navigation[index];
|
||||
|
||||
@@ -32,17 +32,18 @@ groupsController.getGroupsFromSet = function (uid, sort, start, stop, callback)
|
||||
set = 'groups:visible:createtime';
|
||||
}
|
||||
|
||||
groups.getGroupsFromSet(set, uid, start, stop, function (err, groups) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
groups: groups,
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
groups.getGroupsFromSet(set, uid, start, stop, next);
|
||||
},
|
||||
function (groupsData, next) {
|
||||
next(null, {
|
||||
groups: groupsData,
|
||||
allowGroupCreation: parseInt(meta.config.allowGroupCreation, 10) === 1,
|
||||
nextStart: stop + 1,
|
||||
});
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
groupsController.details = function (req, res, callback) {
|
||||
|
||||
@@ -298,7 +298,7 @@ topicsController.teaser = function (req, res, next) {
|
||||
var tid = req.params.topic_id;
|
||||
|
||||
if (!utils.isNumber(tid)) {
|
||||
return next(new Error('[[error:invalid-tid]]'));
|
||||
return next();
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
|
||||
@@ -30,7 +30,7 @@ uploadsController.upload = function (req, res, filesIterator) {
|
||||
deleteTempFiles(files);
|
||||
|
||||
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);
|
||||
@@ -136,26 +136,24 @@ uploadsController.uploadThumb = function (req, res, next) {
|
||||
}
|
||||
|
||||
uploadsController.upload(req, res, function (uploadedFile, next) {
|
||||
file.isFileTypeAllowed(uploadedFile.path, function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
if (!uploadedFile.type.match(/image./)) {
|
||||
return next(new Error('[[error:invalid-file]]'));
|
||||
}
|
||||
|
||||
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,
|
||||
}, function (err) {
|
||||
if (err) {
|
||||
return next(err);
|
||||
}
|
||||
|
||||
}, next);
|
||||
},
|
||||
function (next) {
|
||||
if (plugins.hasListeners('filter:uploadImage')) {
|
||||
return plugins.fireHook('filter:uploadImage', {
|
||||
image: uploadedFile,
|
||||
@@ -164,8 +162,8 @@ uploadsController.uploadThumb = function (req, res, next) {
|
||||
}
|
||||
|
||||
uploadFile(req.uid, uploadedFile, next);
|
||||
});
|
||||
});
|
||||
},
|
||||
], next);
|
||||
}, next);
|
||||
};
|
||||
|
||||
@@ -184,12 +182,14 @@ uploadsController.uploadGroupCover = function (uid, uploadedFile, callback) {
|
||||
}, callback);
|
||||
}
|
||||
|
||||
file.isFileTypeAllowed(uploadedFile.path, function (err) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
saveFileToLocal(uploadedFile, callback);
|
||||
});
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
file.isFileTypeAllowed(uploadedFile.path, next);
|
||||
},
|
||||
function (next) {
|
||||
saveFileToLocal(uploadedFile, next);
|
||||
},
|
||||
], 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;
|
||||
|
||||
file.saveFileToLocal(filename, 'files', uploadedFile.path, function (err, upload) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, {
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
file.saveFileToLocal(filename, 'files', uploadedFile.path, next);
|
||||
},
|
||||
function (upload, next) {
|
||||
next(null, {
|
||||
url: nconf.get('relative_path') + upload.url,
|
||||
path: upload.path,
|
||||
name: uploadedFile.name,
|
||||
});
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
}
|
||||
|
||||
function deleteTempFiles(files) {
|
||||
|
||||
@@ -137,7 +137,6 @@ module.exports = function (Groups) {
|
||||
};
|
||||
|
||||
Groups.acceptMembership = function (groupName, uid, callback) {
|
||||
// Note: For simplicity, this method intentially doesn't check the caller uid for ownership!
|
||||
async.waterfall([
|
||||
async.apply(db.setRemove, 'group:' + groupName + ':pending', uid),
|
||||
async.apply(db.setRemove, 'group:' + groupName + ':invited', uid),
|
||||
@@ -146,7 +145,6 @@ module.exports = function (Groups) {
|
||||
};
|
||||
|
||||
Groups.rejectMembership = function (groupName, uid, callback) {
|
||||
// Note: For simplicity, this method intentially doesn't check the caller uid for ownership!
|
||||
async.parallel([
|
||||
async.apply(db.setRemove, 'group:' + groupName + ':pending', 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) {
|
||||
topics.getTopicField(tid, 'cid', function (err, cid) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
topics.getTopicField(tid, 'cid', next);
|
||||
},
|
||||
function (cid, next) {
|
||||
privileges.categories.can(privilege, cid, uid, next);
|
||||
}
|
||||
|
||||
privileges.categories.can(privilege, cid, uid, callback);
|
||||
});
|
||||
], callback);
|
||||
};
|
||||
|
||||
privileges.topics.filterTids = function (privilege, tids, uid, callback) {
|
||||
|
||||
@@ -77,7 +77,7 @@ function isOwner(next) {
|
||||
isAdmin: async.apply(user.isAdministrator, socket.uid),
|
||||
isOwner: async.apply(groups.ownership.isOwner, socket.uid, data.groupName),
|
||||
}, function (err, results) {
|
||||
if (err || (!isOwner && !results.isAdmin)) {
|
||||
if (err || (!results.isOwner && !results.isAdmin)) {
|
||||
return callback(err || new Error('[[error:no-privileges]]'));
|
||||
}
|
||||
next(socket, data, callback);
|
||||
@@ -141,22 +141,25 @@ SocketGroups.issueMassInvite = isOwner(function (socket, data, callback) {
|
||||
if (!data || !data.usernames || !data.groupName) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
var usernames = data.usernames.split(',');
|
||||
var usernames = String(data.usernames).split(',');
|
||||
usernames = usernames.map(function (username) {
|
||||
return username && username.trim();
|
||||
});
|
||||
user.getUidsByUsernames(usernames, function (err, uids) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
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);
|
||||
}, callback);
|
||||
});
|
||||
}, next);
|
||||
},
|
||||
], 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]]'));
|
||||
}
|
||||
|
||||
groups.ownership.isOwner(data.uid, data.groupName, function (err, isOwner) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
groups.kick(data.uid, data.groupName, isOwner, callback);
|
||||
});
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
groups.ownership.isOwner(data.uid, data.groupName, next);
|
||||
},
|
||||
function (isOwner, next) {
|
||||
groups.kick(data.uid, data.groupName, isOwner, next);
|
||||
},
|
||||
], 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]]'));
|
||||
}
|
||||
|
||||
|
||||
data.ownerUid = socket.uid;
|
||||
groups.create(data, callback);
|
||||
};
|
||||
|
||||
SocketGroups.delete = function (socket, data, callback) {
|
||||
SocketGroups.delete = isOwner(function (socket, data, callback) {
|
||||
if (data.groupName === 'administrators' ||
|
||||
data.groupName === 'registered-users' ||
|
||||
data.groupName === 'Global Moderators') {
|
||||
return callback(new Error('[[error:not-allowed]]'));
|
||||
}
|
||||
|
||||
async.parallel({
|
||||
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) {
|
||||
data.options = data.options || {};
|
||||
@@ -241,7 +233,7 @@ SocketGroups.search = function (socket, data, callback) {
|
||||
|
||||
SocketGroups.loadMore = function (socket, data, callback) {
|
||||
if (!data.sort || !utils.isNumber(data.after) || parseInt(data.after, 10) < 0) {
|
||||
return callback();
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
|
||||
var groupsPerPage = 9;
|
||||
@@ -260,13 +252,17 @@ SocketGroups.loadMoreMembers = function (socket, data, callback) {
|
||||
return callback(new Error('[[error:invalid-data]]'));
|
||||
}
|
||||
data.after = parseInt(data.after, 10);
|
||||
user.getUsersFromSet('group:' + data.groupName + ':members', socket.uid, data.after, data.after + 9, function (err, users) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, { users: users, nextStart: data.after + 10 });
|
||||
async.waterfall([
|
||||
function (next) {
|
||||
user.getUsersFromSet('group:' + data.groupName + ':members', socket.uid, data.after, data.after + 9, next);
|
||||
},
|
||||
function (users, next) {
|
||||
next(null, {
|
||||
users: users,
|
||||
nextStart: data.after + 10,
|
||||
});
|
||||
},
|
||||
], callback);
|
||||
};
|
||||
|
||||
SocketGroups.cover = {};
|
||||
|
||||
309
test/groups.js
309
test/groups.js
@@ -432,7 +432,6 @@ describe('Groups', function () {
|
||||
var socketGroups = require('../src/socket.io/groups');
|
||||
var meta = require('../src/meta');
|
||||
|
||||
|
||||
it('should error if data is null', function (done) {
|
||||
socketGroups.before({ uid: 0 }, 'groups.join', null, function (err) {
|
||||
assert.equal(err.message, '[[error:invalid-data]]');
|
||||
@@ -535,7 +534,27 @@ describe('Groups', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should reject membership of user', function (done) {
|
||||
socketGroups.reject({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) {
|
||||
assert.ifError(err);
|
||||
Groups.isInvited(testUid, 'PrivateCanJoin', function (err, invited) {
|
||||
assert.ifError(err);
|
||||
assert.equal(invited, false);
|
||||
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) {
|
||||
@@ -545,6 +564,155 @@ describe('Groups', function () {
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
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) {
|
||||
socketGroups.grant({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (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) {
|
||||
socketGroups.kick({ uid: adminUid }, { groupName: 'PrivateCanJoin', uid: testUid }, function (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 () {
|
||||
@@ -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) {
|
||||
socketGroups.cover.remove({ uid: regularUid }, { groupName: 'Test' }, function (err) {
|
||||
assert.equal(err.message, '[[error:no-privileges]]');
|
||||
|
||||
55
test/template-helpers.js
Normal file
55
test/template-helpers.js
Normal file
@@ -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, '{"a":"herp < derp > and & quote \\""}');
|
||||
done();
|
||||
});
|
||||
|
||||
it('should escape html', function (done) {
|
||||
var str = helpers.escape('gdkfhgk < some > and &');
|
||||
assert.equal(str, 'gdkfhgk < some > and &');
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
159
test/topics.js
159
test/topics.js
@@ -10,6 +10,7 @@ var topics = require('../src/topics');
|
||||
var categories = require('../src/categories');
|
||||
var User = require('../src/user');
|
||||
var groups = require('../src/groups');
|
||||
var helpers = require('./helpers');
|
||||
var socketPosts = require('../src/socket.io/posts');
|
||||
|
||||
describe('Topic\'s', function () {
|
||||
@@ -19,7 +20,7 @@ describe('Topic\'s', function () {
|
||||
|
||||
before(function (done) {
|
||||
groups.resetCache();
|
||||
User.create({ username: 'admin' }, function (err, uid) {
|
||||
User.create({ username: 'admin', password: '123456' }, function (err, uid) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
@@ -669,7 +670,11 @@ describe('Topic\'s', function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should load topic', function (done) {
|
||||
describe('controller', function () {
|
||||
var request = require('request');
|
||||
var topicData;
|
||||
|
||||
before(function (done) {
|
||||
topics.post({
|
||||
uid: topic.userId,
|
||||
title: 'topic for controller test',
|
||||
@@ -679,15 +684,161 @@ describe('Topic\'s', function () {
|
||||
}, function (err, result) {
|
||||
assert.ifError(err);
|
||||
assert.ok(result);
|
||||
var request = require('request');
|
||||
request(nconf.get('url') + '/topic/' + result.topicData.slug, function (err, response, body) {
|
||||
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.equal(response.statusCode, 200);
|
||||
assert(body);
|
||||
assert.deepEqual(body, {
|
||||
prev: { page: 1, active: false },
|
||||
next: { page: 1, active: false },
|
||||
rel: [],
|
||||
pages: [],
|
||||
currentPage: 1,
|
||||
pageCount: 1,
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('infinitescroll', function () {
|
||||
var socketTopics = require('../src/socket.io/topics');
|
||||
|
||||
@@ -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) {
|
||||
meta.config.allowFileUploads = 1;
|
||||
@@ -99,6 +113,37 @@ describe('Upload Controllers', function () {
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user