diff --git a/adapters/adapters.go b/adapters/adapters.go new file mode 100644 index 0000000..ee05218 --- /dev/null +++ b/adapters/adapters.go @@ -0,0 +1,18 @@ +package adapters + +import "ticket-pimp/internal/domain" + +type IDummyTelegram interface { + DummyNotification(id string, text string) +} + +type ICloud interface { + CreateFolder(name string) domain.Response +} + +type ICoda interface { + ListDocs() + CreateApp(task domain.CodaApplication) + CreateTask(title string, desc string, creatorName string, creatorID string) (string, error) + GetRowLink(id string) (string, error) +} diff --git a/client/discord/discord.go b/client/discord/discord.go index b540b34..4db4320 100644 --- a/client/discord/discord.go +++ b/client/discord/discord.go @@ -6,7 +6,7 @@ import ( "log" "os" "os/signal" - "ticket-pimp/client/discord/handler" + "ticket-pimp/client/discord/router" "ticket-pimp/internal/controller" "ticket-pimp/internal/domain" @@ -51,7 +51,7 @@ func Run(conf domain.Config, opts DiscordOptions) error { s := initBotWith(token) - router := handler.InitRouter(*opts.Controller, &conf.Discord, &conf.Telegram) + router := router.InitRouter(*opts.Controller, &conf.Discord, &conf.Telegram) commandHandlers := map[string]func(s *discordgo.Session, i *discordgo.InteractionCreate){} for _, handler := range router.Commands { @@ -89,18 +89,35 @@ func Run(conf domain.Config, opts DiscordOptions) error { // UPDATE FORUM IF NEEDED: - forum, err := s.Channel(conf.Discord.IsProjectChannel) + forum, err := s.Channel(conf.Discord.IsTaskForum) if err != nil { log.Print(err) } - _, err = s.ChannelEditComplex(forum.ID, &discordgo.ChannelEdit{ - AvailableTags: &router.Tags, + tagsAvailable := []discordgo.ForumTag{ + { + Name: "В работе", + Moderated: true, + EmojiName: "👩‍🍳", + }, + { + Name: "Готово", + Moderated: true, + EmojiName: "✅", + }, + } + dchan, err := s.ChannelEditComplex(forum.ID, &discordgo.ChannelEdit{ + AvailableTags: &tagsAvailable, }) 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 var logString []string diff --git a/client/discord/handler/common.go b/client/discord/handler/common.go new file mode 100644 index 0000000..2dfe4d2 --- /dev/null +++ b/client/discord/handler/common.go @@ -0,0 +1,22 @@ +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 + } +} diff --git a/client/discord/handler/discord_handler.go b/client/discord/handler/discord_handler.go new file mode 100644 index 0000000..6b87a0d --- /dev/null +++ b/client/discord/handler/discord_handler.go @@ -0,0 +1,541 @@ +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) handleTaskButton(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) createFolderHandler(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) createRepoHandler(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) getInfo(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) initProjectFromChannel(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) createTicketHandler(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) +} diff --git a/client/discord/handler/handle_external_task.go b/client/discord/router/handle_external_task.go similarity index 91% rename from client/discord/handler/handle_external_task.go rename to client/discord/router/handle_external_task.go index b41dd5c..18274c7 100644 --- a/client/discord/handler/handle_external_task.go +++ b/client/discord/router/handle_external_task.go @@ -1,4 +1,4 @@ -package handler +package router import ( "context" @@ -198,10 +198,10 @@ func (c *client) handleTaskButton(s *discordgo.Session, i *discordgo.Interaction } // Устанавливаем тэги статуса на тред --------------------------------------------------------------------- - err = c.setFlag(s, i, &c.Tags[opt]) - if err != nil { - log.Printf("error while `start` tag setting: %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 { @@ -212,6 +212,7 @@ type TelegramMessage struct { DisablePreview bool `json:"disable_web_page_preview"` } +// [ ] As a separate service? func (c *client) sendTelegramMessageToCreator(tgChatID string, text string) { http := req.C() @@ -224,26 +225,4 @@ func (c *client) sendTelegramMessageToCreator(tgChatID string, text string) { DisablePreview: true, }). Post("https://api.telegram.org/bot" + c.tgConf.Token + "/sendMessage") - // [HTTP Kit Marlerino]::POST( - // "https://api.telegram.org/bot" + Config.botToken + - // "/sendMessage", - // "", - // Object( - // "chat_id", - // thisRow.[Creator ID].ToText(), - // "text", - // Format( - // "{2} взята в работу", - // thisRow.ObjectLink().ToText(), - // "Задача" - // ), - // "disable_notification", - // true, - // "parse_mode", - // "HTML", - // "disable_web_page_preview", - // true - // ) - // ) - } diff --git a/client/discord/handler/handle_folder.go b/client/discord/router/handle_folder.go similarity index 99% rename from client/discord/handler/handle_folder.go rename to client/discord/router/handle_folder.go index ab7a6e7..2cac468 100644 --- a/client/discord/handler/handle_folder.go +++ b/client/discord/router/handle_folder.go @@ -1,4 +1,4 @@ -package handler +package router import ( "context" diff --git a/client/discord/handler/handle_git.go b/client/discord/router/handle_git.go similarity index 99% rename from client/discord/handler/handle_git.go rename to client/discord/router/handle_git.go index f41ff60..9f1e2a6 100644 --- a/client/discord/handler/handle_git.go +++ b/client/discord/router/handle_git.go @@ -1,4 +1,4 @@ -package handler +package router import ( "context" diff --git a/client/discord/handler/handle_ping.go b/client/discord/router/handle_ping.go similarity index 97% rename from client/discord/handler/handle_ping.go rename to client/discord/router/handle_ping.go index 4f91795..9257715 100644 --- a/client/discord/handler/handle_ping.go +++ b/client/discord/router/handle_ping.go @@ -1,4 +1,4 @@ -package handler +package router import ( "log" diff --git a/client/discord/handler/handle_ticket.go b/client/discord/router/handle_ticket.go similarity index 99% rename from client/discord/handler/handle_ticket.go rename to client/discord/router/handle_ticket.go index f904e5d..9624d7c 100644 --- a/client/discord/handler/handle_ticket.go +++ b/client/discord/router/handle_ticket.go @@ -1,4 +1,4 @@ -package handler +package router import ( "context" diff --git a/client/discord/handler/handler.go b/client/discord/router/handler.go similarity index 77% rename from client/discord/handler/handler.go rename to client/discord/router/handler.go index cb64fc3..5deda56 100644 --- a/client/discord/handler/handler.go +++ b/client/discord/router/handler.go @@ -1,4 +1,4 @@ -package handler +package router import ( "fmt" @@ -12,7 +12,7 @@ type client struct { Commands []Command Components []Component - Tags []discordgo.ForumTag + // Tags []discordgo.ForumTag controller controller.WorkflowController conf *domain.DiscordConfig @@ -27,30 +27,16 @@ func InitRouter(wc controller.WorkflowController, conf *domain.DiscordConfig, tg r.conf = conf r.Commands = append(r.Commands, - r.CreateRepoHandler(3), - r.CreateFolderHandler(3), + // r.CreateRepoHandler(3), + // r.CreateFolderHandler(3), r.Ping(), - r.CreateTicketHandler(3), - r.InitProjectFromChannel(3), - r.GetInfo(), + // r.CreateTicketHandler(3), + // r.InitProjectFromChannel(3), + // r.GetInfo(), ) r.Components = append(r.Components, r.HandleTaskButtons(), ) - - r.Tags = append( - r.Tags, - discordgo.ForumTag{ - Name: "В работе", - Moderated: true, - EmojiName: "👩‍🍳", - }, - - discordgo.ForumTag{ - Name: "Готово", - Moderated: true, - EmojiName: "✅", - }) r.tgConf = tgConf return &r diff --git a/client/telegram/handler/handler.go b/client/telegram/handler/handler.go index da3a326..c2c21ac 100644 --- a/client/telegram/handler/handler.go +++ b/client/telegram/handler/handler.go @@ -1,14 +1,15 @@ package handler import ( + "ticket-pimp/adapters" "ticket-pimp/internal/controller" "ticket-pimp/internal/services" ) type Handler struct { git services.IGit - cloud services.ICloud - coda services.ICoda + cloud adapters.ICloud + coda adapters.ICoda key string id string controller *controller.WorkflowController @@ -16,8 +17,8 @@ type Handler struct { func NewHandler( git services.IGit, - cloud services.ICloud, - coda services.ICoda, + cloud adapters.ICloud, + coda adapters.ICoda, controller *controller.WorkflowController, ) *Handler { diff --git a/internal/controller/controller.go b/internal/controller/controller.go index ecea95d..5b836fd 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,6 +1,7 @@ package controller import ( + "ticket-pimp/adapters" "ticket-pimp/internal/domain" "ticket-pimp/internal/services" "ticket-pimp/internal/storage/db" @@ -11,8 +12,8 @@ import ( type WorkflowController struct { IGit services.IGit - ICloud services.ICloud - ICoda services.ICoda + ICloud adapters.ICloud + ICoda adapters.ICoda pool *pgxpool.Pool q *db.Queries ATags []discordgo.ForumTag @@ -20,8 +21,8 @@ type WorkflowController struct { func NewWorkflowController( git services.IGit, - cloud services.ICloud, - coda services.ICoda, + cloud adapters.ICloud, + coda adapters.ICoda, pool *pgxpool.Pool, ) *WorkflowController { return &WorkflowController{ diff --git a/internal/domain/models.go b/internal/domain/models.go index 48ec870..5f320b9 100644 --- a/internal/domain/models.go +++ b/internal/domain/models.go @@ -11,6 +11,11 @@ type Folder struct { PrivateURL string // http://domain/apps/files/?dir=/temp/k OR http://domain/f/3333 } +type Response struct { + Folder *Folder + ErrMessage error +} + type CodaApplication struct { ID string `json:"id"` Summary string `json:"summary"` diff --git a/internal/services/cloud.go b/internal/services/cloud.go index b5a748e..b4f1692 100644 --- a/internal/services/cloud.go +++ b/internal/services/cloud.go @@ -16,10 +16,6 @@ type Cloud struct { Config domain.CloudConfig } -type ICloud interface { - CreateFolder(name string) Response -} - func NewCloud(conf domain.CloudConfig) *Cloud { client := NewClient(). @@ -35,13 +31,8 @@ func NewCloud(conf domain.CloudConfig) *Cloud { } } -type Response struct { - Folder *domain.Folder - ErrMessage error -} - -func (c *Cloud) CreateFolder(name string) Response { - var R Response +func (c *Cloud) CreateFolder(name string) domain.Response { + var R domain.Response rootDir := c.Config.RootDir user := c.Config.User diff --git a/internal/services/dummy_telegram.go b/internal/services/dummy_telegram.go new file mode 100644 index 0000000..dca909f --- /dev/null +++ b/internal/services/dummy_telegram.go @@ -0,0 +1,28 @@ +package services + +import "ticket-pimp/internal/domain" + +type DummyTelegram struct { + *CommonClient + config domain.TelegramConfig +} + +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"` +} + +func (tg *DummyTelegram) DummyNotification(id string, text string) { + tg.R(). + SetBody(&TelegramMessage{ + ChatID: id, + Text: text, + DisableNotification: true, + ParseMode: "HTML", + DisablePreview: true, + }). + Post("https://api.telegram.org/bot" + tg.config.Token + "/sendMessage") +}