Skip to content

Commit 43d3081

Browse files
authored
Merge pull request #114 from pepabo/fix/unify-detection-and-extraction
fix: ターゲットとオペレーター検出を統合し誤検出を防止
2 parents 129d251 + 49c754d commit 43d3081

2 files changed

Lines changed: 200 additions & 189 deletions

File tree

bot/bot.go

Lines changed: 36 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -81,101 +81,45 @@ const (
8181
PointCheck
8282
)
8383

84-
// detectPointOperation checks if the message contains a point operation (++, --, ==)
85-
func (b *Bot) detectPointOperation(text string) PointOperation {
86-
// Support both user mentions and emoji patterns
87-
// User mention patterns: <@U123456>++
88-
userPlusPattern := `.*<@[A-Z0-9]+>[  ]*\+\+.*`
89-
userMinusPattern := `.*<@[A-Z0-9]+>[  ]*\-\-.*`
90-
userEqualsPattern := `.*<@[A-Z0-9]+>[  ]*\=\=.*`
91-
92-
// Emoji patterns: :emoji: ++
93-
emojiPlusPattern := `.*:[a-zA-Z0-9_+-]+:[  ]*\+\+.*`
94-
emojiMinusPattern := `.*:[a-zA-Z0-9_+-]+:[  ]*\-\-.*`
95-
emojiEqualsPattern := `.*:[a-zA-Z0-9_+-]+:[  ]*\=\=.*`
96-
97-
// Check for plus patterns
98-
userPlusMatched, err := regexp.MatchString(userPlusPattern, text)
99-
if err != nil {
100-
b.logger.Error("Error matching user plus pattern", "error", err)
101-
return NoOperation
102-
}
103-
emojiPlusMatched, err := regexp.MatchString(emojiPlusPattern, text)
104-
if err != nil {
105-
b.logger.Error("Error matching emoji plus pattern", "error", err)
106-
return NoOperation
107-
}
108-
if userPlusMatched || emojiPlusMatched {
109-
return PointUp
110-
}
84+
// Pre-compiled regexes for detecting point operations with targets
85+
var (
86+
// User mention pattern: <@U123456> ++ (captures user ID and operator)
87+
userOperationPattern = regexp.MustCompile(`<@([A-Z0-9]+)>[  ]*(\+\+|-{2}|={2})`)
88+
// Emoji pattern: :emoji: ++ (captures emoji name and operator)
89+
emojiOperationPattern = regexp.MustCompile(`:([a-zA-Z0-9_+-]+):[  ]*(\+\+|-{2}|={2})`)
90+
)
11191

112-
// Check for minus patterns
113-
userMinusMatched, err := regexp.MatchString(userMinusPattern, text)
114-
if err != nil {
115-
b.logger.Error("Error matching user minus pattern", "error", err)
116-
return NoOperation
117-
}
118-
emojiMinusMatched, err := regexp.MatchString(emojiMinusPattern, text)
119-
if err != nil {
120-
b.logger.Error("Error matching emoji minus pattern", "error", err)
121-
return NoOperation
122-
}
123-
if userMinusMatched || emojiMinusMatched {
92+
// parseOperator converts an operator string to a PointOperation
93+
func parseOperator(op string) PointOperation {
94+
switch op {
95+
case "++":
96+
return PointUp
97+
case "--":
12498
return PointDown
125-
}
126-
127-
// Check for equals patterns
128-
userEqualsMatched, err := regexp.MatchString(userEqualsPattern, text)
129-
if err != nil {
130-
b.logger.Error("Error matching user equals pattern", "error", err)
131-
return NoOperation
132-
}
133-
emojiEqualsMatched, err := regexp.MatchString(emojiEqualsPattern, text)
134-
if err != nil {
135-
b.logger.Error("Error matching emoji equals pattern", "error", err)
136-
return NoOperation
137-
}
138-
if userEqualsMatched || emojiEqualsMatched {
99+
case "==":
139100
return PointCheck
101+
default:
102+
return NoOperation
140103
}
141-
142-
return NoOperation
143104
}
144105

145-
func extractUserID(text string) string {
146-
re := regexp.MustCompile(`<@([A-Z0-9]+)>`)
147-
matches := re.FindStringSubmatch(text)
148-
if len(matches) < 2 {
149-
return ""
106+
// detectOperationAndTarget detects the point operation and extracts the target in one step.
107+
// This ensures the detected operation is associated with the correct target.
108+
func detectOperationAndTarget(text string) (PointOperation, string, bool) {
109+
// User mentions have priority
110+
if matches := userOperationPattern.FindStringSubmatch(text); len(matches) >= 3 {
111+
return parseOperator(matches[2]), matches[1], true
150112
}
151-
return matches[1]
152-
}
153-
154-
// extractEmojiName extracts emoji name from text (e.g., ":sake:" -> "sake")
155-
func extractEmojiName(text string) string {
156-
re := regexp.MustCompile(`:([a-zA-Z0-9_+-]+):`)
157-
matches := re.FindStringSubmatch(text)
158-
if len(matches) < 2 {
159-
return ""
113+
if matches := emojiOperationPattern.FindStringSubmatch(text); len(matches) >= 3 {
114+
return parseOperator(matches[2]), matches[1], false
160115
}
161-
return matches[1]
116+
return NoOperation, "", false
162117
}
163118

164-
// extractTargetFromText extracts either user ID or emoji name from text
165-
func extractTargetFromText(text string) (string, bool) {
166-
// Try to extract user ID first
167-
userID := extractUserID(text)
168-
if userID != "" {
169-
return userID, true // true indicates it's a user ID
170-
}
171-
172-
// If no user ID, try to extract emoji name
173-
emojiName := extractEmojiName(text)
174-
if emojiName != "" {
175-
return emojiName, false // false indicates it's an emoji name
176-
}
177-
178-
return "", false
119+
// detectPointOperation checks if the message contains a point operation (++, --, ==)
120+
func (b *Bot) detectPointOperation(text string) PointOperation {
121+
op, _, _ := detectOperationAndTarget(text)
122+
return op
179123
}
180124

181125
// isUser checks if the given user ID belongs to a user
@@ -189,13 +133,7 @@ func (b *Bot) isUser(userID string) (bool, error) {
189133
}
190134

191135
// handlePointChangeMessage processes a point up or down message
192-
func (b *Bot) handlePointChangeMessage(ev *slackevents.MessageEvent, operation PointOperation) {
193-
// Extract target (user ID or emoji name) from the message
194-
target, isUser := extractTargetFromText(ev.Text)
195-
if target == "" {
196-
b.logger.Error("No target found in message")
197-
return
198-
}
136+
func (b *Bot) handlePointChangeMessage(ev *slackevents.MessageEvent, operation PointOperation, target string, isUser bool) {
199137

200138
// Check if user is trying to point themselves (only applies to user targets)
201139
if isUser && target == ev.User {
@@ -258,14 +196,7 @@ func (b *Bot) handlePointChangeMessage(ev *slackevents.MessageEvent, operation P
258196
b.logger.Debug("Reply sent", "message", message)
259197
}
260198

261-
func (b *Bot) handlePointCheckMessage(ev *slackevents.MessageEvent) {
262-
// Extract target (user ID or emoji name) from the message
263-
target, isUser := extractTargetFromText(ev.Text)
264-
if target == "" {
265-
b.logger.Error("No target found in message")
266-
return
267-
}
268-
199+
func (b *Bot) handlePointCheckMessage(ev *slackevents.MessageEvent, target string, isUser bool) {
269200
ctx := context.Background()
270201
points, err := b.repo.GetPoints(ctx, target)
271202
if err != nil {
@@ -284,13 +215,13 @@ func (b *Bot) handlePointCheckMessage(ev *slackevents.MessageEvent) {
284215
// handleMessageEvent processes a message event
285216
func (b *Bot) handleMessageEvent(ev *slackevents.MessageEvent) {
286217
b.logger.Debug("Received message event", "event", ev)
287-
operation := b.detectPointOperation(ev.Text)
288-
if operation != NoOperation {
289-
b.logger.Info("Point operation detected", "text", ev.Text)
218+
operation, target, isUser := detectOperationAndTarget(ev.Text)
219+
if operation != NoOperation && target != "" {
220+
b.logger.Info("Point operation detected", "text", ev.Text, "target", target, "isUser", isUser)
290221
if operation == PointCheck {
291-
b.handlePointCheckMessage(ev)
222+
b.handlePointCheckMessage(ev, target, isUser)
292223
} else {
293-
b.handlePointChangeMessage(ev, operation)
224+
b.handlePointChangeMessage(ev, operation, target, isUser)
294225
}
295226
}
296227
}

0 commit comments

Comments
 (0)