package discord import ( "fmt" "log" "os" "os/signal" "ticket-pimp/client/discord/discord_handler" "ticket-pimp/internal/controller" "ticket-pimp/internal/domain" "ticket-pimp/internal/services" "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 { discord, err := discordgo.New("Bot " + token) if err != nil { log.Fatalf("unable to create discord session: %v", err) } return discord } type DiscordOptions struct { Config *domain.Config Controller *controller.WorkflowController } func Run(conf domain.Config, opts DiscordOptions) error { s := initBotWith(conf.Discord.Token) h := discord_handler.New( opts.Controller, &conf.Discord, services.NewDummyClient(conf.Telegram), tags, ) commandHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){} 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){ "task_start": h.HandleTaskButtons, "task_close": h.HandleTaskButtons, } s.AddHandler(h.ListenPosts) s.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) { h.AllInteractions(s, i) switch i.Type { case discordgo.InteractionApplicationCommand: if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok { h(s, i) } case discordgo.InteractionMessageComponent: if h, ok := componentsHandlers[i.MessageComponentData().CustomID]; ok { h(s, i) } } }) if err := s.Open(); err != nil { return fmt.Errorf("cannot open the session: %v", err) } // UPDATE FORUM IF NEEDED: forum, err := s.Channel(conf.Discord.IsTaskForum) if err != nil { log.Print(err) } dchan, err := s.ChannelEditComplex(forum.ID, &discordgo.ChannelEdit{ AvailableTags: &tags, }) if err != nil { log.Fatal(err) } log.Printf("Channel %s with ID %s propagated by tags:", dchan.Name, dchan.ID) for _, t := range dchan.AvailableTags { log.Printf("N: %s, ID: %s", t.Name, t.ID) } log.Println("Adding commands...") var cmds []*discordgo.ApplicationCommand for _, cmd := range commands { cmd, err := s.ApplicationCommandCreate(s.State.User.ID, "", &cmd) if err != nil { log.Panicf("Cannot create '%v' command: %v", cmd.Name, err) } cmds = append(cmds, cmd) log.Println(cmd.Name + " command added") } defer s.Close() stop := make(chan os.Signal, 1) signal.Notify(stop, os.Interrupt) <-stop log.Println("Graceful shutdown") log.Println("Removing commands...") for _, h := range cmds { err := s.ApplicationCommandDelete(s.State.User.ID, "", h.ID) if err != nil { log.Panicf("Cannot delete '%v' command: %v", h.Name, err) } } return nil }