Admin command buttons in the profile modal

master
Noah 2024-05-10 21:32:32 -07:00
parent b5bbbde784
commit e70b439cdd
2 changed files with 90 additions and 7 deletions

View File

@ -653,7 +653,7 @@ export default {
},
isOp() {
// Returns if the current user has operator rights
return this.jwt.claims.op;
return this.jwt.claims.op || this.whoMap[this.username].op;
},
isVIP() {
// Returns if the current user has VIP rights.
@ -933,6 +933,14 @@ export default {
this.messageBox.selectionStart = this.messageBox.selectionEnd = this.messageBox.value.length;
});
},
sendCommand(message) {
// Automatically send a message to the chat server.
// e.g. for the ProfileModal to send a "/kick username" command for easy operator buttons.
let origMsg = this.message;
this.message = message;
this.sendMessage();
this.message = origMsg;
},
sendMessage() {
if (!this.message) {
return;
@ -4064,11 +4072,23 @@ export default {
:message="reportModal.message" @accept="doReport" @cancel="reportModal.visible = false"></ReportModal>
<!-- Profile Modal (profile cards popup) -->
<ProfileModal :visible="profileModal.visible" :user="profileModal.user" :username="username" :jwt="jwt.token"
:website-url="config.website" :is-dnd="isUsernameDND(profileModal.username)"
:is-muted="isMutedUser(profileModal.username)" :is-booted="isBooted(profileModal.username)"
:profile-webhook-enabled="isWebhookEnabled('profile')" :vip-config="config.VIP" @send-dm="openDMs"
@mute-user="muteUser" @boot-user="bootUser" @cancel="profileModal.visible = false"></ProfileModal>
<ProfileModal
:visible="profileModal.visible"
:user="profileModal.user"
:username="username"
:is-viewer-op="isOp"
:jwt="jwt.token"
:website-url="config.website"
:is-dnd="isUsernameDND(profileModal.username)"
:is-muted="isMutedUser(profileModal.username)"
:is-booted="isBooted(profileModal.username)"
:profile-webhook-enabled="isWebhookEnabled('profile')"
:vip-config="config.VIP"
@send-dm="openDMs"
@mute-user="muteUser"
@boot-user="bootUser"
@send-command="sendCommand"
@cancel="profileModal.visible = false"></ProfileModal>
<div class="chat-container">

View File

@ -1,10 +1,13 @@
<script>
import VideoFlag from '../lib/VideoFlag';
export default {
props: {
visible: Boolean,
jwt: String, // caller's JWT token for authorization
user: Object, // the user we are viewing
username: String, // the local user
isViewerOp: Boolean, // the viewer is an operator (show buttons)
websiteUrl: String,
isDnd: Boolean,
isMuted: Boolean,
@ -53,6 +56,13 @@ export default {
}
return this.user.username;
},
isOnBlueCam() {
// User is broadcasting a cam and is not NSFW.
if ((this.user.video & VideoFlag.Active) && !(this.user.video & VideoFlag.NSFW)) {
return true;
}
return false;
},
},
methods: {
refresh() {
@ -115,6 +125,29 @@ export default {
this.$emit('boot-user', this.user.username);
},
// Operator commands (may be rejected by server if not really Op)
markNsfw() {
if (!window.confirm("Mark this user's webcam as 'Explicit'?")) return;
this.$emit('send-command', `/nsfw ${this.user.username}`);
// Close the modal immediately: our view of the user's cam data is a copy
// and we can't follow the current value.
this.cancel();
},
kickUser() {
if (!window.confirm("Really kick this user from the chat room?")) return;
this.$emit('send-command', `/kick ${this.user.username}`);
},
banUser() {
let hours = window.prompt(
"Ban this user for how many hours? (Default 24)",
"24",
);
if (!/^\d+$/.test(hours)) return;
this.$emit('send-command', `/ban ${this.user.username} ${hours}`);
},
urlFor(url) {
// Prepend the base websiteUrl if the given URL is relative.
if (url.match(/^https?:/i)) {
@ -221,6 +254,37 @@ export default {
}"></i>
{{ isBooted ? 'Allow to watch my webcam' : "Don't allow to watch my webcam" }}
</button>
<!-- Admin actions -->
<div v-if="isViewerOp" class="mt-1">
<!-- Mark camera NSFW -->
<button v-if="isOnBlueCam"
type="button"
class="button is-small is-outlined is-danger has-text-dark px-2 mr-1 mb-1"
@click="markNsfw()" title="Mark their camera as Explicit (red).">
<i class="fa fa-video mr-1" :class="{
'has-text-success': isMuted,
'has-text-danger': !isMuted
}"></i>
Mark camera as Explicit
</button>
<!-- Kick user -->
<button type="button"
class="button is-small is-outlined is-danger has-text-dark px-2 mr-1 mb-1"
@click="kickUser()" title="Kick this user from the chat room.">
<i class="fa fa-shoe-prints mr-1 has-text-danger"></i>
Kick from the room
</button>
<!-- Ban user -->
<button type="button"
class="button is-small is-outlined is-danger has-text-dark px-2 mb-1"
@click="banUser()" title="Ban this user from the chat room for 24 hours.">
<i class="fa fa-clock mr-1 has-text-danger"></i>
Ban user (temporary)
</button>
</div>
</div>
<!-- Profile Fields spinner/error -->
@ -245,7 +309,6 @@ export default {
{{ field.Value }}
</div>
</div>
</div>
<footer class="card-footer">
<a :href="profileURL" target="_blank"