120 lines
2.7 KiB
Go
120 lines
2.7 KiB
Go
package isphere
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type Group struct {
|
|
GroupID string
|
|
DisplayName string
|
|
Source string
|
|
Confidence float64
|
|
RawRef string
|
|
}
|
|
|
|
type SearchGroupsQuery struct {
|
|
Query string
|
|
Limit int
|
|
}
|
|
|
|
type SearchGroupsResult struct {
|
|
Groups []Group
|
|
}
|
|
|
|
func SearchGroupsFromMessages(messages []Message, query SearchGroupsQuery) SearchGroupsResult {
|
|
unique := map[string]Group{}
|
|
for _, message := range messages {
|
|
if strings.EqualFold(message.ConversationType, "groupchat") {
|
|
addMessageGroup(unique, message.SenderID)
|
|
addMessageGroup(unique, message.ReceiverID)
|
|
continue
|
|
}
|
|
if isLikelyGroupJID(message.SenderID) {
|
|
addMessageGroup(unique, message.SenderID)
|
|
}
|
|
if isLikelyGroupJID(message.ReceiverID) {
|
|
addMessageGroup(unique, message.ReceiverID)
|
|
}
|
|
}
|
|
|
|
queryText := normalizedSearchText(query.Query)
|
|
groups := make([]Group, 0, len(unique))
|
|
for _, group := range unique {
|
|
if groupMatchesQuery(group, queryText) {
|
|
groups = append(groups, group)
|
|
}
|
|
}
|
|
sort.Slice(groups, func(i, j int) bool {
|
|
leftRank := groupSearchRank(groups[i], queryText)
|
|
rightRank := groupSearchRank(groups[j], queryText)
|
|
if leftRank != rightRank {
|
|
return leftRank < rightRank
|
|
}
|
|
leftID := strings.ToLower(groups[i].GroupID)
|
|
rightID := strings.ToLower(groups[j].GroupID)
|
|
if leftID != rightID {
|
|
return leftID < rightID
|
|
}
|
|
return groups[i].GroupID < groups[j].GroupID
|
|
})
|
|
|
|
limit := query.Limit
|
|
if limit <= 0 || limit > len(groups) {
|
|
limit = len(groups)
|
|
}
|
|
return SearchGroupsResult{Groups: groups[:limit]}
|
|
}
|
|
|
|
func addMessageGroup(unique map[string]Group, id string) {
|
|
trimmed := strings.TrimSpace(id)
|
|
if trimmed == "" || !isLikelyGroupJID(trimmed) {
|
|
return
|
|
}
|
|
key := strings.ToLower(trimmed)
|
|
if _, exists := unique[key]; exists {
|
|
return
|
|
}
|
|
unique[key] = Group{
|
|
GroupID: trimmed,
|
|
DisplayName: trimmed,
|
|
Source: "local_readonly",
|
|
Confidence: 0.6,
|
|
RawRef: "groupchat_jid",
|
|
}
|
|
}
|
|
|
|
func isLikelyGroupJID(id string) bool {
|
|
lower := strings.ToLower(strings.TrimSpace(id))
|
|
return strings.Contains(lower, "conference") || strings.Contains(lower, "muc") || strings.Contains(lower, "group")
|
|
}
|
|
|
|
func groupMatchesQuery(group Group, queryText string) bool {
|
|
if queryText == "" {
|
|
return true
|
|
}
|
|
return strings.Contains(strings.ToLower(group.GroupID), queryText) ||
|
|
strings.Contains(strings.ToLower(group.DisplayName), queryText)
|
|
}
|
|
|
|
func groupSearchRank(group Group, queryText string) int {
|
|
if queryText == "" {
|
|
return 0
|
|
}
|
|
values := []string{
|
|
strings.ToLower(group.GroupID),
|
|
strings.ToLower(group.DisplayName),
|
|
}
|
|
for _, value := range values {
|
|
if value == queryText {
|
|
return 0
|
|
}
|
|
}
|
|
for _, value := range values {
|
|
if strings.HasPrefix(value, queryText) {
|
|
return 1
|
|
}
|
|
}
|
|
return 2
|
|
}
|