1
Fork 0

Implement selective clearchat.

This commit is contained in:
Juliusz Chroboczek 2024-08-11 23:57:11 +02:00
parent eb72069c9b
commit 123d51e011
4 changed files with 129 additions and 15 deletions

View File

@ -799,10 +799,42 @@ func (g *Group) WallOps(message string) {
const maxChatHistory = 50
func (g *Group) ClearChatHistory() {
// deleteFunc is just like slices.DeleteFunc.
// Remove this once we require Go 1.21.
func deleteFunc[S ~[]E, E any](s S, f func(E) bool) S {
i := 0
for i = range s {
if f(s[i]) {
break
}
}
if i >= len(s) {
return s
}
for j := i + 1; j < len(s); j++ {
if v := s[j]; !f(v) {
s[i] = v
i++
}
}
var zero E
for j := i; j < len(s); j++ {
s[j] = zero
}
return s[:i]
}
func (g *Group) ClearChatHistory(id string, userId string) {
g.mu.Lock()
defer g.mu.Unlock()
g.history = nil
if id == "" && userId == "" {
g.history = nil
return
}
g.history = deleteFunc(g.history, func(e ChatHistoryEntry) bool {
return e.Source == userId && (id == "" || e.Id == id)
})
}
func (g *Group) AddToChatHistory(id, source string, user *string, time time.Time, kind string, value interface{}) {

View File

@ -4,9 +4,9 @@ import (
"encoding/json"
"errors"
"fmt"
"sort"
"testing"
"time"
"sort"
)
func TestGroup(t *testing.T) {
@ -54,7 +54,10 @@ func TestChatHistory(t *testing.T) {
}
user := "user"
for i := 0; i < 2*maxChatHistory; i++ {
g.AddToChatHistory("id", "source", &user, time.Now(), "",
g.AddToChatHistory(
fmt.Sprintf("id-%v", i),
fmt.Sprintf("source-%v", i%4),
&user, time.Now(), "",
fmt.Sprintf("%v", i),
)
}
@ -63,10 +66,33 @@ func TestChatHistory(t *testing.T) {
t.Errorf("Expected %v, got %v", maxChatHistory, len(g.history))
}
for i, s := range h {
e := fmt.Sprintf("%v", i+maxChatHistory)
if s.Value.(string) != e {
t.Errorf("Expected %v, got %v", e, s)
j := i + maxChatHistory
if s.Id != fmt.Sprintf("id-%v", j) {
t.Errorf("Expected %v, got %v", j, s.Id)
}
if s.Source != fmt.Sprintf("source-%v", j%4) {
t.Errorf("Expected %v, got %v", j%4, s.Id)
}
if s.Value.(string) != fmt.Sprintf("%v", j) {
t.Errorf("Expected %v, got %v", j, s.Value)
}
}
l := len(h)
j := maxChatHistory + 4
g.ClearChatHistory(
fmt.Sprintf("id-%v", j), fmt.Sprintf("source-%v", j%4),
)
if lh := len(g.GetChatHistory()); lh != l-1 {
t.Errorf("Expected %v, got %v", l-1, lh)
}
g.ClearChatHistory("", fmt.Sprintf("source-%v", j%4))
if lh := len(g.GetChatHistory()); lh != l*3/4 {
t.Errorf("Expected %v, got %v", l*3/4, lh)
}
g.ClearChatHistory("", "");
if lh := len(g.GetChatHistory()); lh != 0 {
t.Errorf("Expected 0, got %v", lh)
}
}

View File

@ -1636,10 +1636,27 @@ func handleClientMessage(c *webClient, m clientMessage) error {
if !member("op", c.permissions) {
return c.error(group.UserError("not authorised"))
}
g.ClearChatHistory()
var id, userId string
if m.Value != nil {
value, ok := m.Value.(map[string]any)
if !ok {
return c.error(group.UserError(
"bad value in clearchat",
))
}
id, _ = value["id"].(string)
userId, _ = value["userId"].(string)
if userId == "" && id != "" {
return c.error(group.UserError(
"bad value in clearchat",
))
}
}
g.ClearChatHistory(id, userId)
m := clientMessage{
Type: "usermessage",
Kind: "clearchat",
Value: m.Value,
Privileged: true,
}
err := broadcast(g.GetClients(nil), m)

View File

@ -2781,13 +2781,16 @@ function gotUserMessage(id, dest, username, time, privileged, kind, error, messa
let by = username ? ' by ' + username : '';
displayWarning(`You have been muted${by}`);
break;
case 'clearchat':
case 'clearchat': {
if(!privileged) {
console.error(`Got unprivileged message of kind ${kind}`);
return;
}
clearChat();
let id = message && message.id;
let userId = message && message.userId;
clearChat(id, userId);
break;
}
case 'token':
if(!privileged) {
console.error(`Got unprivileged message of kind ${kind}`);
@ -3071,17 +3074,31 @@ function chatMessageMenu(elt) {
serverConnection.permissions.indexOf('op') >= 0))
return;
let messageId = elt.dataset.id;
let peerId = elt.dataset.peerId;
if(!peerId)
return;
let username = elt.dataset.username;
let u = username ? ' ' + username : '';
let u = username || 'user';
let items = [];
items.push({label: 'Identify user' + u, onClick: () => {
if(messageId)
items.push({label: 'Delete message', onClick: () => {
serverConnection.groupAction('clearchat', {
id: messageId,
userId: peerId,
});
}});
items.push({label: `Delete all from ${u}`,
onClick: () => {
serverConnection.groupAction('clearchat', {
userId: peerId,
});
}});
items.push({label: `Identify ${u}`, onClick: () => {
serverConnection.userAction('identify', peerId);
}});
items.push({label: 'Kick out user' + u, onClick: () => {
items.push({label: `Kick out ${u}`, onClick: () => {
serverConnection.userAction('kick', peerId);
}});
@ -3098,9 +3115,31 @@ function localMessage(message) {
return addToChatbox(null, null, null, null, new Date(), false, false, '', message);
}
function clearChat() {
/**
* @param {string} [id]
* @param {string} [userId]
*/
function clearChat(id, userId) {
lastMessage = {};
document.getElementById('box').textContent = '';
let box = document.getElementById('box');
if(!id && !userId) {
box.textContent = '';
return;
}
let elts = box.children;
for(let i = 0; i < elts.length; i++) {
let row = elts.item(i);
if(!(row instanceof HTMLDivElement))
continue;
let div = row.firstChild;
console.log(div);
if(!(div instanceof HTMLDivElement))
continue;
if((!id || div.dataset.id === id) && div.dataset.peerId === userId)
box.removeChild(row);
}
}
/**