simplify discord architecture;
This commit is contained in:
parent
6cecec06b6
commit
86b00e03b6
|
|
@ -1,18 +1,119 @@
|
||||||
package discord
|
package discord
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"ticket-pimp/client/discord/router"
|
"ticket-pimp/client/discord/discord_handler"
|
||||||
|
|
||||||
"ticket-pimp/internal/controller"
|
"ticket-pimp/internal/controller"
|
||||||
"ticket-pimp/internal/domain"
|
"ticket-pimp/internal/domain"
|
||||||
|
"ticket-pimp/internal/services"
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
"github.com/bwmarrin/discordgo"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
minLength int = 3
|
||||||
|
repoType string = "repo_type"
|
||||||
|
projectRepo string = "project_repo"
|
||||||
|
buildRepo string = "build_repo"
|
||||||
|
nameOption string = "repo_name"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tags = []discordgo.ForumTag{
|
||||||
|
{
|
||||||
|
Name: "В работе",
|
||||||
|
Moderated: true,
|
||||||
|
EmojiName: "👩🍳",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Готово",
|
||||||
|
Moderated: true,
|
||||||
|
EmojiName: "✅",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var commands = []discordgo.ApplicationCommand{
|
||||||
|
{
|
||||||
|
Name: "ping",
|
||||||
|
Description: "pongs in a reply",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "init_project",
|
||||||
|
Description: "Connect project with Coda ID",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Name: "key",
|
||||||
|
Description: "Project's key from Coda.io",
|
||||||
|
Required: true,
|
||||||
|
MinLength: &minLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "project",
|
||||||
|
Description: "Create new development ticket",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Name: "project_name",
|
||||||
|
Description: "Temporary project name",
|
||||||
|
Required: true,
|
||||||
|
MinLength: &minLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "info",
|
||||||
|
Description: "Get project's info",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "repo",
|
||||||
|
Description: "Creates repository of selected type. Name used for projects channels only",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Name: repoType,
|
||||||
|
Description: "The type of repo",
|
||||||
|
Required: true,
|
||||||
|
Choices: []*discordgo.ApplicationCommandOptionChoice{
|
||||||
|
{
|
||||||
|
Name: "Unity project repo",
|
||||||
|
Value: projectRepo,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "XCode build repo",
|
||||||
|
Value: buildRepo,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Name: nameOption,
|
||||||
|
Description: "Type the repository's name",
|
||||||
|
Required: false,
|
||||||
|
MinLength: &minLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "folder",
|
||||||
|
Description: "Command for cloud folder creation",
|
||||||
|
Options: []*discordgo.ApplicationCommandOption{
|
||||||
|
{
|
||||||
|
Type: discordgo.ApplicationCommandOptionString,
|
||||||
|
Name: nameOption,
|
||||||
|
Description: "Type the folder's name",
|
||||||
|
Required: false,
|
||||||
|
MinLength: &minLength,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func initBotWith(token string) *discordgo.Session {
|
func initBotWith(token string) *discordgo.Session {
|
||||||
discord, err := discordgo.New("Bot " + token)
|
discord, err := discordgo.New("Bot " + token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -27,60 +128,48 @@ type DiscordOptions struct {
|
||||||
Controller *controller.WorkflowController
|
Controller *controller.WorkflowController
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkPrivateMessaging(s *discordgo.Session, i *discordgo.InteractionCreate) error {
|
|
||||||
// Моментальный ответ для избежания столкновения с протуханием токена
|
|
||||||
initialResponse := discordgo.InteractionResponse{
|
|
||||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
|
||||||
Data: &discordgo.InteractionResponseData{
|
|
||||||
Flags: discordgo.MessageFlagsEphemeral,
|
|
||||||
Content: "👩🍳 Cooking your query..",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
s.InteractionRespond(i.Interaction, &initialResponse)
|
|
||||||
|
|
||||||
dchan, err := s.Channel(i.ChannelID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if dchan.Type == discordgo.ChannelTypeDM {
|
|
||||||
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
|
||||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
|
||||||
Data: &discordgo.InteractionResponseData{
|
|
||||||
Content: "Yo, fella! I'm not working in private!",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
return errors.New("no private messages! lol")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Run(conf domain.Config, opts DiscordOptions) error {
|
func Run(conf domain.Config, opts DiscordOptions) error {
|
||||||
token := conf.Discord.Token
|
|
||||||
|
|
||||||
s := initBotWith(token)
|
s := initBotWith(conf.Discord.Token)
|
||||||
|
|
||||||
router := router.InitRouter(*opts.Controller, &conf.Discord, &conf.Telegram)
|
h := discord_handler.New(
|
||||||
|
opts.Controller,
|
||||||
|
&conf.Discord,
|
||||||
|
services.NewDummyClient(conf.Telegram),
|
||||||
|
tags,
|
||||||
|
)
|
||||||
|
|
||||||
commandHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){}
|
commandHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){}
|
||||||
for _, handler := range router.Commands {
|
|
||||||
commandHandlers[handler.Command.Name] = handler.Handler
|
for _, cmd := range commands {
|
||||||
|
var f func(s *discordgo.Session, i *discordgo.InteractionCreate)
|
||||||
|
|
||||||
|
switch cmd.Name {
|
||||||
|
case "ping":
|
||||||
|
f = h.Ping
|
||||||
|
case "project":
|
||||||
|
f = h.CreateTicket
|
||||||
|
case "info":
|
||||||
|
f = h.ProjectInfo
|
||||||
|
case "repo":
|
||||||
|
f = h.CreateGit
|
||||||
|
case "folder":
|
||||||
|
f = h.CreateFolder
|
||||||
|
case "init_project":
|
||||||
|
f = h.InitChannelAsProject
|
||||||
|
}
|
||||||
|
commandHandlers[cmd.Name] = f
|
||||||
}
|
}
|
||||||
|
|
||||||
componentsHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
|
componentsHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){
|
||||||
"task_start": router.Components[0].Handler,
|
"task_start": h.HandleTaskButtons,
|
||||||
"task_close": router.Components[0].Handler,
|
"task_close": h.HandleTaskButtons,
|
||||||
}
|
}
|
||||||
|
|
||||||
s.AddHandler(router.ListenPosts)
|
s.AddHandler(h.ListenPosts)
|
||||||
|
|
||||||
s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
err := checkPrivateMessaging(s, i)
|
h.AllInteractions(s, i)
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
switch i.Type {
|
switch i.Type {
|
||||||
case discordgo.InteractionApplicationCommand:
|
case discordgo.InteractionApplicationCommand:
|
||||||
|
|
@ -105,20 +194,8 @@ func Run(conf domain.Config, opts DiscordOptions) error {
|
||||||
log.Print(err)
|
log.Print(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
tagsAvailable := []discordgo.ForumTag{
|
|
||||||
{
|
|
||||||
Name: "В работе",
|
|
||||||
Moderated: true,
|
|
||||||
EmojiName: "👩🍳",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "Готово",
|
|
||||||
Moderated: true,
|
|
||||||
EmojiName: "✅",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
dchan, err := s.ChannelEditComplex(forum.ID, &discordgo.ChannelEdit{
|
dchan, err := s.ChannelEditComplex(forum.ID, &discordgo.ChannelEdit{
|
||||||
AvailableTags: &tagsAvailable,
|
AvailableTags: &tags,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
|
|
@ -131,19 +208,16 @@ func Run(conf domain.Config, opts DiscordOptions) error {
|
||||||
|
|
||||||
log.Println("Adding commands...")
|
log.Println("Adding commands...")
|
||||||
var cmds []*discordgo.ApplicationCommand
|
var cmds []*discordgo.ApplicationCommand
|
||||||
var logString []string
|
|
||||||
for _, h := range router.Commands {
|
for _, cmd := range commands {
|
||||||
cmd, err := s.ApplicationCommandCreate(s.State.User.ID, "", &h.Command)
|
cmd, err := s.ApplicationCommandCreate(s.State.User.ID, "", &cmd)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Panicf("Cannot create '%v' command: %v", h.Command.Name, err)
|
log.Panicf("Cannot create '%v' command: %v", cmd.Name, err)
|
||||||
}
|
}
|
||||||
cmds = append(cmds, cmd)
|
cmds = append(cmds, cmd)
|
||||||
logString = append(logString, cmd.Name)
|
log.Println(cmd.Name + " command added")
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("Following commands added:")
|
|
||||||
log.Println(logString)
|
|
||||||
|
|
||||||
defer s.Close()
|
defer s.Close()
|
||||||
stop := make(chan os.Signal, 1)
|
stop := make(chan os.Signal, 1)
|
||||||
signal.Notify(stop, os.Interrupt)
|
signal.Notify(stop, os.Interrupt)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,82 @@
|
||||||
|
package discord_handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/bwmarrin/discordgo"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *Handler) defaultFollowUp(answer string, s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
|
||||||
|
// Sending result:
|
||||||
|
_, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
||||||
|
Content: answer,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
||||||
|
Content: fmt.Sprintf("Something went wrong: %v", err),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *Handler) AllInteractions(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
|
||||||
|
dchan, err := s.Channel(i.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if dchan.Type == discordgo.ChannelTypeDM {
|
||||||
|
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Content: "Yo, fella! I'm not working in private!",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Моментальный ответ для избежания столкновения с протуханием токена
|
||||||
|
initialResponse := discordgo.InteractionResponse{
|
||||||
|
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||||||
|
Data: &discordgo.InteractionResponseData{
|
||||||
|
Flags: discordgo.MessageFlagsEphemeral,
|
||||||
|
Content: "👩🍳 Cooking your query..",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
s.InteractionRespond(i.Interaction, &initialResponse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// setFlag
|
||||||
|
// sets tag with In progress and Done text to discords channel;
|
||||||
|
func (h *Handler) setFlag(s *discordgo.Session, i *discordgo.InteractionCreate, tag *discordgo.ForumTag) error {
|
||||||
|
|
||||||
|
th, err := s.Channel(i.ChannelID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
forum, err := s.Channel(th.ParentID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверка на существование тега в списке тегов:
|
||||||
|
if len(forum.AvailableTags) != 0 {
|
||||||
|
for _, some := range forum.AvailableTags {
|
||||||
|
if some.Name == tag.Name {
|
||||||
|
_, err := s.ChannelEditComplex(i.ChannelID, &discordgo.ChannelEdit{
|
||||||
|
AppliedTags: &[]string{some.ID},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package discord_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -12,20 +12,23 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Handler struct {
|
type Handler struct {
|
||||||
controller *controller.WorkflowController
|
controller *controller.WorkflowController
|
||||||
conf *domain.DiscordConfig
|
conf *domain.DiscordConfig
|
||||||
tg adapters.IDummyTelegram
|
telegramDummyClient adapters.IDummyTelegram
|
||||||
|
tags []discordgo.ForumTag
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHandler(
|
func New(
|
||||||
controller *controller.WorkflowController,
|
controller *controller.WorkflowController,
|
||||||
conf *domain.DiscordConfig,
|
conf *domain.DiscordConfig,
|
||||||
tg adapters.IDummyTelegram,
|
tg adapters.IDummyTelegram,
|
||||||
|
tags []discordgo.ForumTag,
|
||||||
) *Handler {
|
) *Handler {
|
||||||
return &Handler{
|
return &Handler{
|
||||||
controller: controller,
|
controller: controller,
|
||||||
conf: conf,
|
conf: conf,
|
||||||
tg: tg,
|
telegramDummyClient: tg,
|
||||||
|
tags: tags,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,37 +45,6 @@ func (h *Handler) Ping(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// setFlag
|
|
||||||
// sets tag with In progress and Done text to discords channel;
|
|
||||||
func (h *Handler) setFlag(s *discordgo.Session, i *discordgo.InteractionCreate, tag *discordgo.ForumTag) error {
|
|
||||||
|
|
||||||
th, err := s.Channel(i.ChannelID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
forum, err := s.Channel(th.ParentID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверка на существование тега в списке тегов:
|
|
||||||
if len(forum.AvailableTags) != 0 {
|
|
||||||
for _, some := range forum.AvailableTags {
|
|
||||||
if some.Name == tag.Name {
|
|
||||||
_, err := s.ChannelEditComplex(i.ChannelID, &discordgo.ChannelEdit{
|
|
||||||
AppliedTags: &[]string{some.ID},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListenPosts
|
// ListenPosts
|
||||||
// ..listens to new posts in specific channel
|
// ..listens to new posts in specific channel
|
||||||
// to act them like a task
|
// to act them like a task
|
||||||
|
|
@ -151,10 +123,10 @@ func (h *Handler) ListenPosts(s *discordgo.Session, th *discordgo.ThreadCreate)
|
||||||
func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
|
||||||
// Send an empty interaction response; ----------------------------------------------------------------
|
// Send an empty interaction response; ----------------------------------------------------------------
|
||||||
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
// s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||||||
Type: discordgo.InteractionResponseUpdateMessage,
|
// Type: discordgo.InteractionResponseUpdateMessage,
|
||||||
Data: &discordgo.InteractionResponseData{},
|
// Data: &discordgo.InteractionResponseData{},
|
||||||
})
|
// })
|
||||||
|
|
||||||
// Get assignee value; ---------------------------------------------------------------------------------
|
// Get assignee value; ---------------------------------------------------------------------------------
|
||||||
user := i.Member.User.Mention()
|
user := i.Member.User.Mention()
|
||||||
|
|
@ -164,6 +136,7 @@ func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.Interacti
|
||||||
doneButtonIsDisabled bool = false
|
doneButtonIsDisabled bool = false
|
||||||
state domain.TaskState = domain.NewTaskState()
|
state domain.TaskState = domain.NewTaskState()
|
||||||
message string
|
message string
|
||||||
|
tag discordgo.ForumTag
|
||||||
)
|
)
|
||||||
|
|
||||||
// Check what flow was touched: -------------------------------------------------------------------------
|
// Check what flow was touched: -------------------------------------------------------------------------
|
||||||
|
|
@ -173,11 +146,13 @@ func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.Interacti
|
||||||
doneButtonIsDisabled = false
|
doneButtonIsDisabled = false
|
||||||
state = domain.InrpogressTaskState()
|
state = domain.InrpogressTaskState()
|
||||||
message = "взята в работу"
|
message = "взята в работу"
|
||||||
|
tag = h.tags[0]
|
||||||
case "task_close":
|
case "task_close":
|
||||||
opt = 1
|
opt = 1
|
||||||
doneButtonIsDisabled = true
|
doneButtonIsDisabled = true
|
||||||
state = domain.DoneTaskState()
|
state = domain.DoneTaskState()
|
||||||
message = "выполнена"
|
message = "выполнена"
|
||||||
|
tag = h.tags[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send the task update to db --------------------------------------------------------------------------
|
// Send the task update to db --------------------------------------------------------------------------
|
||||||
|
|
@ -196,7 +171,7 @@ func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.Interacti
|
||||||
// Send message to the creator in Telegram: -------------------------------------------------------------
|
// Send message to the creator in Telegram: -------------------------------------------------------------
|
||||||
|
|
||||||
if task.CreatorLink != "" {
|
if task.CreatorLink != "" {
|
||||||
h.tg.DummyNotification(
|
h.telegramDummyClient.DummyNotification(
|
||||||
task.CreatorLink,
|
task.CreatorLink,
|
||||||
fmt.Sprintf("Task ID: %d %s", task.ID, message))
|
fmt.Sprintf("Task ID: %d %s", task.ID, message))
|
||||||
}
|
}
|
||||||
|
|
@ -231,10 +206,10 @@ func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.Interacti
|
||||||
}
|
}
|
||||||
|
|
||||||
// [ ] Устанавливаем тэги статуса на тред ---------------------------------------------------------------------
|
// [ ] Устанавливаем тэги статуса на тред ---------------------------------------------------------------------
|
||||||
// err = h.setFlag(s, i, &h.Tags[opt])
|
err = h.setFlag(s, i, &tag)
|
||||||
// if err != nil {
|
if err != nil {
|
||||||
// log.Printf("error while `start` tag setting: %v", err)
|
log.Printf("error while `start` tag setting: %v", err)
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *Handler) CreateFolder(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
func (h *Handler) CreateFolder(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
package handler
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (h *Handler) defaultFollowUp(answer string, s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
// Sending result:
|
|
||||||
_, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
|
||||||
Content: answer,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
|
||||||
Content: fmt.Sprintf("Something went wrong: %v", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,222 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"ticket-pimp/internal/domain"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
"github.com/imroc/req/v3"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *client) setFlag(s *discordgo.Session, i *discordgo.InteractionCreate, tag *discordgo.ForumTag) error {
|
|
||||||
|
|
||||||
th, err := s.Channel(i.ChannelID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
forum, err := s.Channel(th.ParentID)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Проверка на существование тега в списке тегов:
|
|
||||||
if len(forum.AvailableTags) != 0 {
|
|
||||||
for _, some := range forum.AvailableTags {
|
|
||||||
if some.Name == tag.Name {
|
|
||||||
_, err := s.ChannelEditComplex(i.ChannelID, &discordgo.ChannelEdit{
|
|
||||||
AppliedTags: &[]string{some.ID},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) ListenPosts(s *discordgo.Session, th *discordgo.ThreadCreate) {
|
|
||||||
|
|
||||||
// Check if thread starter is not a bot, and thread started at the tasks channel;
|
|
||||||
if th.ParentID != c.conf.IsTaskForum || th.OwnerID == s.State.User.ID {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
msgs, _ := s.ChannelMessages(th.ID, 1, "", "", "")
|
|
||||||
|
|
||||||
msg, _ := s.ChannelMessage(th.ID, msgs[0].ID)
|
|
||||||
|
|
||||||
if msg.Author.ID == s.State.User.ID {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
content := th.Name
|
|
||||||
content += "\n" + msg.Content
|
|
||||||
|
|
||||||
user, _ := s.GuildMember(th.GuildID, msg.Author.ID)
|
|
||||||
|
|
||||||
t, err := c.controller.WriteTaskToDB(&domain.Task{
|
|
||||||
Description: content,
|
|
||||||
Creator: user.User.Mention(),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
s.ChannelMessageSend(th.ID, fmt.Sprintf("unable to write task to db, %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// [x] -- Отредактировать Thread name как для задачи
|
|
||||||
_, err = s.ChannelEditComplex(th.ID, &discordgo.ChannelEdit{
|
|
||||||
Name: fmt.Sprintf("Task ID: %d, by %s", t.ID, t.Creator),
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("th edition is not complete: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix the original task message:
|
|
||||||
taskMessage, err := s.ChannelMessageSendComplex(th.ID, &discordgo.MessageSend{
|
|
||||||
Content: content,
|
|
||||||
Components: []discordgo.MessageComponent{
|
|
||||||
discordgo.ActionsRow{
|
|
||||||
Components: []discordgo.MessageComponent{
|
|
||||||
discordgo.Button{
|
|
||||||
Label: "Start",
|
|
||||||
Style: discordgo.SuccessButton,
|
|
||||||
Disabled: false,
|
|
||||||
CustomID: "task_start",
|
|
||||||
},
|
|
||||||
discordgo.Button{
|
|
||||||
Label: "Close",
|
|
||||||
Style: discordgo.DangerButton,
|
|
||||||
Disabled: true,
|
|
||||||
CustomID: "task_close",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("th start message edition is not complete: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = c.controller.UpdateTasksMessageID(context.TODO(), taskMessage.ID, t.ID)
|
|
||||||
if err != nil {
|
|
||||||
s.ChannelMessageSend(th.ID, fmt.Sprintf("unable to update task at the db, %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) HandleTaskButtons() Component {
|
|
||||||
return Component{
|
|
||||||
Handler: c.handleTaskButton,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) handleTaskButton(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
// Get assignee value; ---------------------------------------------------------------------------------
|
|
||||||
user := i.Member.User.Mention()
|
|
||||||
|
|
||||||
var (
|
|
||||||
opt int = -1
|
|
||||||
doneButtonIsDisabled bool = false
|
|
||||||
state domain.TaskState = domain.NewTaskState()
|
|
||||||
message string
|
|
||||||
)
|
|
||||||
|
|
||||||
// Check what flow was touched: -------------------------------------------------------------------------
|
|
||||||
switch i.Interaction.MessageComponentData().CustomID {
|
|
||||||
case "task_start":
|
|
||||||
opt = 0
|
|
||||||
doneButtonIsDisabled = false
|
|
||||||
state = domain.InrpogressTaskState()
|
|
||||||
message = "взята в работу"
|
|
||||||
case "task_close":
|
|
||||||
opt = 1
|
|
||||||
doneButtonIsDisabled = true
|
|
||||||
state = domain.DoneTaskState()
|
|
||||||
message = "выполнена"
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send the task update to db --------------------------------------------------------------------------
|
|
||||||
convertable, err := c.controller.UpdateTask(i.Message.ID, opt, user)
|
|
||||||
if err != nil {
|
|
||||||
s.ChannelMessageSend(i.ChannelID, fmt.Sprintf("Unable to update task at the db w/ error: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map DB's response to domain.Task: -------------------------------------------------------------------
|
|
||||||
task := convertable.
|
|
||||||
ExtractDomain()
|
|
||||||
|
|
||||||
newContent := task.DiscordMessage(state)
|
|
||||||
|
|
||||||
// Send message to the creator in Telegram: -------------------------------------------------------------
|
|
||||||
|
|
||||||
if task.CreatorLink != "" {
|
|
||||||
c.sendTelegramMessageToCreator(
|
|
||||||
task.CreatorLink,
|
|
||||||
fmt.Sprintf("Task ID: %d %s", task.ID, message))
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send a message to the thread about the task was started: ---------------------------------------------
|
|
||||||
_, err = s.ChannelMessageSendComplex(i.ChannelID, &discordgo.MessageSend{
|
|
||||||
Content: newContent,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error while sending start task message: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fix the original task message: ----------------------------------------------------------------------
|
|
||||||
_, err = s.ChannelMessageEditComplex(&discordgo.MessageEdit{
|
|
||||||
Channel: i.ChannelID,
|
|
||||||
ID: i.Message.ID,
|
|
||||||
Components: []discordgo.MessageComponent{
|
|
||||||
discordgo.ActionsRow{
|
|
||||||
Components: []discordgo.MessageComponent{
|
|
||||||
discordgo.Button{
|
|
||||||
Label: "Close",
|
|
||||||
Style: discordgo.DangerButton,
|
|
||||||
Disabled: doneButtonIsDisabled,
|
|
||||||
CustomID: "task_close",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("th start message edition is not complete: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Устанавливаем тэги статуса на тред ---------------------------------------------------------------------
|
|
||||||
// err = c.setFlag(s, i, &c.Tags[opt])
|
|
||||||
// if err != nil {
|
|
||||||
// log.Printf("error while `start` tag setting: %v", err)
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
type TelegramMessage struct {
|
|
||||||
ChatID string `json:"chat_id"`
|
|
||||||
Text string `json:"text"`
|
|
||||||
DisableNotification bool `json:"disable_notification"`
|
|
||||||
ParseMode string `json:"parse_mode"`
|
|
||||||
DisablePreview bool `json:"disable_web_page_preview"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// [ ] As a separate service?
|
|
||||||
func (c *client) sendTelegramMessageToCreator(tgChatID string, text string) {
|
|
||||||
|
|
||||||
http := req.C()
|
|
||||||
http.R().
|
|
||||||
SetBody(&TelegramMessage{
|
|
||||||
ChatID: tgChatID,
|
|
||||||
Text: text,
|
|
||||||
DisableNotification: true,
|
|
||||||
ParseMode: "HTML",
|
|
||||||
DisablePreview: true,
|
|
||||||
}).
|
|
||||||
Post("https://api.telegram.org/bot" + c.tgConf.Token + "/sendMessage")
|
|
||||||
}
|
|
||||||
|
|
@ -1,86 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"ticket-pimp/internal/controller"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *client) CreateFolderHandler(nameMinLenght int) Command {
|
|
||||||
const (
|
|
||||||
nameOption string = "folder_name"
|
|
||||||
)
|
|
||||||
return Command{
|
|
||||||
|
|
||||||
Command: discordgo.ApplicationCommand{
|
|
||||||
Name: "folder",
|
|
||||||
Description: "Command for cloud folder creation",
|
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
|
||||||
{
|
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
|
||||||
Name: nameOption,
|
|
||||||
Description: "Type the folder's name",
|
|
||||||
Required: false,
|
|
||||||
MinLength: &nameMinLenght,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
Handler: c.createFolderHandler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) createFolderHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
const (
|
|
||||||
nameOption string = "folder_name"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Определение переменной для ответа
|
|
||||||
var result string = "unexpected result"
|
|
||||||
|
|
||||||
// Определение выбранных вариантов ответа
|
|
||||||
options := i.ApplicationCommandData().Options
|
|
||||||
|
|
||||||
optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
|
|
||||||
for _, opt := range options {
|
|
||||||
optionMap[opt.Name] = opt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating request:
|
|
||||||
var req controller.FolderRequest
|
|
||||||
name, insertedValueNotNil := optionMap[nameOption]
|
|
||||||
dchan, err := s.Channel(i.ChannelID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error while identifying channel: %v", err)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if dchan.ParentID == c.conf.IsProjectChannel {
|
|
||||||
req.ChannelID = dchan.ID
|
|
||||||
if insertedValueNotNil {
|
|
||||||
req.InsertedName = name.StringValue()
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
req.ChannelID = ""
|
|
||||||
if insertedValueNotNil {
|
|
||||||
req.InsertedName = name.StringValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Making request:
|
|
||||||
resp := c.controller.CreateFolder(context.TODO(), req)
|
|
||||||
if resp.Project == nil {
|
|
||||||
result = "Надо написать имя для папки, или создать папку из проекта!"
|
|
||||||
} else {
|
|
||||||
result = resp.Project.DiscordString()
|
|
||||||
if resp.Message != nil {
|
|
||||||
result += "Errors: " + resp.Message.Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.defaultFollowUp(result, s, i)
|
|
||||||
}
|
|
||||||
|
|
@ -1,117 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"log"
|
|
||||||
"ticket-pimp/internal/controller"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *client) CreateRepoHandler(repoNameMinLength int) Command {
|
|
||||||
const (
|
|
||||||
repoType = "repo_type"
|
|
||||||
projectRepo = "project_repo"
|
|
||||||
buildRepo = "build_repo"
|
|
||||||
nameOption = "repo_name"
|
|
||||||
)
|
|
||||||
|
|
||||||
return Command{
|
|
||||||
Command: discordgo.ApplicationCommand{
|
|
||||||
Name: "repo",
|
|
||||||
Description: "Creates repository of selected type. Name used for projects channels only",
|
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
|
||||||
{
|
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
|
||||||
Name: repoType,
|
|
||||||
Description: "The type of repo",
|
|
||||||
Required: true,
|
|
||||||
Choices: []*discordgo.ApplicationCommandOptionChoice{
|
|
||||||
{
|
|
||||||
Name: "Unity project repo",
|
|
||||||
Value: projectRepo,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Name: "XCode build repo",
|
|
||||||
Value: buildRepo,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
|
||||||
Name: nameOption,
|
|
||||||
Description: "Type the repository's name",
|
|
||||||
Required: false,
|
|
||||||
MinLength: &repoNameMinLength,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Handler: c.createRepoHandler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) createRepoHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
const (
|
|
||||||
repoType = "repo_type"
|
|
||||||
projectRepo = "project_repo"
|
|
||||||
buildRepo = "build_repo"
|
|
||||||
nameOption = "repo_name"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Определение переменной для ответа
|
|
||||||
var result string = "unexpected result"
|
|
||||||
|
|
||||||
// Access options in the order provided by the user.
|
|
||||||
options := i.ApplicationCommandData().Options
|
|
||||||
|
|
||||||
// Or convert the slice into a map
|
|
||||||
optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
|
|
||||||
for _, opt := range options {
|
|
||||||
optionMap[opt.Name] = opt
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creating request:
|
|
||||||
var req controller.GitRequest
|
|
||||||
name, insertedValueNotNil := optionMap[nameOption]
|
|
||||||
isBuild := optionMap[repoType]
|
|
||||||
switch isBuild.StringValue() {
|
|
||||||
case buildRepo:
|
|
||||||
req.IsBuildGit = true
|
|
||||||
case projectRepo:
|
|
||||||
req.IsBuildGit = false
|
|
||||||
}
|
|
||||||
dchan, err := s.Channel(i.ChannelID)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("error while identifying channel: %v", err)
|
|
||||||
} else {
|
|
||||||
|
|
||||||
if dchan.ParentID == c.conf.IsProjectChannel {
|
|
||||||
req.ChannelID = dchan.ID
|
|
||||||
if insertedValueNotNil {
|
|
||||||
req.InsertedName = name.StringValue()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
req.ChannelID = ""
|
|
||||||
if insertedValueNotNil {
|
|
||||||
req.InsertedName = name.StringValue()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Making request:
|
|
||||||
resp := c.controller.CreateGit(context.TODO(), req)
|
|
||||||
if resp.Project == nil {
|
|
||||||
if resp.Message != nil {
|
|
||||||
result = resp.Message.Error()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
|
|
||||||
result = resp.Project.DiscordString()
|
|
||||||
if resp.Message != nil {
|
|
||||||
result += "Errors: " + resp.Message.Error()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
c.defaultFollowUp(result, s, i)
|
|
||||||
}
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"log"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *client) Ping() Command {
|
|
||||||
return Command{
|
|
||||||
Command: discordgo.ApplicationCommand{
|
|
||||||
Name: "ping",
|
|
||||||
Description: "pongs in a reply",
|
|
||||||
},
|
|
||||||
Handler: c.ping,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) ping(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
|
||||||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
|
||||||
Data: &discordgo.InteractionResponseData{
|
|
||||||
Content: "Pong to: " + i.Member.User.Mention(),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
log.Println(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,188 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"ticket-pimp/internal/domain"
|
|
||||||
"ticket-pimp/internal/helpers"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
func (c *client) GetInfo() Command {
|
|
||||||
return Command{
|
|
||||||
Command: discordgo.ApplicationCommand{
|
|
||||||
Name: "info",
|
|
||||||
Description: "Get project's info",
|
|
||||||
},
|
|
||||||
Handler: c.getInfo,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) getInfo(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
var result string
|
|
||||||
|
|
||||||
// Get channel from the request
|
|
||||||
dchan, err := s.Channel(i.ChannelID)
|
|
||||||
if err != nil {
|
|
||||||
result = "unable to get channel from the message"
|
|
||||||
} else {
|
|
||||||
project, err := c.controller.GetProjectByChannelID(context.TODO(), dchan.ID)
|
|
||||||
if err != nil {
|
|
||||||
result = err.Error()
|
|
||||||
} else {
|
|
||||||
if project != nil {
|
|
||||||
result = project.DiscordString()
|
|
||||||
if err != nil {
|
|
||||||
result += "Errors: " + err.Error()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result = "Something wrong with retrieving project from db"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.defaultFollowUp(result, s, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) InitProjectFromChannel(minLength int) Command {
|
|
||||||
return Command{
|
|
||||||
Command: discordgo.ApplicationCommand{
|
|
||||||
Name: "init_project",
|
|
||||||
Description: "Connect project with Coda ID",
|
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
|
||||||
{
|
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
|
||||||
Name: "key",
|
|
||||||
Description: "Project's key from Coda.io",
|
|
||||||
Required: true,
|
|
||||||
MinLength: &minLength,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Handler: c.initProjectFromChannel,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) initProjectFromChannel(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
var result string
|
|
||||||
|
|
||||||
// Get channel from the request
|
|
||||||
dchan, err := s.Channel(i.ChannelID)
|
|
||||||
if err != nil {
|
|
||||||
result = "unable to get channel from the message"
|
|
||||||
} else {
|
|
||||||
if dchan.ParentID != c.conf.IsProjectChannel {
|
|
||||||
// Sending result:
|
|
||||||
_, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
|
||||||
Content: "This channel is not at the project's group",
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
|
||||||
Content: fmt.Sprintf("Something went wrong: %v", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Access options in the order provided by the user.
|
|
||||||
options := i.ApplicationCommandData().Options
|
|
||||||
|
|
||||||
// Or convert the slice into a map
|
|
||||||
optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
|
|
||||||
for _, opt := range options {
|
|
||||||
optionMap[opt.Name] = opt
|
|
||||||
}
|
|
||||||
|
|
||||||
if option, ok := optionMap["key"]; ok {
|
|
||||||
var errMsg error = nil
|
|
||||||
|
|
||||||
project, err := c.controller.InitProjectInChannel(context.TODO(), i.ChannelID, option.StringValue())
|
|
||||||
if err != nil {
|
|
||||||
result = fmt.Sprintf("unable to init project: %v", err)
|
|
||||||
} else {
|
|
||||||
result = project.DiscordString()
|
|
||||||
if errMsg != nil {
|
|
||||||
result += "Errors: " + errMsg.Error()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.defaultFollowUp(result, s, i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) CreateTicketHandler(repoNameMinLength int) Command {
|
|
||||||
return Command{
|
|
||||||
Command: discordgo.ApplicationCommand{
|
|
||||||
Name: "project",
|
|
||||||
Description: "Create new development ticket",
|
|
||||||
Options: []*discordgo.ApplicationCommandOption{
|
|
||||||
{
|
|
||||||
Type: discordgo.ApplicationCommandOptionString,
|
|
||||||
Name: "project_name",
|
|
||||||
Description: "Temporary project name",
|
|
||||||
Required: true,
|
|
||||||
MinLength: &repoNameMinLength,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
Handler: c.createTicketHandler,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *client) createTicketHandler(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
var result string
|
|
||||||
// Access options in the order provided by the user.
|
|
||||||
options := i.ApplicationCommandData().Options
|
|
||||||
|
|
||||||
// Or convert the slice into a map
|
|
||||||
optionMap := make(map[string]*discordgo.ApplicationCommandInteractionDataOption, len(options))
|
|
||||||
for _, opt := range options {
|
|
||||||
optionMap[opt.Name] = opt
|
|
||||||
}
|
|
||||||
|
|
||||||
if option, ok := optionMap["project_name"]; ok {
|
|
||||||
dchan, err := s.GuildChannelCreate(i.GuildID, option.StringValue(), discordgo.ChannelTypeGuildText)
|
|
||||||
if err != nil {
|
|
||||||
result = fmt.Sprintf("chan creation problem: %v\n", err)
|
|
||||||
} else {
|
|
||||||
p, err := c.controller.ProjectCreate(context.TODO(), domain.Project{
|
|
||||||
ChannelID: dchan.ID,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
result = fmt.Sprintf("unable to create project: %v\n", err)
|
|
||||||
_, err := s.ChannelDelete(dchan.ID)
|
|
||||||
if err != nil {
|
|
||||||
result += fmt.Sprintf("\nunable to clean channel: %v\n", err)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
edit := discordgo.ChannelEdit{
|
|
||||||
Name: p.ShortName + "-" + helpers.Cut(option.StringValue()),
|
|
||||||
ParentID: c.conf.IsProjectChannel,
|
|
||||||
}
|
|
||||||
|
|
||||||
dchan, err = s.ChannelEdit(dchan.ID, &edit)
|
|
||||||
if err != nil {
|
|
||||||
result = fmt.Sprintf("channel %s created, but unable to edit follow up message: %v\n", p.ShortName, err)
|
|
||||||
|
|
||||||
} else {
|
|
||||||
_, err = s.ChannelMessageSend(dchan.ID, "Hello!")
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("message send problem: %v\n", err)
|
|
||||||
}
|
|
||||||
result = "Project " + p.ShortName + " was created"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
c.defaultFollowUp(result, s, i)
|
|
||||||
}
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
package router
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"ticket-pimp/internal/controller"
|
|
||||||
"ticket-pimp/internal/domain"
|
|
||||||
|
|
||||||
"github.com/bwmarrin/discordgo"
|
|
||||||
)
|
|
||||||
|
|
||||||
type client struct {
|
|
||||||
Commands []Command
|
|
||||||
Components []Component
|
|
||||||
|
|
||||||
// Tags []discordgo.ForumTag
|
|
||||||
|
|
||||||
controller controller.WorkflowController
|
|
||||||
conf *domain.DiscordConfig
|
|
||||||
tgConf *domain.TelegramConfig
|
|
||||||
}
|
|
||||||
|
|
||||||
// Подключение роутов к Discord боту
|
|
||||||
func InitRouter(wc controller.WorkflowController, conf *domain.DiscordConfig, tgConf *domain.TelegramConfig) *client {
|
|
||||||
|
|
||||||
var r client
|
|
||||||
r.controller = wc
|
|
||||||
r.conf = conf
|
|
||||||
|
|
||||||
r.Commands = append(r.Commands,
|
|
||||||
r.CreateRepoHandler(3),
|
|
||||||
r.CreateFolderHandler(3),
|
|
||||||
r.Ping(),
|
|
||||||
r.CreateTicketHandler(3),
|
|
||||||
r.InitProjectFromChannel(3),
|
|
||||||
r.GetInfo(),
|
|
||||||
)
|
|
||||||
r.Components = append(r.Components,
|
|
||||||
r.HandleTaskButtons(),
|
|
||||||
)
|
|
||||||
r.tgConf = tgConf
|
|
||||||
|
|
||||||
return &r
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Подключение роутов к Discord боту
|
|
||||||
|
|
||||||
type Command struct {
|
|
||||||
Command discordgo.ApplicationCommand
|
|
||||||
Handler func(s *discordgo.Session, i *discordgo.InteractionCreate)
|
|
||||||
}
|
|
||||||
|
|
||||||
type Component struct {
|
|
||||||
Component discordgo.MessageComponent
|
|
||||||
Handler func(s *discordgo.Session, i *discordgo.InteractionCreate)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *client) defaultFollowUp(answer string, s *discordgo.Session, i *discordgo.InteractionCreate) {
|
|
||||||
|
|
||||||
// Sending result:
|
|
||||||
_, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
|
||||||
Content: answer,
|
|
||||||
})
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
|
|
||||||
Content: fmt.Sprintf("Something went wrong: %v", err),
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -3,7 +3,7 @@ package telegram
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"log"
|
"log"
|
||||||
"ticket-pimp/client/telegram/handler"
|
"ticket-pimp/client/telegram/telegram_handler"
|
||||||
"ticket-pimp/internal/controller"
|
"ticket-pimp/internal/controller"
|
||||||
"ticket-pimp/internal/domain"
|
"ticket-pimp/internal/domain"
|
||||||
"ticket-pimp/internal/services"
|
"ticket-pimp/internal/services"
|
||||||
|
|
@ -30,7 +30,7 @@ func Run(ctx context.Context, opts TelegramOptions) error {
|
||||||
log.Print("Start telegram bot init..")
|
log.Print("Start telegram bot init..")
|
||||||
client := tg.New(opts.AppConfig.Telegram.Token)
|
client := tg.New(opts.AppConfig.Telegram.Token)
|
||||||
|
|
||||||
h := handler.NewHandler(
|
h := telegram_handler.NewHandler(
|
||||||
opts.GitService,
|
opts.GitService,
|
||||||
opts.CloudService,
|
opts.CloudService,
|
||||||
opts.Coda,
|
opts.Coda,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package telegram_handler
|
||||||
|
|
||||||
// func (h *Handler) DevelopmentTaskHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
|
// func (h *Handler) DevelopmentTaskHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package telegram_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package telegram_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package telegram_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package telegram_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package handler
|
package telegram_handler
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"ticket-pimp/adapters"
|
"ticket-pimp/adapters"
|
||||||
|
|
@ -1,12 +1,28 @@
|
||||||
package services
|
package services
|
||||||
|
|
||||||
import "ticket-pimp/internal/domain"
|
import (
|
||||||
|
"ticket-pimp/internal/domain"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type DummyTelegram struct {
|
type DummyTelegram struct {
|
||||||
*CommonClient
|
*CommonClient
|
||||||
config domain.TelegramConfig
|
config domain.TelegramConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewDummyClient(conf domain.TelegramConfig) *DummyTelegram {
|
||||||
|
|
||||||
|
client := NewClient().
|
||||||
|
SetTimeout(5 * time.Second)
|
||||||
|
|
||||||
|
return &DummyTelegram{
|
||||||
|
CommonClient: &CommonClient{
|
||||||
|
Client: client,
|
||||||
|
},
|
||||||
|
config: conf,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type TelegramMessage struct {
|
type TelegramMessage struct {
|
||||||
ChatID string `json:"chat_id"`
|
ChatID string `json:"chat_id"`
|
||||||
Text string `json:"text"`
|
Text string `json:"text"`
|
||||||
|
|
|
||||||
|
|
@ -86,7 +86,6 @@ func (gb *Git) defaultGroupAsCollaborator(git *domain.Git) (*domain.Git, error)
|
||||||
Perm: "push",
|
Perm: "push",
|
||||||
}
|
}
|
||||||
|
|
||||||
// respURL := "/orgs/mobilerino/teams/devs/repos/mobilerino/" + git.Name
|
|
||||||
respURL := fmt.Sprintf("/orgs/%s/teams/devs/repos/%s/%s", gb.conf.OrgName, gb.conf.OrgName, git.Name)
|
respURL := fmt.Sprintf("/orgs/%s/teams/devs/repos/%s/%s", gb.conf.OrgName, gb.conf.OrgName, git.Name)
|
||||||
|
|
||||||
resp, _ := gb.R().
|
resp, _ := gb.R().
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue