mirror of
https://github.com/shazow/ssh-chat.git
synced 2025-04-12 15:17:16 +03:00
Merge pull request #383 from shazow/add-mute
chat: Add /mute command for op
This commit is contained in:
commit
9bf66ea992
@ -477,4 +477,38 @@ func InitCommands(c *Commands) {
|
||||
return nil
|
||||
},
|
||||
})
|
||||
|
||||
c.Add(Command{
|
||||
Op: true,
|
||||
Prefix: "/mute",
|
||||
PrefixHelp: "USER",
|
||||
Help: "Toggle muting USER, preventing messages from broadcasting.",
|
||||
Handler: func(room *Room, msg message.CommandMsg) error {
|
||||
if !room.IsOp(msg.From()) {
|
||||
return errors.New("must be op")
|
||||
}
|
||||
|
||||
args := msg.Args()
|
||||
if len(args) == 0 {
|
||||
return errors.New("must specify user")
|
||||
}
|
||||
|
||||
member, ok := room.MemberByID(args[0])
|
||||
if !ok {
|
||||
return errors.New("user not found")
|
||||
}
|
||||
|
||||
setMute := !member.IsMuted()
|
||||
member.SetMute(setMute)
|
||||
id := member.ID()
|
||||
|
||||
if setMute {
|
||||
room.Send(message.NewSystemMsg("Muted: "+id, msg.From()))
|
||||
} else {
|
||||
room.Send(message.NewSystemMsg("Unmuted: "+id, msg.From()))
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
})
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package chat
|
||||
|
||||
import "io"
|
||||
import stdlog "log"
|
||||
import (
|
||||
"io"
|
||||
stdlog "log"
|
||||
)
|
||||
|
||||
var logger *stdlog.Logger
|
||||
|
||||
|
32
chat/room.go
32
chat/room.go
@ -27,6 +27,23 @@ var ErrInvalidName = errors.New("invalid name")
|
||||
type Member struct {
|
||||
*message.User
|
||||
IsOp bool
|
||||
|
||||
// TODO: Move IsOp under mu?
|
||||
|
||||
mu sync.Mutex
|
||||
isMuted bool // When true, messages should not be broadcasted.
|
||||
}
|
||||
|
||||
func (m *Member) IsMuted() bool {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
return m.isMuted
|
||||
}
|
||||
|
||||
func (m *Member) SetMute(muted bool) {
|
||||
m.mu.Lock()
|
||||
defer m.mu.Unlock()
|
||||
m.isMuted = muted
|
||||
}
|
||||
|
||||
// Room definition, also a Set of User Items
|
||||
@ -84,6 +101,20 @@ func (r *Room) HandleMsg(m message.Message) {
|
||||
fromID = fromMsg.From().ID()
|
||||
}
|
||||
|
||||
if fromID != "" {
|
||||
if item, err := r.Members.Get(fromID); err != nil {
|
||||
// Message from a member who is not in the room, this should not happen.
|
||||
logger.Printf("Room received unexpected message from a non-member: %v", m)
|
||||
return
|
||||
} else if member, ok := item.Value().(*Member); ok && member.IsMuted() {
|
||||
// Short circuit message handling for muted users
|
||||
if _, ok = m.(*message.CommandMsg); !ok {
|
||||
member.User.Send(m)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
switch m := m.(type) {
|
||||
case *message.CommandMsg:
|
||||
cmd := *m
|
||||
@ -150,6 +181,7 @@ func (r *Room) Join(u *message.User) (*Member, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO: Remove user ID from sets, probably referring to a prior user.
|
||||
r.History(u)
|
||||
s := fmt.Sprintf("%s joined. (Connected: %d)", u.Name(), r.Members.Len())
|
||||
r.Send(message.NewAnnounceMsg(s))
|
||||
|
@ -158,6 +158,94 @@ func TestIgnore(t *testing.T) {
|
||||
expectOutput(t, buffer, ignored.user.Name()+": hello again!"+message.Newline)
|
||||
}
|
||||
|
||||
func TestMute(t *testing.T) {
|
||||
var buffer []byte
|
||||
|
||||
ch := NewRoom()
|
||||
go ch.Serve()
|
||||
defer ch.Close()
|
||||
|
||||
// Create 3 users, join the room and clear their screen buffers
|
||||
users := make([]ScreenedUser, 3)
|
||||
members := make([]*Member, 3)
|
||||
for i := 0; i < 3; i++ {
|
||||
screen := &MockScreen{}
|
||||
user := message.NewUserScreen(message.SimpleID(fmt.Sprintf("user%d", i)), screen)
|
||||
users[i] = ScreenedUser{
|
||||
user: user,
|
||||
screen: screen,
|
||||
}
|
||||
|
||||
member, err := ch.Join(user)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
members[i] = member
|
||||
}
|
||||
|
||||
for _, u := range users {
|
||||
for i := 0; i < 3; i++ {
|
||||
u.user.HandleMsg(u.user.ConsumeOne())
|
||||
u.screen.Read(&buffer)
|
||||
}
|
||||
}
|
||||
|
||||
// Use some handy variable names for distinguish between roles
|
||||
muter := users[0]
|
||||
muted := users[1]
|
||||
other := users[2]
|
||||
|
||||
members[0].IsOp = true
|
||||
|
||||
// test muting unexisting user
|
||||
if err := sendCommand("/mute test", muter, ch, &buffer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectOutput(t, buffer, "-> Err: user not found"+message.Newline)
|
||||
|
||||
// test muting by non-op
|
||||
if err := sendCommand("/mute "+muted.user.Name(), other, ch, &buffer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectOutput(t, buffer, "-> Err: must be op"+message.Newline)
|
||||
|
||||
// test muting existing user
|
||||
if err := sendCommand("/mute "+muted.user.Name(), muter, ch, &buffer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectOutput(t, buffer, "-> Muted: "+muted.user.Name()+message.Newline)
|
||||
|
||||
if got, want := members[1].IsMuted(), true; got != want {
|
||||
t.Error("muted user failed to set mute flag")
|
||||
}
|
||||
|
||||
// when an emote is sent by a muted user, it should not be displayed for anyone
|
||||
ch.HandleMsg(message.NewPublicMsg("hello!", muted.user))
|
||||
ch.HandleMsg(message.NewEmoteMsg("is crying", muted.user))
|
||||
|
||||
if muter.user.HasMessages() {
|
||||
muter.user.HandleMsg(muter.user.ConsumeOne())
|
||||
muter.screen.Read(&buffer)
|
||||
t.Errorf("muter should not have messages: %s", buffer)
|
||||
}
|
||||
if other.user.HasMessages() {
|
||||
other.user.HandleMsg(other.user.ConsumeOne())
|
||||
other.screen.Read(&buffer)
|
||||
t.Errorf("other should not have messages: %s", buffer)
|
||||
}
|
||||
|
||||
// test unmuting
|
||||
if err := sendCommand("/mute "+muted.user.Name(), muter, ch, &buffer); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expectOutput(t, buffer, "-> Unmuted: "+muted.user.Name()+message.Newline)
|
||||
|
||||
ch.HandleMsg(message.NewPublicMsg("hello again!", muted.user))
|
||||
other.user.HandleMsg(other.user.ConsumeOne())
|
||||
other.screen.Read(&buffer)
|
||||
expectOutput(t, buffer, muted.user.Name()+": hello again!"+message.Newline)
|
||||
}
|
||||
|
||||
func expectOutput(t *testing.T, buffer []byte, expected string) {
|
||||
t.Helper()
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user