bot sends all errors and results to dm
This commit is contained in:
parent
2d5cf75f52
commit
11d2221752
@ -48,7 +48,17 @@ func (p *Plugin) ExecuteCommand(
|
||||
|
||||
split := strings.Fields(args.Command)
|
||||
if len(split) < 2 {
|
||||
return p.commandHelp(), nil
|
||||
// Отправляем help в DM
|
||||
helpText := `**Sentry plugin commands**
|
||||
|
||||
• /sentry link <project_slug> — link project to channel
|
||||
• /sentry unlink <project_slug> — unlink project
|
||||
• /sentry list — list linked projects
|
||||
• /sentry setup — setup project
|
||||
• /sentry help — show help`
|
||||
post := &model.Post{Message: helpText}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
switch split[1] {
|
||||
@ -68,7 +78,17 @@ func (p *Plugin) ExecuteCommand(
|
||||
case "help":
|
||||
fallthrough
|
||||
default:
|
||||
return p.commandHelp(), nil
|
||||
// Отправляем help в DM
|
||||
helpText := `**Sentry plugin commands**
|
||||
|
||||
• /sentry link <project_slug> — link project to channel
|
||||
• /sentry unlink <project_slug> — unlink project
|
||||
• /sentry list — list linked projects
|
||||
• /sentry setup — setup project
|
||||
• /sentry help — show help`
|
||||
post := &model.Post{Message: helpText}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -71,3 +71,34 @@ func (p *Plugin) setBotIcon() error {
|
||||
p.API.LogInfo("Bot icon set successfully")
|
||||
return nil
|
||||
}
|
||||
|
||||
// getDirectChannel получает или создает DM канал между ботом и пользователем
|
||||
func (p *Plugin) getDirectChannel(userID string) (string, error) {
|
||||
if p.botUserID == "" {
|
||||
return "", fmt.Errorf("bot user ID is not set")
|
||||
}
|
||||
|
||||
channel, appErr := p.API.GetDirectChannel(p.botUserID, userID)
|
||||
if appErr != nil {
|
||||
return "", fmt.Errorf("failed to get direct channel: %s", appErr.Error())
|
||||
}
|
||||
|
||||
return channel.Id, nil
|
||||
}
|
||||
|
||||
// sendDMToUser отправляет сообщение пользователю в личные сообщения
|
||||
func (p *Plugin) sendDMToUser(userID string, post *model.Post) error {
|
||||
dmChannelID, err := p.getDirectChannel(userID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get DM channel: %w", err)
|
||||
}
|
||||
|
||||
post.ChannelId = dmChannelID
|
||||
post.UserId = p.botUserID
|
||||
|
||||
if _, appErr := p.API.CreatePost(post); appErr != nil {
|
||||
return fmt.Errorf("failed to create post: %s", appErr.Error())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -9,10 +9,9 @@ import (
|
||||
|
||||
func (p *Plugin) commandLink(args *model.CommandArgs, split []string) (*model.CommandResponse, *model.AppError) {
|
||||
if len(split) < 3 {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "❌ Usage: /sentry link <project_slug>",
|
||||
}, nil
|
||||
post := &model.Post{Message: "❌ Usage: /sentry link <project_slug>"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
projectSlug := split[2]
|
||||
@ -26,38 +25,36 @@ func (p *Plugin) commandLink(args *model.CommandArgs, split []string) (*model.Co
|
||||
|
||||
project, err := p.linkProjectToChannel(projectSlug, channelID, hooks)
|
||||
if err != nil {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "❌ " + err.Error(),
|
||||
}, nil
|
||||
post := &model.Post{Message: "❌ " + err.Error()}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: fmt.Sprintf(
|
||||
post := &model.Post{
|
||||
Message: fmt.Sprintf(
|
||||
"✅ Linked **%s** (`%s`) to this channel",
|
||||
project.Name,
|
||||
project.Slug,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) commandUnlink(args *model.CommandArgs, split []string) (*model.CommandResponse, *model.AppError) {
|
||||
if len(split) < 3 {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "❌ Usage: /sentry unlink <project_slug>",
|
||||
}, nil
|
||||
post := &model.Post{Message: "❌ Usage: /sentry unlink <project_slug>"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
slug := split[2]
|
||||
|
||||
projects, err := p.getAllProjects()
|
||||
if err != nil {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "ℹ️ No linked projects",
|
||||
}, nil
|
||||
post := &model.Post{Message: "ℹ️ No linked projects"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
var removed *LinkedProject
|
||||
@ -65,66 +62,94 @@ func (p *Plugin) commandUnlink(args *model.CommandArgs, split []string) (*model.
|
||||
if project.Slug == slug {
|
||||
removed = project
|
||||
if err := p.deleteProject(project.ID); err != nil {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "❌ Failed to unlink project: " + err.Error(),
|
||||
}, nil
|
||||
post := &model.Post{Message: "❌ Failed to unlink project: " + err.Error()}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if removed == nil {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "❌ Project not found",
|
||||
}, nil
|
||||
post := &model.Post{Message: "❌ Project not found"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: fmt.Sprintf(
|
||||
post := &model.Post{
|
||||
Message: fmt.Sprintf(
|
||||
"✅ Unlinked **%s** (`%s`)",
|
||||
removed.Name,
|
||||
removed.Slug,
|
||||
),
|
||||
}, nil
|
||||
}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) commandList(args *model.CommandArgs) (*model.CommandResponse, *model.AppError) {
|
||||
projects, err := p.getAllProjects()
|
||||
if err != nil || len(projects) == 0 {
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "_No linked Sentry projects_",
|
||||
}, nil
|
||||
post := &model.Post{Message: "_No linked Sentry projects_"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
var lines []string
|
||||
// Формируем таблицу
|
||||
var tableRows []string
|
||||
|
||||
// Заголовок таблицы
|
||||
tableRows = append(tableRows, "| Project | Slug | Channel | Hooks |")
|
||||
tableRows = append(tableRows, "|---------|------|---------|-------|")
|
||||
|
||||
// Строки с данными
|
||||
for _, project := range projects {
|
||||
channelName := project.ChannelID
|
||||
if ch, err := p.API.GetChannel(project.ChannelID); err == nil {
|
||||
channelName = "~" + ch.Name
|
||||
}
|
||||
|
||||
lines = append(
|
||||
lines,
|
||||
fmt.Sprintf(
|
||||
"• **%s** (`%s`) → %s",
|
||||
project.Name,
|
||||
project.Slug,
|
||||
channelName,
|
||||
),
|
||||
// Формируем список включенных хуков
|
||||
var hooks []string
|
||||
if project.Hooks.EventAlert {
|
||||
hooks = append(hooks, "Event")
|
||||
}
|
||||
if project.Hooks.MetricAlert {
|
||||
hooks = append(hooks, "Metric")
|
||||
}
|
||||
if project.Hooks.Issue {
|
||||
hooks = append(hooks, "Issue")
|
||||
}
|
||||
if project.Hooks.Comment {
|
||||
hooks = append(hooks, "Comment")
|
||||
}
|
||||
|
||||
hooksStr := strings.Join(hooks, ", ")
|
||||
if hooksStr == "" {
|
||||
hooksStr = "-"
|
||||
}
|
||||
|
||||
// Экранируем символы для markdown таблицы
|
||||
projectName := strings.ReplaceAll(project.Name, "|", "\\|")
|
||||
slug := strings.ReplaceAll(project.Slug, "|", "\\|")
|
||||
channelName = strings.ReplaceAll(channelName, "|", "\\|")
|
||||
hooksStr = strings.ReplaceAll(hooksStr, "|", "\\|")
|
||||
|
||||
tableRows = append(
|
||||
tableRows,
|
||||
fmt.Sprintf("| %s | `%s` | %s | %s |", projectName, slug, channelName, hooksStr),
|
||||
)
|
||||
}
|
||||
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "🔗 **Linked Sentry projects:**\n\n" + strings.Join(lines, "\n"),
|
||||
}, nil
|
||||
message := "🔗 **Linked Sentry projects:**\n\n" + strings.Join(tableRows, "\n")
|
||||
post := &model.Post{Message: message}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) commandHelp() *model.CommandResponse {
|
||||
// Help отправляется через ephemeral в ExecuteCommand, но мы не можем получить userId здесь
|
||||
// Поэтому оставляем как есть, но это будет обработано в ExecuteCommand
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: `**Sentry plugin commands**
|
||||
@ -139,20 +164,18 @@ func (p *Plugin) commandSetup(args *model.CommandArgs) (*model.CommandResponse,
|
||||
|
||||
if args.TriggerId == "" {
|
||||
p.API.LogWarn("commandSetup: triggerId is empty")
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "This command must be run from Mattermost UI",
|
||||
}, nil
|
||||
post := &model.Post{Message: "This command must be run from Loop UI"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
// Получаем каналы пользователя
|
||||
channels, appErr := p.API.GetChannelsForTeamForUser(args.TeamId, args.UserId, false)
|
||||
if appErr != nil {
|
||||
p.API.LogError("Failed to load channels", "error", appErr.Error())
|
||||
return &model.CommandResponse{
|
||||
ResponseType: model.CommandResponseTypeEphemeral,
|
||||
Text: "❌ Failed to load channels",
|
||||
}, nil
|
||||
post := &model.Post{Message: "❌ Failed to load channels"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
channelOptions := []*model.PostActionOptions{}
|
||||
@ -253,13 +276,17 @@ func (p *Plugin) commandSetupHook(
|
||||
|
||||
project, err := p.getProjectByChannel(args.ChannelId)
|
||||
if err != nil {
|
||||
return ephemeral("❌ " + err.Error()), nil
|
||||
post := &model.Post{Message: "❌ " + err.Error()}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
hookType := HookType(hook)
|
||||
|
||||
if !isHookEnabled(project, hookType) {
|
||||
return ephemeral("⚠️ This webhook is disabled in setup"), nil
|
||||
post := &model.Post{Message: "⚠️ This webhook is disabled in setup"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
switch hookType {
|
||||
@ -272,6 +299,8 @@ func (p *Plugin) commandSetupHook(
|
||||
case HookComment:
|
||||
return p.openCommentSetup(args, project)
|
||||
default:
|
||||
return ephemeral("❌ Unknown webhook type"), nil
|
||||
post := &model.Post{Message: "❌ Unknown webhook type"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,15 +34,18 @@ func (p *Plugin) handleDialogSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
project, err := p.linkProjectToChannel(projectSlug, channelID, hooks)
|
||||
if err != nil {
|
||||
p.API.SendEphemeralPost(req.UserId, &model.Post{
|
||||
ChannelId: channelID,
|
||||
Message: "❌ " + err.Error(),
|
||||
})
|
||||
// Отправляем ошибку в личные сообщения
|
||||
post := &model.Post{
|
||||
Message: "❌ " + err.Error(),
|
||||
}
|
||||
if dmErr := p.sendDMToUser(req.UserId, post); dmErr != nil {
|
||||
p.API.LogError("Failed to send DM to user", "error", dmErr.Error())
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
p.API.SendEphemeralPost(req.UserId, &model.Post{
|
||||
ChannelId: channelID,
|
||||
// Отправляем успешное сообщение в личные сообщения
|
||||
post := &model.Post{
|
||||
Message: fmt.Sprintf(
|
||||
"✅ Linked **%s** (`%s`)\nHooks: event=%v, metric=%v, issue=%v, comment=%v",
|
||||
project.Name,
|
||||
@ -52,7 +55,10 @@ func (p *Plugin) handleDialogSubmit(w http.ResponseWriter, r *http.Request) {
|
||||
hooks.Issue,
|
||||
hooks.Comment,
|
||||
),
|
||||
})
|
||||
}
|
||||
if dmErr := p.sendDMToUser(req.UserId, post); dmErr != nil {
|
||||
p.API.LogError("Failed to send DM to user", "error", dmErr.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) openEventAlertSetup(
|
||||
@ -61,10 +67,14 @@ func (p *Plugin) openEventAlertSetup(
|
||||
) (*model.CommandResponse, *model.AppError) {
|
||||
|
||||
if args.TriggerId == "" {
|
||||
return ephemeral("This command must be run from UI"), nil
|
||||
post := &model.Post{Message: "This command must be run from UI"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
return ephemeral("🛠 Event alert setup is not implemented yet"), nil
|
||||
post := &model.Post{Message: "🛠 Event alert setup is not implemented yet"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) openMetricAlertSetup(
|
||||
@ -73,10 +83,14 @@ func (p *Plugin) openMetricAlertSetup(
|
||||
) (*model.CommandResponse, *model.AppError) {
|
||||
|
||||
if args.TriggerId == "" {
|
||||
return ephemeral("This command must be run from UI"), nil
|
||||
post := &model.Post{Message: "This command must be run from UI"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
return ephemeral("🛠 Metric alert setup is not implemented yet"), nil
|
||||
post := &model.Post{Message: "🛠 Metric alert setup is not implemented yet"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) openIssueSetup(
|
||||
@ -85,10 +99,14 @@ func (p *Plugin) openIssueSetup(
|
||||
) (*model.CommandResponse, *model.AppError) {
|
||||
|
||||
if args.TriggerId == "" {
|
||||
return ephemeral("This command must be run from UI"), nil
|
||||
post := &model.Post{Message: "This command must be run from UI"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
return ephemeral("🛠 Issue setup is not implemented yet"), nil
|
||||
post := &model.Post{Message: "🛠 Issue setup is not implemented yet"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) openCommentSetup(
|
||||
@ -97,8 +115,12 @@ func (p *Plugin) openCommentSetup(
|
||||
) (*model.CommandResponse, *model.AppError) {
|
||||
|
||||
if args.TriggerId == "" {
|
||||
return ephemeral("This command must be run from UI"), nil
|
||||
post := &model.Post{Message: "This command must be run from UI"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
return ephemeral("🛠 Comment setup is not implemented yet"), nil
|
||||
post := &model.Post{Message: "🛠 Comment setup is not implemented yet"}
|
||||
_ = p.sendDMToUser(args.UserId, post)
|
||||
return &model.CommandResponse{}, nil
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user