Fixes for admins, VIP and blocking + Frontend tweaks

Changes to the chat server:
* Blocking will not apply to admin user accounts (operators)
* Users who block an admin will instead mute them, but the admin can
  still DM them if required
* Messages to VIP channels are broadcast to admins even if they are not
  VIPs, e.g. so moderator chatbots can see
* On the Who List: VIP-only cameras to highlight with the VIP background
  color on those buttons
vue-cli
Noah 2023-09-07 19:43:03 -07:00
parent d8cb1c7c11
commit d8c92800f3
3 changed files with 49 additions and 9 deletions

View File

@ -453,6 +453,7 @@ func (s *Server) OnBlocklist(sub *Subscriber, msg messages.Message) {
sub.muteMu.Lock()
for _, username := range msg.Usernames {
sub.muted[username] = struct{}{}
sub.blocked[username] = struct{}{}
}

View File

@ -354,7 +354,7 @@ func (s *Server) Broadcast(msg messages.Message) {
}
// VIP channels: only deliver to subscribed VIP users.
if ch, ok := config.Current.GetChannel(msg.Channel); ok && ch.VIP && !sub.IsVIP() {
if ch, ok := config.Current.GetChannel(msg.Channel); ok && ch.VIP && !sub.IsVIP() && !sub.IsAdmin() {
log.Debug("Do not broadcast message to %s: VIP channel and they are not VIP", sub.Username)
continue
}
@ -499,6 +499,11 @@ func (s *Subscriber) Blocks(other *Subscriber) bool {
return false
}
// If either side is an admin, blocking is not allowed.
if s.IsAdmin() || other.IsAdmin() {
return false
}
s.muteMu.RLock()
defer s.muteMu.RUnlock()

View File

@ -27,8 +27,9 @@ export default {
return null;
},
profileButtonClass() {
// VIP background.
let result = "";
// VIP background.
if (this.user.vip) {
result = "has-background-vip ";
}
@ -43,6 +44,43 @@ export default {
}
return "";
},
videoButtonClass() {
let result = "";
// VIP background if their cam is set to VIPs only
if ((this.user.video & VideoFlag.Active) && (this.user.video & VideoFlag.VipOnly)) {
result = "has-background-vip ";
}
// Colors and/or cursors.
if ((this.user.video & VideoFlag.Active) && (this.user.video & VideoFlag.NSFW)) {
result += "is-danger is-outlined";
} else if ((this.user.video & VideoFlag.Active) && !(this.user.video & VideoFlag.NSFW)) {
result += "is-info is-outlined";
} else if (this.isVideoNotAllowed) {
result += "cursor-notallowed";
}
return result;
},
videoButtonTitle() {
// Mouse-over title text for the video button.
let parts = ["Open video stream"];
if (this.user.video & VideoFlag.MutualRequired) {
parts.push("mutual video sharing required");
}
if (this.user.video & VideoFlag.MutualOpen) {
parts.push("will auto-open your video");
}
if (this.user.video & VideoFlag.VipOnly) {
parts.push(`${this.vipConfig.Name} only`);
}
return parts.join("; ");
},
avatarURL() {
if (this.user.avatar) {
return this.urlFor(this.user.avatar);
@ -179,13 +217,9 @@ export default {
<!-- Video button (Who List tab) -->
<button type="button" class="button is-small px-2 py-1"
v-if="!isWatchingTab"
:disabled="!(user.video & VideoFlag.Active)" :class="{
'is-danger is-outlined': (user.video & VideoFlag.Active) && (user.video & VideoFlag.NSFW),
'is-info is-outlined': (user.video & VideoFlag.Active) && !(user.video & VideoFlag.NSFW),
'cursor-notallowed': isVideoNotAllowed,
}" :title="`Open video stream` +
(user.video & VideoFlag.MutualRequired ? '; mutual video sharing required' : '') +
(user.video & VideoFlag.MutualOpen ? '; will auto-open your video' : '')"
:disabled="!(user.video & VideoFlag.Active)"
:class="videoButtonClass"
:title="videoButtonTitle"
@click="openVideo()">
<i class="fa" :class="videoIconClass"></i>
</button>