diff --git a/app/lib/server/functions/setUserActiveStatus.js b/app/lib/server/functions/setUserActiveStatus.js index 63dd06be185d..8f1207ad898c 100644 --- a/app/lib/server/functions/setUserActiveStatus.js +++ b/app/lib/server/functions/setUserActiveStatus.js @@ -40,8 +40,18 @@ export function setUserActiveStatus(userId, active, confirmRelinquish = false) { return false; } + // Users without username can't do anything, so there is no need to check for owned rooms if (user.username != null && !active) { + const userAdmin = Users.findOneAdmin(userId.count); + const adminsCount = Users.findActiveUsersInRoles(['admin']).count(); + if (userAdmin && adminsCount === 1) { + throw new Meteor.Error('error-action-not-allowed', 'Leaving the app without an active admin is not allowed', { + method: 'removeUserFromRole', + action: 'Remove_last_admin', + }); + } + const subscribedRooms = getSubscribedRoomsForUserWithDetails(userId); // give omnichannel rooms a special treatment :) const chatSubscribedRooms = subscribedRooms.filter(({ t }) => t !== 'l'); diff --git a/app/models/server/models/Users.js b/app/models/server/models/Users.js index 5db566ec5f78..f74d4de0c90f 100644 --- a/app/models/server/models/Users.js +++ b/app/models/server/models/Users.js @@ -569,6 +569,17 @@ export class Users extends Base { return this.find(query, options); } + findActiveUsersInRoles(roles, scope, options) { + roles = [].concat(roles); + + const query = { + roles: { $in: roles }, + active: true, + }; + + return this.find(query, options); + } + findOneByAppId(appId, options) { const query = { appId };