refactor: unify user mode processing into shared service layer
Some checks failed
check / check (push) Failing after 2m28s
Some checks failed
check / check (push) Failing after 2m28s
Both the HTTP API and IRC wire protocol handlers now call service.ApplyUserMode/service.QueryUserMode for all user mode operations. The service layer iterates mode strings character by character (the correct IRC approach), ensuring identical behavior regardless of transport. Removed duplicate mode logic from internal/handlers/utility.go (buildUserModeString, applyUserModeChange, applyModeChar) and internal/ircserver/commands.go (buildUmodeString, inline iteration). Added service-level tests for QueryUserMode, ApplyUserMode (single-char, multi-char, invalid input, de-oper, +o rejection).
This commit is contained in:
@@ -730,17 +730,23 @@ func (c *Conn) handleUserMode(
|
||||
|
||||
// Mode query (no mode string).
|
||||
if len(msg.Params) < 2 { //nolint:mnd
|
||||
c.sendNumeric(
|
||||
irc.RplUmodeIs,
|
||||
c.buildUmodeString(ctx),
|
||||
)
|
||||
modes := c.svc.QueryUserMode(ctx, c.sessionID)
|
||||
c.sendNumeric(irc.RplUmodeIs, modes)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
modeStr := msg.Params[1]
|
||||
newModes, err := c.svc.ApplyUserMode(
|
||||
ctx, c.sessionID, msg.Params[1],
|
||||
)
|
||||
if err != nil {
|
||||
var ircErr *service.IRCError
|
||||
if errors.As(err, &ircErr) {
|
||||
c.sendNumeric(ircErr.Code, ircErr.Message)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if len(modeStr) < 2 { //nolint:mnd
|
||||
c.sendNumeric(
|
||||
irc.ErrUmodeUnknownFlag,
|
||||
"Unknown MODE flag",
|
||||
@@ -749,64 +755,7 @@ func (c *Conn) handleUserMode(
|
||||
return
|
||||
}
|
||||
|
||||
adding := modeStr[0] == '+'
|
||||
|
||||
for _, ch := range modeStr[1:] {
|
||||
switch ch {
|
||||
case 'w':
|
||||
_ = c.database.SetSessionWallops(
|
||||
ctx, c.sessionID, adding,
|
||||
)
|
||||
case 'o':
|
||||
if adding {
|
||||
c.sendNumeric(
|
||||
irc.ErrUmodeUnknownFlag,
|
||||
"Unknown MODE flag",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_ = c.database.SetSessionOper(
|
||||
ctx, c.sessionID, false,
|
||||
)
|
||||
default:
|
||||
c.sendNumeric(
|
||||
irc.ErrUmodeUnknownFlag,
|
||||
"Unknown MODE flag",
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
c.sendNumeric(
|
||||
irc.RplUmodeIs,
|
||||
c.buildUmodeString(ctx),
|
||||
)
|
||||
}
|
||||
|
||||
// buildUmodeString returns the current user mode string.
|
||||
func (c *Conn) buildUmodeString(
|
||||
ctx context.Context,
|
||||
) string {
|
||||
modes := "+"
|
||||
|
||||
isOper, err := c.database.IsSessionOper(
|
||||
ctx, c.sessionID,
|
||||
)
|
||||
if err == nil && isOper {
|
||||
modes += "o"
|
||||
}
|
||||
|
||||
isWallops, err := c.database.IsSessionWallops(
|
||||
ctx, c.sessionID,
|
||||
)
|
||||
if err == nil && isWallops {
|
||||
modes += "w"
|
||||
}
|
||||
|
||||
return modes
|
||||
c.sendNumeric(irc.RplUmodeIs, newModes)
|
||||
}
|
||||
|
||||
// handleNames replies with channel member list.
|
||||
|
||||
Reference in New Issue
Block a user