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

View File

@ -1,10 +1,13 @@
<script> <script>
import VideoFlag from '../lib/VideoFlag';
export default { export default {
props: { props: {
visible: Boolean, visible: Boolean,
jwt: String, // caller's JWT token for authorization jwt: String, // caller's JWT token for authorization
user: Object, // the user we are viewing user: Object, // the user we are viewing
username: String, // the local user username: String, // the local user
isViewerOp: Boolean, // the viewer is an operator (show buttons)
websiteUrl: String, websiteUrl: String,
isDnd: Boolean, isDnd: Boolean,
isMuted: Boolean, isMuted: Boolean,
@ -53,6 +56,13 @@ export default {
} }
return this.user.username; 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: { methods: {
refresh() { refresh() {
@ -115,6 +125,29 @@ export default {
this.$emit('boot-user', this.user.username); 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) { urlFor(url) {
// Prepend the base websiteUrl if the given URL is relative. // Prepend the base websiteUrl if the given URL is relative.
if (url.match(/^https?:/i)) { if (url.match(/^https?:/i)) {
@ -221,6 +254,37 @@ export default {
}"></i> }"></i>
{{ isBooted ? 'Allow to watch my webcam' : "Don't allow to watch my webcam" }} {{ isBooted ? 'Allow to watch my webcam' : "Don't allow to watch my webcam" }}
</button> </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> </div>
<!-- Profile Fields spinner/error --> <!-- Profile Fields spinner/error -->
@ -245,7 +309,6 @@ export default {
{{ field.Value }} {{ field.Value }}
</div> </div>
</div> </div>
</div> </div>
<footer class="card-footer"> <footer class="card-footer">
<a :href="profileURL" target="_blank" <a :href="profileURL" target="_blank"