mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 11:05:54 +01:00 
			
		
		
		
	Merge branch 'master' into styleguide
This commit is contained in:
		| @@ -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./)) { | 				if (!uploadedFile.type.match(/image./)) { | ||||||
| 					return next(new Error('[[error:invalid-file]]')); | 					return next(new Error('[[error:invalid-file]]')); | ||||||
| 				} | 				} | ||||||
|  |  | ||||||
|  | 				file.isFileTypeAllowed(uploadedFile.path, next); | ||||||
|  | 			}, | ||||||
|  | 			function (next) { | ||||||
| 				var size = parseInt(meta.config.topicThumbSize, 10) || 120; | 				var size = parseInt(meta.config.topicThumbSize, 10) || 120; | ||||||
| 				image.resizeImage({ | 				image.resizeImage({ | ||||||
| 					path: uploadedFile.path, | 					path: uploadedFile.path, | ||||||
| 					extension: path.extname(uploadedFile.name), | 					extension: path.extname(uploadedFile.name), | ||||||
| 					width: size, | 					width: size, | ||||||
| 					height: size, | 					height: size, | ||||||
| 			}, function (err) { | 				}, next); | ||||||
| 				if (err) { | 			}, | ||||||
| 					return next(err); | 			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) { | ||||||
|   | |||||||
| @@ -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) { | ||||||
|   | |||||||
| @@ -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) { | 	async.waterfall([ | ||||||
| 			return callback(err); | 		function (next) { | ||||||
| 		} | 			user.getUidsByUsernames(usernames, next); | ||||||
|  | 		}, | ||||||
|  | 		function (uids, next) { | ||||||
| 			uids = uids.filter(function (uid) { | 			uids = uids.filter(function (uid) { | ||||||
| 				return !!uid && parseInt(uid, 10); | 				return !!uid && parseInt(uid, 10); | ||||||
| 			}); | 			}); | ||||||
|  |  | ||||||
| 			async.eachSeries(uids, function (uid, next) { | 			async.eachSeries(uids, function (uid, next) { | ||||||
| 				groups.invite(data.groupName, uid, next); | 				groups.invite(data.groupName, uid, next); | ||||||
| 		}, callback); | 			}, 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({ |  | ||||||
| 		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); | 	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 = {}; | ||||||
|   | |||||||
							
								
								
									
										309
									
								
								test/groups.js
									
									
									
									
									
								
							
							
						
						
									
										309
									
								
								test/groups.js
									
									
									
									
									
								
							| @@ -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,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) { | 		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) { | 				socketGroups.accept({ uid: adminUid }, { groupName: 'PrivateCanJoin', toUid: testUid }, function (err) { | ||||||
| 					assert.ifError(err); | 					assert.ifError(err); | ||||||
| 					Groups.isMember(testUid, 'PrivateCanJoin', function (err, isMember) { | 					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) { | 		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) { | ||||||
| @@ -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]]'); | ||||||
|   | |||||||
							
								
								
									
										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 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,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({ | 			topics.post({ | ||||||
| 				uid: topic.userId, | 				uid: topic.userId, | ||||||
| 				title: 'topic for controller test', | 				title: 'topic for controller test', | ||||||
| @@ -679,15 +684,161 @@ describe('Topic\'s', function () { | |||||||
| 			}, function (err, result) { | 			}, function (err, result) { | ||||||
| 				assert.ifError(err); | 				assert.ifError(err); | ||||||
| 				assert.ok(result); | 				assert.ok(result); | ||||||
| 			var request = require('request'); | 				topicData = result.topicData; | ||||||
| 			request(nconf.get('url') + '/topic/' + result.topicData.slug, function (err, response, body) { | 				done(); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
|  |  | ||||||
|  | 		it('should load topic', function (done) { | ||||||
|  | 			request(nconf.get('url') + '/topic/' + topicData.slug, function (err, response, body) { | ||||||
| 				assert.ifError(err); | 				assert.ifError(err); | ||||||
| 				assert.equal(response.statusCode, 200); | 				assert.equal(response.statusCode, 200); | ||||||
| 				assert(body); | 				assert(body); | ||||||
| 				done(); | 				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 () { | 	describe('infinitescroll', function () { | ||||||
| 		var socketTopics = require('../src/socket.io/topics'); | 		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) { | 		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(); | ||||||
|  | 			}); | ||||||
|  | 		}); | ||||||
| 	}); | 	}); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user