diff --git a/core/client/ui/levels.js b/core/client/ui/levels.js
index 787525da..10331994 100644
--- a/core/client/ui/levels.js
+++ b/core/client/ui/levels.js
@@ -11,8 +11,15 @@ const levelQueryFilters = ignoredLevelId => ({
});
const askLoadLevel = (levelId, incrementVisit = false) => {
+ const bannedUserIds = Levels.findOne({ _id: levelId }).bannedUserIds || [];
+
if (Meteor.user().profile.levelId === levelId) return;
+ if (bannedUserIds.includes(Meteor.userId())) {
+ lp.notif.error('You have been banned from this level');
+ return;
+ }
+
if (incrementVisit) Meteor.call('increaseLevelVisits', levelId);
if (window.self !== window.top) {
diff --git a/core/lib/misc.js b/core/lib/misc.js
index 07cba923..6fa8a054 100644
--- a/core/lib/misc.js
+++ b/core/lib/misc.js
@@ -305,6 +305,17 @@ const getChannelType = channelId => {
}
};
+const kickUser = userId => {
+ // if (!this.userId) throw new Meteor.Error('missing-user', 'A valid user is required');
+ check(userId, Match.Id);
+ if (!Meteor.settings.defaultKickLevelId) throw new Meteor.Error('missing-levelId', 'Missing configuration for defaultKickLevelId');
+ const level = Levels.findOne({ _id: Meteor.settings.defaultKickLevelId });
+ if (!level) throw new Meteor.Error('missing-levelId', 'Level in defaultKickLevelId does not exists');
+ log('kickUser', { kicker: Meteor.userId(), kicked: userId });
+
+ Meteor.users.update({ _id: userId }, { $set: { 'profile.levelId': Meteor.settings.defaultKickLevelId } });
+};
+
export {
canAccessZone,
canEditActiveLevel,
@@ -316,16 +327,17 @@ export {
completeUserProfile,
currentLevel,
fileOnBeforeUpload,
- generateRandomCharacterSkin,
generateGuestSkin,
+ generateRandomCharacterSkin,
+ getChannelType,
getSpawnLevel,
guestAllowed,
- getChannelType,
isLevelOwner,
+ kickUser,
levelSpawnPosition,
permissionTypes,
+ randomFloatInRange,
+ randomInRange,
subscribedUsersToEntity,
teleportUserInLevel,
- randomInRange,
- randomFloatInRange,
};
diff --git a/core/modules/report/client/report.hbs.html b/core/modules/report/client/report.hbs.html
index e697b41b..4c3a7f9b 100644
--- a/core/modules/report/client/report.hbs.html
+++ b/core/modules/report/client/report.hbs.html
@@ -5,19 +5,23 @@
{{ title }}
-
-{{/modal }}
+ {{/modal }}
diff --git a/core/modules/report/client/report.js b/core/modules/report/client/report.js
index 5707b981..beb075fb 100644
--- a/core/modules/report/client/report.js
+++ b/core/modules/report/client/report.js
@@ -15,7 +15,7 @@ window.addEventListener('load', () => {
window.addEventListener(eventTypes.onMenuOptionSelected, onMenuOptionSelected);
});
-function buildMessage(text, level, reason, reported, messageId) {
+function buildMessage(text, level, reason, reported, messageId, isBanned) {
let messageText = '';
if (messageId) {
const message = Messages.findOne(messageId);
@@ -29,6 +29,8 @@ Level: ${level}
Justification: ${text}
+Banned: ${isBanned}
+
Reason: ${reason}
${messageText}
Reported: ${reported._id} - ${reported.profile.name}`;
@@ -45,12 +47,14 @@ const sendReport = (channel, text) => {
return messageId;
};
-const onSubmit = (reason, reported, messageId) => {
- if (reported._id === Meteor.userId()) {
+const onSubmit = (reason, reported, messageId, isBanned = false) => {
+ const userId = Meteor.userId();
+
+ if (reported._id === userId) {
lp.notif.error('You can\'t report yourself');
return;
}
- const isAdmin = Meteor.users.findOne(Meteor.userId()).roles?.admin;
+ const isAdmin = Meteor.users.findOne(userId).roles?.admin;
const text = document.querySelector('.report .js-command-input').value;
const currentLevel = Meteor.user().profile.levelId;
@@ -64,9 +68,9 @@ const onSubmit = (reason, reported, messageId) => {
}
let admins = Meteor.users.find({ roles: { admin: true } }).fetch();
if (isAdmin) {
- admins = admins.filter(admin => admin._id !== Meteor.userId());
+ admins = admins.filter(admin => admin._id !== userId);
}
- if (!admins.length) {
+ if (!isBanned && !admins.length) {
// Quiting even if the user is an admin because we don't want to create a conversation with himself
lp.notif.error('No admins found');
return;
@@ -76,11 +80,19 @@ const onSubmit = (reason, reported, messageId) => {
admins = adminsLevel;
}
const level = Levels.findOne(currentLevel).name;
- const message = buildMessage(text, level, reason, reported, messageId);
- const channel = [...admins.map(admin => admin._id), Meteor.userId()].sort().join(';');
+ const message = buildMessage(text, level, reason, reported, messageId, isBanned);
+ const channel = [...admins.map(admin => admin._id), userId].sort().join(';');
sendReport(channel, message);
+ if (isBanned) {
+ Meteor.call('banUser', reported._id, currentLevel, err => {
+ if (err) { lp.notif.error(err); return; }
+
+ lp.notif.success('Successfully Banned!');
+ });
+ }
+
closeModal('report');
};
@@ -97,16 +109,23 @@ Template.report.helpers({
const reportAllReasons = ['Non-specified', 'Spam', 'Abusive chat', 'Cheating', 'Offensive name', 'Other'];
return reportAllReasons;
},
+ isAdmin() { return Meteor.user().roles?.admin;},
});
Template.report.events({
'change .js-report-reason-select'(event) {
Template.instance().reason.set(event.target.value);
},
- 'click .js-button-submit'(event) {
+ 'click .js-report-submit'(event) {
event.preventDefault();
event.stopPropagation();
const template = Template.instance();
lp.notif.confirm('Report user', `Do you really want to report this ${template.data.messageId ? 'message' : 'user'}?`, () => onSubmit(template.reason.get(), Meteor.users.findOne(template.data.userId), template.data.messageId));
},
+ 'click .js-ban-submit'(event) {
+ event.preventDefault();
+ event.stopPropagation();
+ const template = Template.instance();
+ lp.notif.confirm('Ban user', 'Do you really want to ban this user', () => onSubmit(template.reason.get(), Meteor.users.findOne(template.data.userId), template.data.messageId, true));
+ },
});
diff --git a/core/modules/report/client/report.scss b/core/modules/report/client/report.scss
index 23a21c66..5d34d3c0 100644
--- a/core/modules/report/client/report.scss
+++ b/core/modules/report/client/report.scss
@@ -1,3 +1,5 @@
+@import "../../../client/_variables";
+
.report {
width: 90%;
height: 80%;
@@ -10,8 +12,22 @@
width: 100%;
height: 80%;
}
- button {
- margin-bottom: 0px;
+
+ .buttons {
+ display: flex;
+ gap: 10px;
+
+ .js-ban-submit {
+ background-color: $new-red;
+
+ &:hover {
+ background-color: lighten($new-red, 5%);
+ }
+ }
+
+ button {
+ margin-bottom: 0px;
+ }
}
}
}
diff --git a/core/server/levels.js b/core/server/levels.js
index d4e2c16b..d014c50b 100644
--- a/core/server/levels.js
+++ b/core/server/levels.js
@@ -169,7 +169,7 @@ deleteLevel = levelId => {
Meteor.publish('levels', function () {
if (!this.userId) return undefined;
- return Levels.find({ }, { fields: { name: 1, hide: 1, visit: 1, createdBy: 1, template: 1 } });
+ return Levels.find({ }, { fields: { name: 1, hide: 1, visit: 1, createdBy: 1, template: 1, bannedUserIds: 1 } });
});
Meteor.publish('levelTemplates', function () {
diff --git a/core/server/users.js b/core/server/users.js
index 43cc009b..fe15c2d8 100644
--- a/core/server/users.js
+++ b/core/server/users.js
@@ -1,4 +1,4 @@
-import { completeUserProfile, getSpawnLevel, levelSpawnPosition, teleportUserInLevel } from '../lib/misc';
+import { completeUserProfile, getSpawnLevel, kickUser, levelSpawnPosition, teleportUserInLevel } from '../lib/misc';
const mainFields = { options: 1, profile: 1, roles: 1, status: { idle: 1, online: 1 }, beta: 1, guildId: 1 };
@@ -107,14 +107,18 @@ Meteor.methods({
Notifications.update({ userId: this.userId }, { $set: { read: true } }, { multi: true });
},
kickUser(userId) {
+ kickUser(userId)
+ },
+ banUser(userId, levelId) {
if (!this.userId) throw new Meteor.Error('missing-user', 'A valid user is required');
check(userId, Match.Id);
- if (!Meteor.settings.defaultKickLevelId) throw new Meteor.Error('missing-levelId', 'Missing configuration for defaultKickLevelId');
- const level = Levels.findOne({ _id: Meteor.settings.defaultKickLevelId });
- if (!level) throw new Meteor.Error('missing-levelId', 'Level in defaultKickLevelId does not exists');
- log('kickUser', { kicker: Meteor.userId(), kicked: userId });
+ const level = Levels.findOne({ _id: levelId });
+ if (!level) throw new Meteor.Error('missing-levelId', 'Level is required');
+ log('banUser', { banner: Meteor.userId(), banned: userId });
+
- Meteor.users.update({ _id: userId }, { $set: { 'profile.levelId': Meteor.settings.defaultKickLevelId } });
+ kickUser(userId);
+ Levels.update({ _id: levelId, bannedUserIds: { $ne: userId } }, { $push: { bannedUserIds: userId } });
},
muteFromZone(zoneId) {
if (!this.userId) return;