diff --git a/internal/kb/suggester.go b/internal/kb/suggester.go index ce195acc..e5eeef94 100644 --- a/internal/kb/suggester.go +++ b/internal/kb/suggester.go @@ -20,6 +20,7 @@ package kb import ( _ "embed" "encoding/json" + "errors" "regexp" "strings" @@ -27,6 +28,8 @@ import ( "golang.org/x/exp/slices" ) +var ErrArticleNotFound = errors.New("KB article not found") + //go:embed kbArticleList.json var articleListString []byte @@ -75,6 +78,20 @@ func GetSuggestions(userInput string) (ArticleList, error) { return articles, nil } +// GetArticleIndex retrieve the index of an article from its url. if the article is not found, ErrArticleNotFound is returned. +func GetArticleIndex(url string) (uint64, error) { + articles, err := GetArticleList() + if err != nil { + return 0, err + } + + index := xslices.IndexFunc(articles, func(article *Article) bool { return strings.EqualFold(article.URL, url) }) + if index == -1 { + return 0, ErrArticleNotFound + } + return uint64(index), nil +} + func simplifyUserInput(input string) string { // replace any sequence not matching of the following with a single space: // - letters in any language (accentuated or not) diff --git a/internal/kb/suggester_test.go b/internal/kb/suggester_test.go index b3a8347e..e4373e2f 100644 --- a/internal/kb/suggester_test.go +++ b/internal/kb/suggester_test.go @@ -52,6 +52,18 @@ func Test_GetSuggestions(t *testing.T) { require.Empty(t, suggestions) } +func Test_GetArticleIndex(t *testing.T) { + index1, err := GetArticleIndex("https://proton.me/support/bridge-for-linux") + require.NoError(t, err) + + index2, err := GetArticleIndex("HTTPS://PROTON.ME/support/bridge-for-linux") + require.NoError(t, err) + require.Equal(t, index1, index2) + + _, err = GetArticleIndex("https://proton.me") + require.ErrorIs(t, err, ErrArticleNotFound) +} + func Test_simplifyUserInput(t *testing.T) { require.Equal(t, "word1 ñóÄ don't déjà 33 pizza", simplifyUserInput(" \nword1 \n\tñóÄ don't\n\n\ndéjà, 33 pizza=🍕\n,\n")) } diff --git a/internal/user/config_status.go b/internal/user/config_status.go index 12b529dc..f40e4d08 100644 --- a/internal/user/config_status.go +++ b/internal/user/config_status.go @@ -20,7 +20,7 @@ package user import ( "context" "encoding/json" - "strings" + "errors" "github.com/ProtonMail/gluon/reporter" "github.com/ProtonMail/proton-bridge/v3/internal/configstatus" @@ -195,26 +195,25 @@ func (user *User) AutoconfigUsed(client string) { } } -func (user *User) ExternalLinkClicked(article string) { +func (user *User) ExternalLinkClicked(url string) { if !user.configStatus.IsPending() { return } - articles, err := kb.GetArticleList() + const externalLinkWasClicked = "External link was clicked." + index, err := kb.GetArticleIndex(url) if err != nil { - user.log.WithError(err).Error("Failed to retrieve list of KB articles.") + if errors.Is(err, kb.ErrArticleNotFound) { + user.log.WithField("report", false).WithField("url", url).Debug(externalLinkWasClicked) + } else { + user.log.WithError(err).Error("Failed to retrieve list of KB articles.") + } return } - var reportToTelemetry bool - for _, a := range articles { - if strings.EqualFold(a.URL, article) { - if err := user.configStatus.RecordLinkClicked(a.Index); err != nil { - user.log.WithError(err).Error("Failed to log LinkClicked in config_status.") - } - reportToTelemetry = true - break - } + if err := user.configStatus.RecordLinkClicked(index); err != nil { + user.log.WithError(err).Error("Failed to log LinkClicked in config_status.") + } else { + user.log.WithField("report", true).WithField("url", url).Debug(externalLinkWasClicked) } - user.log.WithField("report", reportToTelemetry).WithField("article", article).Debug("External link was clicked.") }