Skip to content

Commit ad792e2

Browse files
authored
[i18n] slack support (#193)
1 parent e9d317f commit ad792e2

File tree

11 files changed

+95
-32
lines changed

11 files changed

+95
-32
lines changed

internal/bots/discord/listeners/listeners.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ func (b *Listeners) smrCmd(event *events.ApplicationCommandInteractionCreate, da
9090
Platform: bot.FromPlatformDiscord,
9191
URL: urlString,
9292
ChannelID: event.Channel().ID().String(),
93-
// TODO: support i18n for discord and slack
93+
// TODO: support i18n for discord
9494
Language: "zh-CN",
9595
})
9696
if err != nil {

internal/bots/slack/handlers/handlers.go

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,17 @@ import (
66
"net/http"
77
"strings"
88

9+
"github.com/gin-gonic/gin"
910
"github.com/nekomeowww/insights-bot/internal/services/smr"
1011
"github.com/nekomeowww/insights-bot/internal/services/smr/smrqueue"
1112

12-
"github.com/gin-gonic/gin"
1313
"github.com/nekomeowww/insights-bot/ent"
1414
"github.com/nekomeowww/insights-bot/ent/slackoauthcredentials"
1515
"github.com/nekomeowww/insights-bot/internal/configs"
1616
"github.com/nekomeowww/insights-bot/internal/datastore"
1717
"github.com/nekomeowww/insights-bot/pkg/bots/slackbot"
1818
"github.com/nekomeowww/insights-bot/pkg/bots/slackbot/services"
19+
"github.com/nekomeowww/insights-bot/pkg/i18n"
1920
"github.com/nekomeowww/insights-bot/pkg/logger"
2021
"github.com/nekomeowww/insights-bot/pkg/types/bot"
2122
types "github.com/nekomeowww/insights-bot/pkg/types/smr"
@@ -38,6 +39,7 @@ type NewHandlersParam struct {
3839
Ent *datastore.Ent
3940
SmrQueue *smrqueue.Queue
4041
Services *services.Services
42+
I18n *i18n.I18n
4143
}
4244

4345
type Handlers struct {
@@ -46,6 +48,7 @@ type Handlers struct {
4648
ent *datastore.Ent
4749
smrQueue *smrqueue.Queue
4850
services *services.Services
51+
i18n *i18n.I18n
4952
}
5053

5154
func NewHandlers() func(param NewHandlersParam) *Handlers {
@@ -56,6 +59,7 @@ func NewHandlers() func(param NewHandlersParam) *Handlers {
5659
logger: param.Logger,
5760
smrQueue: param.SmrQueue,
5861
services: param.Services,
62+
i18n: param.I18n,
5963
}
6064
}
6165
}
@@ -83,6 +87,30 @@ func (h *Handlers) PostCommandInfo(ctx *gin.Context) {
8387
zap.String("channel_id", body.ChannelID),
8488
)
8589

90+
// get user locale, navie code, maybe need to refactor
91+
token, err := h.ent.SlackOAuthCredentials.Query().
92+
Where(slackoauthcredentials.TeamID(body.TeamID)).
93+
First(context.Background())
94+
95+
if err != nil {
96+
h.logger.Warn("smr service: failed to get team's access token when get user locale",
97+
zap.Error(err),
98+
)
99+
100+
return
101+
}
102+
103+
slackCli := slackbot.NewSlackCli(nil, h.config.Slack.ClientID, h.config.Slack.ClientSecret, token.RefreshToken, token.AccessToken)
104+
user, err := slackCli.GetUserInfoWithTokenExpirationCheck(body.UserID, h.services.NewStoreFuncForRefresh(body.TeamID))
105+
106+
if err != nil {
107+
h.logger.Warn("smr service: failed to user locale",
108+
zap.Error(err),
109+
)
110+
111+
return
112+
}
113+
86114
urlString := body.Text
87115

88116
urlString = strings.TrimSpace(urlString)
@@ -93,13 +121,12 @@ func (h *Handlers) PostCommandInfo(ctx *gin.Context) {
93121
err, originErr := smr.CheckUrl(urlString)
94122
if err != nil {
95123
if smr.IsUrlCheckError(err) {
96-
// TODO: i18n support for slack
97-
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(smr.FormatUrlCheckError(err, bot.FromPlatformSlack, "", nil)))
124+
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(smr.FormatUrlCheckError(err, bot.FromPlatformSlack, user.Locale, nil)))
98125
return
99126
}
100127

101-
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage("出现了一些问题,可以再试试?"))
102-
h.logger.Warn("discord: failed to send error message", zap.Error(err), zap.NamedError("original_error", originErr))
128+
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(h.i18n.TWithLanguage(user.Locale, "commands.groups.summarization.commands.smr.failedToRead")))
129+
h.logger.Warn("slack: failed to send error message", zap.Error(err), zap.NamedError("original_error", originErr))
103130

104131
return
105132
}
@@ -111,11 +138,11 @@ func (h *Handlers) PostCommandInfo(ctx *gin.Context) {
111138
if err != nil {
112139
h.logger.Warn("slack: failed to get team's access token", zap.Error(err))
113140
if ent.IsNotFound(err) {
114-
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage("本应用没有权限向这个频道发送消息,尝试重新安装一下?"))
141+
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(h.i18n.TWithLanguage(user.Locale, "commands.groups.summarization.commands.smr.permissionDenied")))
115142
return
116143
}
117144

118-
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage("出现了一些问题,可以再试试?"))
145+
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(h.i18n.TWithLanguage(user.Locale, "commands.groups.summarization.commands.smr.failedToRead")))
119146

120147
return
121148
}
@@ -126,18 +153,18 @@ func (h *Handlers) PostCommandInfo(ctx *gin.Context) {
126153
URL: urlString,
127154
ChannelID: body.ChannelID,
128155
TeamID: body.TeamID,
129-
// TODO: support i18n for discord and slack
156+
// TODO: support i18n for discord
130157
Language: "zh-CN",
131158
})
132159
if err != nil {
133160
h.logger.Warn("slack: failed to add task", zap.Error(err))
134-
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage("量子速读请求发送失败了,可以再试试?"))
161+
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(h.i18n.TWithLanguage(user.Locale, "commands.groups.summarization.commands.smr.failedToRead")))
135162

136163
return
137164
}
138165

139166
// response
140-
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage("请稍等,量子速读中..."))
167+
ctx.JSON(http.StatusOK, slackbot.NewSlackWebhookMessage(h.i18n.TWithLanguage(user.Locale, "commands.groups.summarization.commands.smr.reading")))
141168
}
142169

143170
// GetInstallAuth Receive auth code and request for access token.

internal/bots/slack/slack.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@ package slack
22

33
import (
44
"context"
5+
"net/http"
6+
57
"github.com/nekomeowww/insights-bot/internal/bots/slack/handlers"
68
"github.com/nekomeowww/insights-bot/internal/configs"
79
"github.com/nekomeowww/insights-bot/pkg/bots/slackbot"
810
"github.com/nekomeowww/insights-bot/pkg/bots/slackbot/services"
911
"github.com/nekomeowww/insights-bot/pkg/logger"
1012
"go.uber.org/fx"
11-
"net/http"
1213
)
1314

1415
func NewModules() fx.Option {

internal/bots/telegram/handlers/summarize/smr_command.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func (h *Handlers) Handle(c *tgbot.Context) (tgbot.Response, error) {
2222
}
2323
if urlString == "" {
2424
return nil, tgbot.
25-
NewMessageError(c.T("commands.groups.summarization.commands.smr.noLinksFound")).
25+
NewMessageError(c.T("commands.groups.summarization.commands.smr.noLinksFound.telegram")).
2626
WithReply(c.Update.Message)
2727
}
2828

internal/services/smr/processor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ func (s *Service) processor(info types.TaskInfo) {
174174
smrResult, err := s.model.SummarizeInputURL(ctx, info.URL, info.Platform)
175175
if err != nil {
176176
s.logger.Warn("smr service: summarization failed", zap.Error(err))
177-
// TODO: support i18n for discord and slack
177+
// TODO: support i18n for discord
178178
errStr := s.processError(err, lo.Ternary(info.Language == "", "en", info.Language))
179179
s.sendResult(nil, info, errStr)
180180

internal/services/smr/utils.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,18 @@ func FormatUrlCheckError(err error, platform bot.FromPlatform, language string,
3030
case errors.Is(err, ErrNoLink):
3131
switch platform {
3232
case bot.FromPlatformTelegram:
33-
return i18n.TWithLanguage(language, "commands.groups.summarization.commands.smr.noLinksFound")
34-
// TODO: support i18n for discord and slack
33+
return i18n.TWithLanguage(language, "commands.groups.summarization.commands.smr.noLinksFound.telegram")
3534
case bot.FromPlatformDiscord, bot.FromPlatformSlack:
36-
return "没有找到链接,可以发送一个有效的链接吗?用法:`/smr <链接>`"
35+
return i18n.TWithLanguage(language, "commands.groups.summarization.commands.smr.noLinksFound.slackOrDiscord")
3736
default:
3837
return err.Error()
3938
}
4039
case errors.Is(err, ErrParse), errors.Is(err, ErrScheme):
4140
switch platform {
4241
case bot.FromPlatformTelegram:
43-
return i18n.TWithLanguage(language, "commands.groups.summarization.commands.smr.invalidLink")
42+
return i18n.TWithLanguage(language, "commands.groups.summarization.commands.smr.invalidLink.telegram")
4443
case bot.FromPlatformDiscord, bot.FromPlatformSlack:
45-
// TODO: support i18n for discord and slack
46-
return "你发来的链接无法被理解,可以重新发一个试试。用法:`/smr <链接>`"
44+
return i18n.TWithLanguage(language, "commands.groups.summarization.commands.smr.invalidLink.slackOrDiscord")
4745
default:
4846
return err.Error()
4947
}

locales/en.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,18 @@ commands:
7070
commands:
7171
smr:
7272
help: 量子速读网页文章(也支持在频道中使用) 用法:/smr <code>&lt;链接&gt;</code>
73-
noLinksFound: 没有找到链接,可以发送一个有效的链接吗?用法:<code>/smr &lt;链接&gt;</code>
74-
invalidLink: 你发来的链接无法被理解,可以重新发一个试试。用法:<code>/smr &lt;链接&gt;</code>
73+
noLinksFound:
74+
telegram: 没有找到链接,可以发送一个有效的链接吗?用法:<code>/smr &lt;链接&gt;</code>
75+
slackOrDiscord: 你发来的链接无法被理解,可以重新发一个试试。用法:`/smr <链接>`
76+
invalidLink:
77+
telegram: 你发来的链接无法被理解,可以重新发一个试试。用法:<code>/smr &lt;链接&gt;</code>
78+
slackOrDiscord: 你发来的链接无法被理解,可以重新发一个试试。用法:`/smr <链接>`
7579
reading: 请稍等,量子速读中...
7680
rateLimitExceeded: 很抱歉,您的操作触发了我们的限制机制,为了保证系统的可用性,本命令每最多 {{ .Seconds }} 秒使用一次,请您耐心等待 {{ .SecondsToBeWaited }} 秒后再试,感谢您的理解和支持。
7781
failedToRead: 量子速读失败了,可以再试试?
7882
failedToReadDueToFailedToFetch: 量子速读的链接读取失败了哦。可以再试试?
7983
contentNotSupported: 暂时不支持量子速读这样的内容呢,可以换个别的链接试试。
84+
permissionDenied: No permission to send message, please try to reinstall this APP
8085

8186
prompts:
8287
smr:

locales/zh-CN.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,18 @@ commands:
2525
commands:
2626
smr:
2727
help: 量子速读网页文章(也支持在频道中使用) 用法:/smr <code>&lt;链接&gt;</code>
28-
noLinksFound: 没有找到链接,可以发送一个有效的链接吗?用法:<code>/smr &lt;链接&gt;</code>
29-
invalidLink: 你发来的链接无法被理解,可以重新发一个试试。用法:<code>/smr &lt;链接&gt;</code>
28+
noLinksFound:
29+
telegram: 没有找到链接,可以发送一个有效的链接吗?用法:<code>/smr &lt;链接&gt;</code>
30+
slackOrDiscord: 没有找到链接,可以发送一个有效的链接吗?用法:`/smr <链接>`
31+
invalidLink:
32+
telegram: 你发来的链接无法被理解,可以重新发一个试试。用法:<code>/smr &lt;链接&gt;</code>
33+
slackOrDiscord: 你发来的链接无法被理解,可以重新发一个试试。用法:`/smr <链接>`
3034
reading: 请稍等,量子速读中...
3135
rateLimitExceeded: 很抱歉,您的操作触发了我们的限制机制,为了保证系统的可用性,本命令每最多 {{ .Seconds }} 秒使用一次,请您耐心等待 {{ .SecondsToBeWaited }} 秒后再试,感谢您的理解和支持。
3236
failedToRead: 量子速读失败了,可以再试试?
3337
failedToReadDueToFailedToFetch: 量子速读的链接读取失败了哦。可以再试试?
3438
contentNotSupported: 暂时不支持量子速读这样的内容呢,可以换个别的链接试试。
39+
permissionDenied: 本应用没有权限向这个频道发送消息,尝试重新安装一下?
3540

3641
modules:
3742
telegram:

pkg/bots/slackbot/services/services.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package services
33
import (
44
"context"
55

6+
"github.com/nekomeowww/insights-bot/internal/configs"
67
"github.com/nekomeowww/insights-bot/internal/datastore"
78
"github.com/nekomeowww/insights-bot/pkg/logger"
89
"go.uber.org/fx"
@@ -16,18 +17,21 @@ type NewServicesParam struct {
1617

1718
Logger *logger.Logger
1819
Ent *datastore.Ent
20+
Config *configs.Config
1921
}
2022

2123
type Services struct {
2224
logger *logger.Logger
23-
ent *datastore.Ent
25+
Ent *datastore.Ent
26+
Config *configs.Config
2427
}
2528

2629
func NewServices() func(param NewServicesParam) *Services {
2730
return func(param NewServicesParam) *Services {
2831
return &Services{
2932
logger: param.Logger,
30-
ent: param.Ent,
33+
Ent: param.Ent,
34+
Config: param.Config,
3135
}
3236
}
3337
}
@@ -39,7 +43,7 @@ func (b *Services) NewStoreFuncForRefresh(teamID string) func(accessToken, refre
3943
}
4044

4145
func (b *Services) CreateOrUpdateSlackCredential(teamID, accessToken, refreshToken string) error {
42-
affectRows, err := b.ent.SlackOAuthCredentials.Update().
46+
affectRows, err := b.Ent.SlackOAuthCredentials.Update().
4347
Where(slackoauthcredentials.TeamID(teamID)).
4448
SetAccessToken(accessToken).
4549
SetRefreshToken(refreshToken).
@@ -51,7 +55,7 @@ func (b *Services) CreateOrUpdateSlackCredential(teamID, accessToken, refreshTok
5155

5256
if affectRows == 0 {
5357
// create
54-
err = b.ent.SlackOAuthCredentials.Create().
58+
err = b.Ent.SlackOAuthCredentials.Create().
5559
SetTeamID(teamID).
5660
SetAccessToken(accessToken).
5761
SetRefreshToken(refreshToken).

pkg/bots/slackbot/services/services_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,13 @@ func newTestServices() *Services {
3232
}
3333

3434
return &Services{
35-
ent: ent,
35+
Ent: ent,
3636
logger: logger,
3737
}
3838
}
3939

4040
func cleanSlackCredential(s *Services, r *require.Assertions) {
41-
_, err := s.ent.SlackOAuthCredentials.Delete().Exec(context.Background())
41+
_, err := s.Ent.SlackOAuthCredentials.Delete().Exec(context.Background())
4242
r.Empty(err)
4343
}
4444

@@ -58,7 +58,7 @@ func TestSlackBot_createNewSlackCredential(t *testing.T) {
5858
r.Empty(s.CreateOrUpdateSlackCredential(expectTeamID, expectAccessToken, expectRefreshToken))
5959

6060
// query
61-
cre, err := s.ent.SlackOAuthCredentials.Query().First(context.Background())
61+
cre, err := s.Ent.SlackOAuthCredentials.Query().First(context.Background())
6262
r.Empty(err)
6363
a.Equal(expectTeamID, cre.TeamID)
6464
a.Equal(expectAccessToken, cre.AccessToken)
@@ -79,7 +79,7 @@ func TestSlackBot_createNewSlackCredential(t *testing.T) {
7979
r.Empty(s.CreateOrUpdateSlackCredential(expectTeamID, expectAccessToken, expectRefreshToken))
8080

8181
// query
82-
cre, err := s.ent.SlackOAuthCredentials.Query().First(context.Background())
82+
cre, err := s.Ent.SlackOAuthCredentials.Query().First(context.Background())
8383
r.Empty(err)
8484
a.Equal(expectTeamID, cre.TeamID)
8585
a.Equal(expectAccessToken, cre.AccessToken)

pkg/bots/slackbot/slackbot.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,29 @@ func (cli *Client) SendMessageWithTokenExpirationCheck(channel string, storeFn S
8383
return cli.SendMessageWithTokenExpirationCheck(channel, storeFn, options...)
8484
}
8585

86+
// GetUserInfoWithTokenExpirationCheck will checks if the error is "token_expired" error,
87+
// if so, will get new token and try again.
88+
func (cli *Client) GetUserInfoWithTokenExpirationCheck(channel string, storeFn StoreNewTokenFunc, options ...slack.MsgOption) (slackUser *slack.User, err error) {
89+
slackUser, err = cli.GetUserInfo(channel)
90+
if err == nil || err.Error() != "token_expired" {
91+
return
92+
}
93+
94+
resp, err := slack.RefreshOAuthV2Token(cli.httpClient, cli.clientID, cli.clientSecret, cli.refreshToken)
95+
if err != nil {
96+
return
97+
}
98+
99+
err = storeFn(resp.AccessToken, resp.RefreshToken)
100+
if err != nil {
101+
return
102+
}
103+
// create new slack client
104+
cli.Client = newOriginSlackCli(cli.httpClient, resp.AccessToken)
105+
106+
return cli.GetUserInfoWithTokenExpirationCheck(channel, storeFn, options...)
107+
}
108+
86109
var _ healthchecker.HealthChecker = (*BotService)(nil)
87110

88111
type BotService struct {

0 commit comments

Comments
 (0)