Inline chat moderation UI (#1331)

* - mock detect when user turns into moderator
- add moderator indicator to display on messages and username changer

* also mock moderator flag in message payload about user to display indicator

* add some menu looking icons and a menu of actions

* WIP chat moderators

* Add support for admin promoting a user to moderator

* WIP-
open a more info panel of user+message info; add some a11y to buttons

* style the details panel

* adjust positioning of menus

* Merge fixes. ChatClient->Client ChatServer->Server

* Remove moderator bool placeholders to use real state

* Support inline hiding of messages by moderators

* Support inline banning of chat users

* Cleanup linter warnings

* Puppeteer tests fail after typing take place

* Manually resolve conflicts in chat between moderator feature and develop

Co-authored-by: Gabe Kangas <gabek@real-ity.com>
This commit is contained in:
gingervitis
2021-11-02 19:27:41 -07:00
committed by GitHub
parent 4a52ba9f35
commit 9a91324456
23 changed files with 902 additions and 116 deletions

View File

@@ -66,11 +66,14 @@ var (
)
func (c *Client) sendConnectedClientInfo() {
payload := events.EventPayload{
"type": events.ConnectedUserInfo,
"user": c.User,
payload := events.ConnectedClientInfo{
Event: events.Event{
Type: events.ConnectedUserInfo,
},
User: c.User,
}
payload.SetDefaults()
c.sendPayload(payload)
}
@@ -204,7 +207,7 @@ func (c *Client) startChatRejectionTimeout() {
c.sendAction("You are temporarily blocked from sending chat messages due to perceived flooding.")
}
func (c *Client) sendPayload(payload events.EventPayload) {
func (c *Client) sendPayload(payload interface{}) {
var data []byte
data, err := json.Marshal(payload)
if err != nil {

View File

@@ -0,0 +1,9 @@
package events
import "github.com/owncast/owncast/core/user"
// ConnectedClientInfo represents the information about a connected client.
type ConnectedClientInfo struct {
Event
User *user.User `json:"user"`
}

View File

@@ -2,6 +2,7 @@ package chat
import (
"encoding/json"
"fmt"
"net/http"
"sync"
"time"
@@ -279,6 +280,49 @@ func (s *Server) DisconnectUser(userID string) {
}
}
// SendConnectedClientInfoToUser will find all the connected clients assigned to a user
// and re-send each the connected client info.
func SendConnectedClientInfoToUser(userID string) error {
clients, err := GetClientsForUser(userID)
if err != nil {
return err
}
// Get an updated reference to the user.
user := user.GetUserByID(userID)
if user == nil {
return fmt.Errorf("user not found")
}
if err != nil {
return err
}
for _, client := range clients {
// Update the client's reference to its user.
client.User = user
// Send the update to the client.
client.sendConnectedClientInfo()
}
return nil
}
// SendActionToUser will send system action text to all connected clients
// assigned to a user ID.
func SendActionToUser(userID string, text string) error {
clients, err := GetClientsForUser(userID)
if err != nil {
return err
}
for _, client := range clients {
_server.sendActionToClient(client, text)
}
return nil
}
func (s *Server) eventReceived(event chatClientEvent) {
var typecheck map[string]interface{}
if err := json.Unmarshal(event.data, &typecheck); err != nil {
@@ -342,6 +386,9 @@ func (s *Server) sendActionToClient(c *Client, message string) {
MessageEvent: events.MessageEvent{
Body: message,
},
Event: events.Event{
Type: events.ChatActionSent,
},
}
clientMessage.SetDefaults()
clientMessage.RenderBody()