542 lines
15 KiB
Go
542 lines
15 KiB
Go
package handler
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"log"
|
||
"ticket-pimp/adapters"
|
||
"ticket-pimp/internal/controller"
|
||
"ticket-pimp/internal/domain"
|
||
|
||
"github.com/bwmarrin/discordgo"
|
||
)
|
||
|
||
type Handler struct {
|
||
controller *controller.WorkflowController
|
||
conf *domain.DiscordConfig
|
||
tg adapters.IDummyTelegram
|
||
}
|
||
|
||
func NewHandler(
|
||
controller *controller.WorkflowController,
|
||
conf *domain.DiscordConfig,
|
||
tg adapters.IDummyTelegram,
|
||
) *Handler {
|
||
return &Handler{
|
||
controller: controller,
|
||
conf: conf,
|
||
tg: tg,
|
||
}
|
||
}
|
||
|
||
func (h *Handler) 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)
|
||
}
|
||
}
|
||
|
||
// 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
|
||
// ..listens to new posts in specific channel
|
||
// to act them like a task
|
||
func (h *Handler) 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 != h.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 := h.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 = h.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
|
||
}
|
||
}
|
||
|
||
// handleTaskBurrons
|
||
// .. handler function to work with the Action Buttons over a task
|
||
func (h *Handler) HandleTaskButtons(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||
|
||
// Send an empty interaction response; ----------------------------------------------------------------
|
||
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
|
||
Type: discordgo.InteractionResponseUpdateMessage,
|
||
Data: &discordgo.InteractionResponseData{},
|
||
})
|
||
|
||
// 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 := h.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 != "" {
|
||
h.tg.DummyNotification(
|
||
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 = h.setFlag(s, i, &h.Tags[opt])
|
||
// if err != nil {
|
||
// log.Printf("error while `start` tag setting: %v", err)
|
||
// }
|
||
}
|
||
|
||
func (h *Handler) CreateFolder(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||
const (
|
||
nameOption string = "folder_name"
|
||
)
|
||
|
||
// Моментальный ответ для избежания столкновения с протуханием токена
|
||
initialResponse := discordgo.InteractionResponse{
|
||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||
Data: &discordgo.InteractionResponseData{
|
||
Flags: discordgo.MessageFlagsEphemeral,
|
||
Content: "👩🍳 Cooking your query..",
|
||
},
|
||
}
|
||
|
||
s.InteractionRespond(i.Interaction, &initialResponse)
|
||
|
||
// Определение переменной для ответа
|
||
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 == h.conf.IsProjectChannel {
|
||
req.ChannelID = dchan.ID
|
||
if insertedValueNotNil {
|
||
req.InsertedName = name.StringValue()
|
||
}
|
||
|
||
} else {
|
||
req.ChannelID = ""
|
||
if insertedValueNotNil {
|
||
req.InsertedName = name.StringValue()
|
||
}
|
||
}
|
||
}
|
||
|
||
// Making request:
|
||
resp := h.controller.CreateFolder(context.TODO(), req)
|
||
if resp.Project == nil {
|
||
result = "Надо написать имя для папки, или создать папку из проекта!"
|
||
} else {
|
||
result = resp.Project.DiscordString()
|
||
if resp.Message != nil {
|
||
result += "Errors: " + resp.Message.Error()
|
||
}
|
||
}
|
||
|
||
h.defaultFollowUp(result, s, i)
|
||
}
|
||
|
||
func (h *Handler) CreateGit(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||
const (
|
||
repoType = "repo_type"
|
||
projectRepo = "project_repo"
|
||
buildRepo = "build_repo"
|
||
nameOption = "repo_name"
|
||
)
|
||
// Моментальный ответ для избежания столкновения с протуханием токена
|
||
initialResponse := discordgo.InteractionResponse{
|
||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||
Data: &discordgo.InteractionResponseData{
|
||
Flags: discordgo.MessageFlagsEphemeral,
|
||
Content: "👩🍳 Cooking your query..",
|
||
},
|
||
}
|
||
|
||
s.InteractionRespond(i.Interaction, &initialResponse)
|
||
|
||
// Определение переменной для ответа
|
||
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 == h.conf.IsProjectChannel {
|
||
req.ChannelID = dchan.ID
|
||
if insertedValueNotNil {
|
||
req.InsertedName = name.StringValue()
|
||
}
|
||
} else {
|
||
req.ChannelID = ""
|
||
if insertedValueNotNil {
|
||
req.InsertedName = name.StringValue()
|
||
}
|
||
}
|
||
}
|
||
|
||
// Making request:
|
||
resp := h.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()
|
||
}
|
||
|
||
}
|
||
h.defaultFollowUp(result, s, i)
|
||
}
|
||
|
||
// PROJECT
|
||
func (h *Handler) ProjectInfo(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||
|
||
// Моментальный ответ для избежания столкновения с протуханием токена
|
||
initialResponse := discordgo.InteractionResponse{
|
||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||
Data: &discordgo.InteractionResponseData{
|
||
Flags: discordgo.MessageFlagsEphemeral,
|
||
Content: "👩🍳 Cooking your query..",
|
||
},
|
||
}
|
||
|
||
s.InteractionRespond(i.Interaction, &initialResponse)
|
||
|
||
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 := h.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"
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
h.defaultFollowUp(result, s, i)
|
||
}
|
||
|
||
func (h *Handler) InitChannelAsProject(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||
|
||
// Моментальный ответ для избежания столкновения с протуханием токена
|
||
initialResponse := discordgo.InteractionResponse{
|
||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||
Data: &discordgo.InteractionResponseData{
|
||
Flags: discordgo.MessageFlagsEphemeral,
|
||
Content: "👩🍳 Cooking your query..",
|
||
},
|
||
}
|
||
|
||
s.InteractionRespond(i.Interaction, &initialResponse)
|
||
|
||
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 != h.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 := h.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()
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
h.defaultFollowUp(result, s, i)
|
||
}
|
||
|
||
func (h *Handler) CreateTicket(s *discordgo.Session, i *discordgo.InteractionCreate) {
|
||
|
||
// Моментальный ответ для избежания столкновения с протуханием токена
|
||
initialResponse := discordgo.InteractionResponse{
|
||
Type: discordgo.InteractionResponseChannelMessageWithSource,
|
||
Data: &discordgo.InteractionResponseData{
|
||
Flags: discordgo.MessageFlagsEphemeral,
|
||
Content: "👩🍳 Cooking your query..",
|
||
},
|
||
}
|
||
|
||
s.InteractionRespond(i.Interaction, &initialResponse)
|
||
|
||
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 := h.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,
|
||
ParentID: "1150719794853716028",
|
||
}
|
||
|
||
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"
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
h.defaultFollowUp(result, s, i)
|
||
}
|