fix: revert .golangci.yml to main, fix all lint issues in code
Some checks failed
check / check (push) Failing after 1m5s
Some checks failed
check / check (push) Failing after 1m5s
- Restore original .golangci.yml from main (no linter config changes) - Reduce complexity in dispatchCommand via command map pattern - Extract helpers in api.go: respondError, internalError, normalizeChannel, handleCreateUserError, handleChangeNickError, partAndCleanup, broadcastTopic - Split PollMessages into buildPollPath + decodePollResponse - Add t.Parallel() to all tests, make subtests independent - Extract test fx providers into named functions to reduce funlen - Use mutex to serialize viper access in parallel tests - Extract PRIVMSG constant, add nolint for gosec false positives - Split long test functions into focused test cases - Add blank lines before expressions per wsl_v5
This commit is contained in:
@@ -49,8 +49,8 @@ func (s *Handlers) requireAuth(
|
||||
) (int64, string, bool) {
|
||||
uid, nick, err := s.authUser(r)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "unauthorized"},
|
||||
s.respondError(w, r,
|
||||
"unauthorized",
|
||||
http.StatusUnauthorized)
|
||||
|
||||
return 0, "", false
|
||||
@@ -120,10 +120,8 @@ func (s *Handlers) HandleCreateSession() http.HandlerFunc {
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "invalid request body",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"invalid request body",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -132,10 +130,8 @@ func (s *Handlers) HandleCreateSession() http.HandlerFunc {
|
||||
req.Nick = strings.TrimSpace(req.Nick)
|
||||
|
||||
if !validNickRe.MatchString(req.Nick) {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "invalid nick format",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"invalid nick format",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -145,21 +141,7 @@ func (s *Handlers) HandleCreateSession() http.HandlerFunc {
|
||||
r.Context(), req.Nick,
|
||||
)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "UNIQUE") {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "nick already taken",
|
||||
},
|
||||
http.StatusConflict)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.log.Error("create user failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
http.StatusInternalServerError)
|
||||
s.handleCreateUserError(w, r, err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -170,6 +152,36 @@ func (s *Handlers) HandleCreateSession() http.HandlerFunc {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Handlers) respondError(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
msg string,
|
||||
code int,
|
||||
) {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": msg}, code)
|
||||
}
|
||||
|
||||
func (s *Handlers) handleCreateUserError(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
err error,
|
||||
) {
|
||||
if strings.Contains(err.Error(), "UNIQUE") {
|
||||
s.respondError(w, r,
|
||||
"nick already taken",
|
||||
http.StatusConflict)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.log.Error("create user failed", "error", err)
|
||||
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
// HandleState returns the current user's info and channels.
|
||||
func (s *Handlers) HandleState() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -184,8 +196,8 @@ func (s *Handlers) HandleState() http.HandlerFunc {
|
||||
if err != nil {
|
||||
s.log.Error("list channels failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -215,8 +227,8 @@ func (s *Handlers) HandleListAllChannels() http.HandlerFunc {
|
||||
"list all channels failed", "error", err,
|
||||
)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -240,10 +252,8 @@ func (s *Handlers) HandleChannelMembers() http.HandlerFunc {
|
||||
r.Context(), name,
|
||||
)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "channel not found",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"channel not found",
|
||||
http.StatusNotFound)
|
||||
|
||||
return
|
||||
@@ -257,8 +267,8 @@ func (s *Handlers) HandleChannelMembers() http.HandlerFunc {
|
||||
"channel members failed", "error", err,
|
||||
)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -299,8 +309,8 @@ func (s *Handlers) HandleGetMessages() http.HandlerFunc {
|
||||
"poll messages failed", "error", err,
|
||||
)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -350,8 +360,8 @@ func (s *Handlers) longPoll(
|
||||
if err != nil {
|
||||
s.log.Error("poll messages failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -382,10 +392,8 @@ func (s *Handlers) HandleSendCommand() http.HandlerFunc {
|
||||
|
||||
err := json.NewDecoder(r.Body).Decode(&req)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "invalid request body",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"invalid request body",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -397,10 +405,8 @@ func (s *Handlers) HandleSendCommand() http.HandlerFunc {
|
||||
req.To = strings.TrimSpace(req.To)
|
||||
|
||||
if req.Command == "" {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "command required",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"command required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -476,8 +482,8 @@ func (s *Handlers) handlePrivmsg(
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
if to == "" {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "to field required"},
|
||||
s.respondError(w, r,
|
||||
"to field required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -485,8 +491,8 @@ func (s *Handlers) handlePrivmsg(
|
||||
|
||||
lines := bodyLines()
|
||||
if len(lines) == 0 {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "body required"},
|
||||
s.respondError(w, r,
|
||||
"body required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -514,8 +520,8 @@ func (s *Handlers) handleChannelMsg(
|
||||
r.Context(), to,
|
||||
)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "channel not found"},
|
||||
s.respondError(w, r,
|
||||
"channel not found",
|
||||
http.StatusNotFound)
|
||||
|
||||
return
|
||||
@@ -529,8 +535,8 @@ func (s *Handlers) handleChannelMsg(
|
||||
"get channel members failed", "error", err,
|
||||
)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -542,8 +548,8 @@ func (s *Handlers) handleChannelMsg(
|
||||
if err != nil {
|
||||
s.log.Error("send message failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -565,8 +571,8 @@ func (s *Handlers) handleDirectMsg(
|
||||
r.Context(), to,
|
||||
)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "user not found"},
|
||||
s.respondError(w, r,
|
||||
"user not found",
|
||||
http.StatusNotFound)
|
||||
|
||||
return
|
||||
@@ -583,8 +589,8 @@ func (s *Handlers) handleDirectMsg(
|
||||
if err != nil {
|
||||
s.log.Error("send dm failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
@@ -595,6 +601,27 @@ func (s *Handlers) handleDirectMsg(
|
||||
http.StatusCreated)
|
||||
}
|
||||
|
||||
func normalizeChannel(name string) string {
|
||||
if !strings.HasPrefix(name, "#") {
|
||||
return "#" + name
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func (s *Handlers) internalError(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
msg string,
|
||||
err error,
|
||||
) {
|
||||
s.log.Error(msg, "error", err)
|
||||
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
func (s *Handlers) handleJoin(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
@@ -602,23 +629,18 @@ func (s *Handlers) handleJoin(
|
||||
nick, to string,
|
||||
) {
|
||||
if to == "" {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "to field required"},
|
||||
s.respondError(w, r,
|
||||
"to field required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
channel := to
|
||||
if !strings.HasPrefix(channel, "#") {
|
||||
channel = "#" + channel
|
||||
}
|
||||
channel := normalizeChannel(to)
|
||||
|
||||
if !validChannelRe.MatchString(channel) {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "invalid channel name",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"invalid channel name",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -628,13 +650,8 @@ func (s *Handlers) handleJoin(
|
||||
r.Context(), channel,
|
||||
)
|
||||
if err != nil {
|
||||
s.log.Error(
|
||||
"get/create channel failed", "error", err,
|
||||
)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
http.StatusInternalServerError)
|
||||
s.internalError(w, r,
|
||||
"get/create channel failed", err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -643,11 +660,8 @@ func (s *Handlers) handleJoin(
|
||||
r.Context(), chID, uid,
|
||||
)
|
||||
if err != nil {
|
||||
s.log.Error("join channel failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
http.StatusInternalServerError)
|
||||
s.internalError(w, r,
|
||||
"join channel failed", err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -676,31 +690,36 @@ func (s *Handlers) handlePart(
|
||||
body json.RawMessage,
|
||||
) {
|
||||
if to == "" {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "to field required"},
|
||||
s.respondError(w, r,
|
||||
"to field required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
channel := to
|
||||
if !strings.HasPrefix(channel, "#") {
|
||||
channel = "#" + channel
|
||||
}
|
||||
channel := normalizeChannel(to)
|
||||
|
||||
chID, err := s.params.Database.GetChannelByName(
|
||||
r.Context(), channel,
|
||||
)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "channel not found",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"channel not found",
|
||||
http.StatusNotFound)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.partAndCleanup(w, r, chID, uid, nick, channel, body)
|
||||
}
|
||||
|
||||
func (s *Handlers) partAndCleanup(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
chID, uid int64,
|
||||
nick, channel string,
|
||||
body json.RawMessage,
|
||||
) {
|
||||
memberIDs, _ := s.params.Database.GetChannelMemberIDs(
|
||||
r.Context(), chID,
|
||||
)
|
||||
@@ -709,15 +728,12 @@ func (s *Handlers) handlePart(
|
||||
r, "PART", nick, channel, body, memberIDs,
|
||||
)
|
||||
|
||||
err = s.params.Database.PartChannel(
|
||||
err := s.params.Database.PartChannel(
|
||||
r.Context(), chID, uid,
|
||||
)
|
||||
if err != nil {
|
||||
s.log.Error("part channel failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
http.StatusInternalServerError)
|
||||
s.internalError(w, r,
|
||||
"part channel failed", err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -743,10 +759,8 @@ func (s *Handlers) handleNick(
|
||||
) {
|
||||
lines := bodyLines()
|
||||
if len(lines) == 0 {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "body required (new nick)",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"body required (new nick)",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -755,8 +769,8 @@ func (s *Handlers) handleNick(
|
||||
newNick := strings.TrimSpace(lines[0])
|
||||
|
||||
if !validNickRe.MatchString(newNick) {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "invalid nick"},
|
||||
s.respondError(w, r,
|
||||
"invalid nick",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -776,21 +790,7 @@ func (s *Handlers) handleNick(
|
||||
r.Context(), uid, newNick,
|
||||
)
|
||||
if err != nil {
|
||||
if strings.Contains(err.Error(), "UNIQUE") {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "nick already in use",
|
||||
},
|
||||
http.StatusConflict)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.log.Error("change nick failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
http.StatusInternalServerError)
|
||||
s.handleChangeNickError(w, r, err)
|
||||
|
||||
return
|
||||
}
|
||||
@@ -804,6 +804,22 @@ func (s *Handlers) handleNick(
|
||||
http.StatusOK)
|
||||
}
|
||||
|
||||
func (s *Handlers) handleChangeNickError(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
err error,
|
||||
) {
|
||||
if strings.Contains(err.Error(), "UNIQUE") {
|
||||
s.respondError(w, r,
|
||||
"nick already in use",
|
||||
http.StatusConflict)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.internalError(w, r, "change nick failed", err)
|
||||
}
|
||||
|
||||
func (s *Handlers) broadcastNick(
|
||||
r *http.Request,
|
||||
uid int64,
|
||||
@@ -858,8 +874,8 @@ func (s *Handlers) handleTopic(
|
||||
bodyLines func() []string,
|
||||
) {
|
||||
if to == "" {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "to field required"},
|
||||
s.respondError(w, r,
|
||||
"to field required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -867,43 +883,40 @@ func (s *Handlers) handleTopic(
|
||||
|
||||
lines := bodyLines()
|
||||
if len(lines) == 0 {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "body required (topic text)",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"body required (topic text)",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
topic := strings.Join(lines, " ")
|
||||
|
||||
channel := to
|
||||
if !strings.HasPrefix(channel, "#") {
|
||||
channel = "#" + channel
|
||||
}
|
||||
channel := normalizeChannel(to)
|
||||
|
||||
err := s.params.Database.SetTopic(
|
||||
r.Context(), channel, topic,
|
||||
)
|
||||
if err != nil {
|
||||
s.log.Error("set topic failed", "error", err)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
http.StatusInternalServerError)
|
||||
s.internalError(w, r, "set topic failed", err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s.broadcastTopic(w, r, nick, channel, topic, body)
|
||||
}
|
||||
|
||||
func (s *Handlers) broadcastTopic(
|
||||
w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
nick, channel, topic string,
|
||||
body json.RawMessage,
|
||||
) {
|
||||
chID, err := s.params.Database.GetChannelByName(
|
||||
r.Context(), channel,
|
||||
)
|
||||
if err != nil {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "channel not found",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"channel not found",
|
||||
http.StatusNotFound)
|
||||
|
||||
return
|
||||
@@ -991,10 +1004,8 @@ func (s *Handlers) HandleGetHistory() http.HandlerFunc {
|
||||
|
||||
target := r.URL.Query().Get("target")
|
||||
if target == "" {
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{
|
||||
"error": "target required",
|
||||
},
|
||||
s.respondError(w, r,
|
||||
"target required",
|
||||
http.StatusBadRequest)
|
||||
|
||||
return
|
||||
@@ -1019,8 +1030,8 @@ func (s *Handlers) HandleGetHistory() http.HandlerFunc {
|
||||
"get history failed", "error", err,
|
||||
)
|
||||
|
||||
s.respondJSON(w, r,
|
||||
map[string]string{"error": "internal error"},
|
||||
s.respondError(w, r,
|
||||
"internal error",
|
||||
http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user