mirror of
				https://github.com/NodeBB/NodeBB.git
				synced 2025-10-31 02:55:58 +01:00 
			
		
		
		
	fix: #12357, properly update lists and counters
This commit is contained in:
		| @@ -6,24 +6,24 @@ define('forum/groups/details', [ | |||||||
| 	'components', | 	'components', | ||||||
| 	'coverPhoto', | 	'coverPhoto', | ||||||
| 	'pictureCropper', | 	'pictureCropper', | ||||||
| 	'translator', |  | ||||||
| 	'api', | 	'api', | ||||||
| 	'slugify', | 	'slugify', | ||||||
| 	'categorySelector', | 	'categorySelector', | ||||||
| 	'bootbox', | 	'bootbox', | ||||||
| 	'alerts', | 	'alerts', | ||||||
|  | 	'helpers', | ||||||
| ], function ( | ], function ( | ||||||
| 	memberList, | 	memberList, | ||||||
| 	iconSelect, | 	iconSelect, | ||||||
| 	components, | 	components, | ||||||
| 	coverPhoto, | 	coverPhoto, | ||||||
| 	pictureCropper, | 	pictureCropper, | ||||||
| 	translator, |  | ||||||
| 	api, | 	api, | ||||||
| 	slugify, | 	slugify, | ||||||
| 	categorySelector, | 	categorySelector, | ||||||
| 	bootbox, | 	bootbox, | ||||||
| 	alerts | 	alerts, | ||||||
|  | 	helpers | ||||||
| ) { | ) { | ||||||
| 	const Details = {}; | 	const Details = {}; | ||||||
| 	let groupName; | 	let groupName; | ||||||
| @@ -85,14 +85,19 @@ define('forum/groups/details', [ | |||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				case 'kick': | 				case 'kick': | ||||||
| 					translator.translate('[[groups:details.kick-confirm]]', function (translated) { | 					bootbox.confirm('[[groups:details.kick-confirm]]', function (confirm) { | ||||||
| 						bootbox.confirm(translated, function (confirm) { |  | ||||||
| 						if (!confirm) { | 						if (!confirm) { | ||||||
| 							return; | 							return; | ||||||
| 						} | 						} | ||||||
|  |  | ||||||
| 							api.del(`/groups/${ajaxify.data.group.slug}/membership/${uid}`, undefined).then(() => userRow.slideUp().remove()).catch(alerts.error); | 						api.del(`/groups/${ajaxify.data.group.slug}/membership/${uid}`, undefined).then( | ||||||
| 						}); | 							() => { | ||||||
|  | 								userRow.remove(); | ||||||
|  | 								$('[component="group/member/count"]').text( | ||||||
|  | 									helpers.humanReadableNumber(ajaxify.data.group.memberCount - 1) | ||||||
|  | 								); | ||||||
|  | 							} | ||||||
|  | 						).catch(alerts.error); | ||||||
| 					}); | 					}); | ||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| @@ -105,29 +110,42 @@ define('forum/groups/details', [ | |||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				case 'join': | 				case 'join': | ||||||
| 					api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then(() => ajaxify.refresh()).catch(alerts.error); | 					api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then( | ||||||
|  | 						() => ajaxify.refresh() | ||||||
|  | 					).catch(alerts.error); | ||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				case 'leave': | 				case 'leave': | ||||||
| 					api.del('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then(() => ajaxify.refresh()).catch(alerts.error); | 					api.del('/groups/' + ajaxify.data.group.slug + '/membership/' + (uid || app.user.uid), undefined).then( | ||||||
|  | 						() => ajaxify.refresh() | ||||||
|  | 					).catch(alerts.error); | ||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				case 'accept': | 				case 'accept': | ||||||
| 					api.put(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); | 					api.put(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then( | ||||||
|  | 						() => { | ||||||
|  | 							userRow.remove(); | ||||||
|  | 							memberList.refresh(); | ||||||
|  | 							updatePendingAlertVisibility(); | ||||||
|  | 						} | ||||||
|  | 					).catch(alerts.error); | ||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				case 'reject': | 				case 'reject': | ||||||
| 					api.del(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); | 					api.del(`/groups/${ajaxify.data.group.slug}/pending/${uid}`).then( | ||||||
| 					break; | 						() => { | ||||||
|  | 							userRow.remove(); | ||||||
| 				case 'issueInvite': | 							memberList.refresh(); | ||||||
| 					api.post(`/groups/${ajaxify.data.group.slug}/invites/${uid}`).then(() => ajaxify.refresh()).catch(alerts.error); | 							updatePendingAlertVisibility(); | ||||||
|  | 						} | ||||||
|  | 					).catch(alerts.error); | ||||||
| 					break; | 					break; | ||||||
|  |  | ||||||
| 				case 'acceptInvite': | 				case 'acceptInvite': | ||||||
| 					api.put(`/groups/${ajaxify.data.group.slug}/invites/${app.user.uid}`).then(() => { | 					api.put(`/groups/${ajaxify.data.group.slug}/invites/${app.user.uid}`).then(() => { | ||||||
| 						if (uid) { | 						if (uid) { | ||||||
| 							userRow.remove(); | 							userRow.remove(); | ||||||
|  | 							memberList.refresh(); | ||||||
| 						} else { | 						} else { | ||||||
| 							ajaxify.refresh(); | 							ajaxify.refresh(); | ||||||
| 						} | 						} | ||||||
| @@ -139,6 +157,8 @@ define('forum/groups/details', [ | |||||||
| 					api.del(`/groups/${ajaxify.data.group.slug}/invites/${uid || app.user.uid}`).then(() => { | 					api.del(`/groups/${ajaxify.data.group.slug}/invites/${uid || app.user.uid}`).then(() => { | ||||||
| 						if (uid) { | 						if (uid) { | ||||||
| 							userRow.remove(); | 							userRow.remove(); | ||||||
|  | 							updateInviteAlertVisibility(); | ||||||
|  | 							memberList.refresh(); | ||||||
| 						} else { | 						} else { | ||||||
| 							ajaxify.refresh(); | 							ajaxify.refresh(); | ||||||
| 						} | 						} | ||||||
| @@ -268,6 +288,20 @@ define('forum/groups/details', [ | |||||||
| 		}); | 		}); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	function updatePendingAlertVisibility() { | ||||||
|  | 		$('[component="groups/pending/alert"]').toggleClass( | ||||||
|  | 			'hidden', | ||||||
|  | 			$('[component="groups/pending"] tbody tr').length > 0 | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  |  | ||||||
|  | 	function updateInviteAlertVisibility() { | ||||||
|  | 		$('[component="groups/invited/alert"]').toggleClass( | ||||||
|  | 			'hidden', | ||||||
|  | 			$('[component="groups/invited"] tbody tr').length > 0 | ||||||
|  | 		); | ||||||
|  | 	} | ||||||
|  |  | ||||||
| 	function handleMemberInvitations() { | 	function handleMemberInvitations() { | ||||||
| 		if (!ajaxify.data.group.isOwner) { | 		if (!ajaxify.data.group.isOwner) { | ||||||
| 			return; | 			return; | ||||||
| @@ -275,8 +309,9 @@ define('forum/groups/details', [ | |||||||
| 		async function updateList() { | 		async function updateList() { | ||||||
| 			const data = await api.get(`/api/groups/${ajaxify.data.group.slug}`); | 			const data = await api.get(`/api/groups/${ajaxify.data.group.slug}`); | ||||||
| 			const html = await app.parseAndTranslate('groups/details', 'group.invited', { group: data.group }); | 			const html = await app.parseAndTranslate('groups/details', 'group.invited', { group: data.group }); | ||||||
| 			$('[component="groups/invited"] tbody tr').remove(); |  | ||||||
| 			$('[component="groups/invited"] tbody').html(html); | 			$('[component="groups/invited"] tbody').html(html); | ||||||
|  | 			updateInviteAlertVisibility(); | ||||||
|  | 			memberList.refresh(); | ||||||
| 		} | 		} | ||||||
| 		const searchInput = $('[component="groups/members/invite"]'); | 		const searchInput = $('[component="groups/members/invite"]'); | ||||||
| 		require(['autocomplete'], function (autocomplete) { | 		require(['autocomplete'], function (autocomplete) { | ||||||
| @@ -305,8 +340,7 @@ define('forum/groups/details', [ | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function removeCover() { | 	function removeCover() { | ||||||
| 		translator.translate('[[groups:remove-group-cover-confirm]]', function (translated) { | 		bootbox.confirm('[[groups:remove-group-cover-confirm]]', function (confirm) { | ||||||
| 			bootbox.confirm(translated, function (confirm) { |  | ||||||
| 			if (!confirm) { | 			if (!confirm) { | ||||||
| 				return; | 				return; | ||||||
| 			} | 			} | ||||||
| @@ -321,7 +355,6 @@ define('forum/groups/details', [ | |||||||
| 				} | 				} | ||||||
| 			}); | 			}); | ||||||
| 		}); | 		}); | ||||||
| 		}); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return Details; | 	return Details; | ||||||
|   | |||||||
| @@ -1,19 +1,36 @@ | |||||||
| 'use strict'; | 'use strict'; | ||||||
|  |  | ||||||
| define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, bootbox, alerts) { | define('forum/groups/memberlist', ['api', 'bootbox', 'alerts', 'helpers'], function (api, bootbox, alerts, helpers) { | ||||||
| 	const MemberList = {}; | 	const MemberList = {}; | ||||||
| 	let groupName; |  | ||||||
| 	let templateName; | 	let templateName; | ||||||
|  |  | ||||||
| 	MemberList.init = function (_templateName) { | 	MemberList.init = function (_templateName) { | ||||||
| 		templateName = _templateName || 'groups/details'; | 		templateName = _templateName || 'groups/details'; | ||||||
| 		groupName = ajaxify.data.group.name; |  | ||||||
|  |  | ||||||
| 		handleMemberAdd(); | 		handleMemberAdd(); | ||||||
| 		handleMemberSearch(); | 		handleMemberSearch(); | ||||||
| 		handleMemberInfiniteScroll(); | 		handleMemberInfiniteScroll(); | ||||||
| 	}; | 	}; | ||||||
|  |  | ||||||
|  | 	MemberList.refresh = async function () { | ||||||
|  | 		const { group } = await api.get(`/api/groups/${ajaxify.data.group.slug}`); | ||||||
|  | 		const html = await parseAndTranslate(group.members); | ||||||
|  | 		$('[component="groups/members"] tbody').html(html); | ||||||
|  | 		$('[component="group/member/count"]').text( | ||||||
|  | 			helpers.humanReadableNumber(group.memberCount) | ||||||
|  | 		); | ||||||
|  | 		$('[component="group/pending/count"]').text( | ||||||
|  | 			helpers.humanReadableNumber(group.pending.length) | ||||||
|  | 		); | ||||||
|  | 		$('[component="group/invited/count"]').text( | ||||||
|  | 			helpers.humanReadableNumber(group.invited.length) | ||||||
|  | 		); | ||||||
|  | 		ajaxify.data.group.members = group.members; | ||||||
|  | 		ajaxify.data.group.memberCount = group.memberCount; | ||||||
|  | 		ajaxify.data.group.invited = group.invited; | ||||||
|  | 		ajaxify.data.group.pending = group.pending; | ||||||
|  | 	}; | ||||||
|  |  | ||||||
| 	function handleMemberAdd() { | 	function handleMemberAdd() { | ||||||
| 		$('[component="groups/members/add"]').on('click', function () { | 		$('[component="groups/members/add"]').on('click', function () { | ||||||
| 			app.parseAndTranslate('admin/partials/groups/add-members', {}, function (html) { | 			app.parseAndTranslate('admin/partials/groups/add-members', {}, function (html) { | ||||||
| @@ -29,7 +46,7 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b | |||||||
| 								modal.find('[data-uid][data-selected]').each(function (index, el) { | 								modal.find('[data-uid][data-selected]').each(function (index, el) { | ||||||
| 									users.push(foundUsers[$(el).attr('data-uid')]); | 									users.push(foundUsers[$(el).attr('data-uid')]); | ||||||
| 								}); | 								}); | ||||||
| 								addUserToGroup(users, function () { | 								addUsersToGroup(users).then(() => { | ||||||
| 									modal.modal('hide'); | 									modal.modal('hide'); | ||||||
| 								}); | 								}); | ||||||
| 							}, | 							}, | ||||||
| @@ -65,99 +82,77 @@ define('forum/groups/memberlist', ['api', 'bootbox', 'alerts'], function (api, b | |||||||
| 		}); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function addUserToGroup(users, callback) { | 	async function addUsersToGroup(users) { | ||||||
| 		function done() { | 		const uids = users.map(u => u.uid); | ||||||
| 			users = users.filter(function (user) { | 		if (ajaxify.data.group.name === 'administrators') { | ||||||
| 				return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; | 			await socket.emit('admin.user.makeAdmins', uids).catch(alerts.error); | ||||||
| 			}); |  | ||||||
| 			parseAndTranslate(users, function (html) { |  | ||||||
| 				$('[component="groups/members"] tbody').prepend(html); |  | ||||||
| 			}); |  | ||||||
| 			callback(); |  | ||||||
| 		} |  | ||||||
| 		const uids = users.map(function (user) { return user.uid; }); |  | ||||||
| 		if (groupName === 'administrators') { |  | ||||||
| 			socket.emit('admin.user.makeAdmins', uids, function (err) { |  | ||||||
| 				if (err) { |  | ||||||
| 					return alerts.error(err); |  | ||||||
| 				} |  | ||||||
| 				done(); |  | ||||||
| 			}); |  | ||||||
| 		} else { | 		} else { | ||||||
| 			Promise.all(uids.map(uid => api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + uid))).then(done).catch(alerts.error); | 			await Promise.all(uids.map(uid => api.put('/groups/' + ajaxify.data.group.slug + '/membership/' + uid))).catch(alerts.error); | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
|  | 		users = users.filter(user => !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length); | ||||||
|  | 		const html = await parseAndTranslate(users); | ||||||
|  | 		$('[component="groups/members"] tbody').prepend(html); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function handleMemberSearch() { | 	function handleMemberSearch() { | ||||||
| 		const searchEl = $('[component="groups/members/search"]'); | 		const searchEl = $('[component="groups/members/search"]'); | ||||||
| 		searchEl.on('keyup', utils.debounce(function () { | 		searchEl.on('keyup', utils.debounce(async function () { | ||||||
| 			const query = searchEl.val(); | 			const query = searchEl.val(); | ||||||
| 			api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }, function (err, results) { | 			const results = await api.get(`/groups/${ajaxify.data.group.slug}/members`, { query }); | ||||||
| 				if (err) { | 			const html = await parseAndTranslate(results.users); | ||||||
| 					return alerts.error(err); |  | ||||||
| 				} |  | ||||||
| 				parseAndTranslate(results.users, function (html) { |  | ||||||
| 			$('[component="groups/members"] tbody').html(html); | 			$('[component="groups/members"] tbody').html(html); | ||||||
| 			$('[component="groups/members"]').attr('data-nextstart', 20); | 			$('[component="groups/members"]').attr('data-nextstart', 20); | ||||||
| 				}); |  | ||||||
| 			}); |  | ||||||
| 		}, 250)); | 		}, 250)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function handleMemberInfiniteScroll() { | 	function handleMemberInfiniteScroll() { | ||||||
| 		$('[component="groups/members"]').on('scroll', function () { | 		$('[component="groups/members"]').on('scroll', utils.debounce(function () { | ||||||
| 			const $this = $(this); | 			const $this = $(this); | ||||||
| 			const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9; | 			const bottom = ($this[0].scrollHeight - $this.innerHeight()) * 0.9; | ||||||
|  |  | ||||||
| 			if ($this.scrollTop() > bottom && !$('[component="groups/members/search"]').val()) { | 			if ($this.scrollTop() > bottom && !$('[component="groups/members/search"]').val()) { | ||||||
| 				loadMoreMembers(); | 				loadMoreMembers(); | ||||||
| 			} | 			} | ||||||
| 		}); | 		}, 250)); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function loadMoreMembers() { | 	async function loadMoreMembers() { | ||||||
| 		const members = $('[component="groups/members"]'); | 		const members = $('[component="groups/members"]'); | ||||||
| 		if (members.attr('loading')) { | 		if (members.attr('loading')) { | ||||||
| 			return; | 			return; | ||||||
| 		} | 		} | ||||||
|  |  | ||||||
| 		members.attr('loading', 1); | 		members.attr('loading', 1); | ||||||
| 		api.get(`/groups/${ajaxify.data.group.slug}/members`, { | 		const data = await api.get(`/groups/${ajaxify.data.group.slug}/members`, { | ||||||
| 			after: members.attr('data-nextstart'), | 			after: members.attr('data-nextstart'), | ||||||
| 		}, function (err, data) { | 		}).catch(alerts.error); | ||||||
| 			if (err) { |  | ||||||
| 				return alerts.error(err); |  | ||||||
| 			} |  | ||||||
|  |  | ||||||
| 		if (data && data.users.length) { | 		if (data && data.users.length) { | ||||||
| 				onMembersLoaded(data.users, function () { | 			await onMembersLoaded(data.users); | ||||||
| 			members.removeAttr('loading'); | 			members.removeAttr('loading'); | ||||||
| 			members.attr('data-nextstart', data.nextStart); | 			members.attr('data-nextstart', data.nextStart); | ||||||
| 				}); |  | ||||||
| 		} else { | 		} else { | ||||||
| 			members.removeAttr('loading'); | 			members.removeAttr('loading'); | ||||||
| 		} | 		} | ||||||
| 		}); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function onMembersLoaded(users, callback) { | 	async function onMembersLoaded(users) { | ||||||
| 		users = users.filter(function (user) { | 		users = users.filter(function (user) { | ||||||
| 			return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; | 			return !$('[component="groups/members"] [data-uid="' + user.uid + '"]').length; | ||||||
| 		}); | 		}); | ||||||
|  |  | ||||||
| 		parseAndTranslate(users, function (html) { | 		const html = await parseAndTranslate(users); | ||||||
| 		$('[component="groups/members"] tbody').append(html); | 		$('[component="groups/members"] tbody').append(html); | ||||||
| 			callback(); |  | ||||||
| 		}); |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	function parseAndTranslate(users, callback) { | 	async function parseAndTranslate(users) { | ||||||
| 		app.parseAndTranslate(templateName, 'group.members', { | 		return await app.parseAndTranslate(templateName, 'group.members', { | ||||||
| 			group: { | 			group: { | ||||||
| 				members: users, | 				members: users, | ||||||
| 				isOwner: ajaxify.data.group.isOwner, | 				isOwner: ajaxify.data.group.isOwner, | ||||||
| 			}, | 			}, | ||||||
| 		}, callback); | 		}); | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	return MemberList; | 	return MemberList; | ||||||
|   | |||||||
| @@ -167,7 +167,7 @@ module.exports = function (utils, Benchpress, relative_path) { | |||||||
| 		if (groupObj.isPending && groupObj.name !== 'administrators') { | 		if (groupObj.isPending && groupObj.name !== 'administrators') { | ||||||
| 			return `<button class="btn btn-warning disabled ${btnClass}"><i class="fa fa-clock-o"></i> [[groups:membership.invitation-pending]]</button>`; | 			return `<button class="btn btn-warning disabled ${btnClass}"><i class="fa fa-clock-o"></i> [[groups:membership.invitation-pending]]</button>`; | ||||||
| 		} else if (groupObj.isInvited) { | 		} else if (groupObj.isInvited) { | ||||||
| 			return `<button class="btn btn-link" data-action="rejectInvite" data-group="${groupObj.displayName}">[[groups:membership.reject]]</button><button class="btn btn-success" data-action="acceptInvite" data-group="${groupObj.name}"><i class="fa fa-plus"></i> [[groups:membership.accept-invitation]]</button>`; | 			return `<button class="btn btn-warning" data-action="rejectInvite" data-group="${groupObj.displayName}">[[groups:membership.reject]]</button><button class="btn btn-success" data-action="acceptInvite" data-group="${groupObj.name}"><i class="fa fa-plus"></i> [[groups:membership.accept-invitation]]</button>`; | ||||||
| 		} else if (!groupObj.disableJoinRequests && groupObj.name !== 'administrators') { | 		} else if (!groupObj.disableJoinRequests && groupObj.name !== 'administrators') { | ||||||
| 			return `<button class="btn btn-success" data-action="join" data-group="${groupObj.displayName}"><i class="fa fa-plus"></i> [[groups:membership.join-group]]</button>`; | 			return `<button class="btn btn-success" data-action="join" data-group="${groupObj.displayName}"><i class="fa fa-plus"></i> [[groups:membership.join-group]]</button>`; | ||||||
| 		} | 		} | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user