- finished coda usage

This commit is contained in:
naudachu 2023-11-25 20:19:40 +05:00
parent eb05bf8470
commit 19f6064066
18 changed files with 170 additions and 74 deletions

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
.vscode/
.idea/
.github
docker/
**/**/*.env
docker/**

View File

@ -16,7 +16,7 @@ type ICloud interface {
type ICoda interface {
ListDocs()
CreateApp(task domain.CodaApplication)
CreateApp(task domain.CodaApplication) (string, error)
CreateTask(title string, desc string, creatorName string, creatorID string) (string, error)
GetRowLink(id string) (string, error)
}

View File

@ -9,7 +9,7 @@ import (
"ticket-pimp/internal/controller"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/services"
"ticket-pimp/internal/external"
"github.com/bwmarrin/discordgo"
)
@ -42,6 +42,10 @@ var (
Name: "ping",
Description: "pongs in a reply",
},
{
Name: "coda_ticket",
Description: "Creates ticket in Coda.io w/ provided info",
},
{
Name: "init_project",
Description: "Connect project with Coda ID",
@ -166,7 +170,7 @@ func isRejected(s *discordgo.Session, i *discordgo.InteractionCreate) bool {
}
func route(s *discordgo.Session, i *discordgo.InteractionCreate, h discord_handler.Handler) {
initialResponse(s, i)
// initialResponse(s, i)
if isRejected(s, i) {
return
@ -175,9 +179,8 @@ func route(s *discordgo.Session, i *discordgo.InteractionCreate, h discord_handl
// Определяем тип взаимодействия и хэндлим правильной функцией:
switch i.Type {
case discordgo.InteractionApplicationCommand:
cmd := i.ApplicationCommandData().Name
switch cmd {
switch i.ApplicationCommandData().Name {
case "ping":
h.Ping(s, i)
case "project":
@ -190,10 +193,13 @@ func route(s *discordgo.Session, i *discordgo.InteractionCreate, h discord_handl
h.CreateFolder(s, i)
case "init_project":
h.InitChannelAsProject(s, i)
case "coda_ticket":
h.CreateCoda(s, i)
}
case discordgo.InteractionMessageComponent:
c := i.MessageComponentData().CustomID
switch c {
switch i.MessageComponentData().CustomID {
case "task_start":
h.HandleTaskButtons(s, i)
case "task_close":
@ -221,10 +227,11 @@ func updateForum(conf *domain.Config, s *discordgo.Session) ([]discordgo.ForumTa
// Result tags array
tags := forum.AvailableTags
// Check if preset tag exists into current channel
// Check if preset tag exists into current channel..
for i := 0; i < len(tagsPreset); i++ {
_, ok := tagsMap[tagsPreset[i].Name]
if !ok {
// .. and append them if they aren't
tags = append(tags, tagsPreset[i])
}
}
@ -241,6 +248,22 @@ func updateForum(conf *domain.Config, s *discordgo.Session) ([]discordgo.ForumTa
fmt.Printf("N: %s, ID: %s", t.Name, t.ID)
}
// Update config w/ tags:
confTags := make(map[domain.TaskState]string)
for _, tag := range dchan.AvailableTags {
switch tag.Name {
case "Не начат":
confTags[domain.State(0)] = tag.ID
case "В работе":
confTags[domain.State(1)] = tag.ID
case "Готово":
confTags[domain.State(2)] = tag.ID
}
}
conf.Discord.Tags = confTags
return dchan.AvailableTags, nil
}
@ -267,7 +290,7 @@ func Run(conf *domain.Config, opts DiscordOptions) error {
h := discord_handler.New(
opts.Controller,
&conf.Discord,
services.NewDummyClient(conf.Telegram),
external.NewDummyClient(conf.Telegram),
)
// Add posts listener

View File

@ -1,24 +1,23 @@
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{
/*_, 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
}
// if err != nil {
// s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{
// Content: fmt.Sprintf("Something went wrong: %v", err),
// })
// return
// }
}
// setFlag

View File

@ -6,16 +6,16 @@ import (
"ticket-pimp/client/telegram/telegram_handler"
"ticket-pimp/internal/controller"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/services"
"ticket-pimp/internal/external"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
)
type TelegramOptions struct {
GitService *services.Git
CloudService *services.Cloud
Coda *services.Coda
GitService *external.Git
CloudService *external.Cloud
Coda *external.Coda
AppConfig *domain.Config
Controller *controller.WorkflowController
}

View File

@ -11,7 +11,7 @@ import (
"ticket-pimp/internal/controller"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/services"
"ticket-pimp/internal/external"
"ticket-pimp/client/discord"
"ticket-pimp/client/telegram"
@ -59,7 +59,7 @@ func Go(ctx context.Context, fns ...func(context.Context) error) error {
}
func applyMigrations(connString string) {
// Aply migrations:
// Apply migrations:
dbConnConfig, err := pgxpool.ParseConfig(connString)
if err != nil {
@ -79,17 +79,20 @@ func applyMigrations(connString string) {
}
fmt.Printf("Applied %d migrations!\n", n)
db.Close()
err = db.Close()
if err != nil {
log.Fatal("unable to close db connection")
}
}
func run(conf *domain.Config) {
func run(c *domain.Config) {
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, os.Kill, syscall.SIGTERM)
defer cancel()
// -- DB connection init -- START
connString := fmt.Sprintf(
"postgresql://%s:%s@%s:%s/%s",
conf.DB.User, conf.DB.Pass, conf.DB.Host, conf.DB.Port, conf.DB.Name,
c.DB.User, c.DB.Pass, c.DB.Host, c.DB.Port, c.DB.Name,
)
conn, err := pgxpool.New(
ctx,
@ -97,42 +100,41 @@ func run(conf *domain.Config) {
if err != nil {
log.Fatalf("DB connection failed: %v", err)
}
// -- DB connection init -- END
// Aply migrations:
// Apply migrations:
applyMigrations(connString)
// Init services instances:
gitService := services.NewGit(conf.Git)
cloudService := services.NewCloud(conf.Cloud)
codaService := services.NewCodaClient(conf.Coda)
git := external.NewGit(c.Git)
cloud := external.NewCloud(c.Cloud)
coda := external.NewCoda(c.Coda)
// Controller instance init:
controller := controller.NewWorkflowController(
gitService,
cloudService,
codaService,
controller := controller.NewApp(
git,
cloud,
coda,
conn,
conf,
c,
)
Go(ctx,
func(ctx context.Context) error {
opts := discord.DiscordOptions{
Controller: controller,
Config: conf,
Config: c,
}
if err := discord.Run(conf, opts); err != nil {
if err := discord.Run(c, opts); err != nil {
return errors.Errorf("discord bot cannot be runned: %v", err)
}
return nil
},
func(ctx context.Context) error {
opts := telegram.TelegramOptions{
GitService: gitService,
CloudService: cloudService,
Coda: codaService,
AppConfig: conf,
GitService: git,
CloudService: cloud,
Coda: coda,
AppConfig: c,
Controller: controller,
}

View File

@ -0,0 +1,27 @@
package controller
import (
"context"
"fmt"
"ticket-pimp/internal/domain"
)
func (wc *WorkflowController) CreateCoda(guildID string, chanID string) (string, error) {
p, err := wc.GetProjectByChannelID(context.TODO(), chanID)
if err != nil {
return "", err
}
requestResult, err := wc.ICoda.CreateApp(domain.CodaApplication{
ID: p.Key,
Summary: p.Name,
URL: fmt.Sprintf("https://discord.com/channels/%s/%s", guildID, chanID),
Git: p.ProjectGit,
GitBuild: p.BuildGit,
Folder: p.Folder,
})
return requestResult, err
}

View File

@ -3,6 +3,7 @@ package controller
import (
"context"
"fmt"
"strconv"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/storage/db"
@ -67,25 +68,24 @@ func (wc *WorkflowController) ProjectCreate(ctx context.Context, project domain.
}
func (wc *WorkflowController) GetProjectByChannelID(ctx context.Context, id string) (*domain.Project, error) {
var proj domain.Project
dbTicket, err := wc.q.GetTicketByChannelID(ctx, pgtype.Text{String: id, Valid: true})
if err != nil {
if err == pgx.ErrNoRows {
return nil, nil
}
return nil, err
} else {
proj = domain.Project{
ID: string(dbTicket.ID),
}
return &domain.Project{
ID: strconv.Itoa(int(dbTicket.ID)),
Key: dbTicket.Key.String,
Name: dbTicket.Key.String,
Name: dbTicket.Title.String,
ChannelID: dbTicket.Channelid.String,
ProjectGit: dbTicket.ProjectGit.String,
BuildGit: dbTicket.BuildGit.String,
Folder: dbTicket.Folder.String,
}
}
return &proj, nil
}, nil
}
// Saves current channel as project's channel;

View File

@ -94,7 +94,7 @@ func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
wc.conf.Discord.IsTaskForum,
&discordgo.ThreadStart{
Name: fmt.Sprintf("Task ID: %d, by %s", task.ID, task.Creator),
AppliedTags: []string{"Не начат"},
AppliedTags: []string{wc.conf.Discord.Tags[domain.NewTaskState()]},
},
&msg,
)

View File

@ -17,7 +17,7 @@ type WorkflowController struct {
conf *domain.Config
}
func NewWorkflowController(
func NewApp(
git adapters.IGit,
cloud adapters.ICloud,
coda adapters.ICoda,

View File

@ -53,6 +53,7 @@ type DiscordConfig struct {
Token string
IsProjectChannel string
IsTaskForum string
Tags map[TaskState]string
}
type ApplicationConfig struct {

View File

@ -83,6 +83,18 @@ const (
done
)
func State(i int) TaskState {
switch i {
case 0:
return new
case 1:
return inprogress
case 2:
return done
}
return -1
}
func NewTaskState() TaskState {
return TaskState(0)
}

View File

@ -1,7 +0,0 @@
package domain
type TgUser struct {
ID string
Name string
TgLink string
}

View File

@ -1,4 +1,4 @@
package services
package external
import (
"fmt"

View File

@ -1,4 +1,4 @@
package services
package external
import (
"errors"

View File

@ -1,8 +1,10 @@
package services
package external
import (
"errors"
"fmt"
"log"
"strings"
"ticket-pimp/internal/domain"
"time"
@ -14,7 +16,7 @@ type Coda struct {
Config domain.CodaConfig
}
func NewCodaClient(conf domain.CodaConfig) *Coda {
func NewCoda(conf domain.CodaConfig) *Coda {
client := NewClient().
SetTimeout(15 * time.Second).
@ -47,14 +49,49 @@ func (c *Coda) ListDocs() {
log.Print(resp)
}
func (c *Coda) CreateApp(task domain.CodaApplication) {
resp, _ := c.R().
type CodaWebhookResponse struct {
ReqID string `json:"requestId"`
}
func (c *Coda) CreateApp(task domain.CodaApplication) (string, error) {
var whResponse CodaWebhookResponse
c.R().
SetBody(task).
SetContentType("application/json").
SetSuccessResult(&whResponse).
SetBearerAuthToken(c.Config.Develop).
Post("/docs/Ic3IZpQ3Wk/hooks/automation/grid-auto-NlUwM7F7Cr")
fmt.Print(resp)
if whResponse.ReqID == "" {
return "", errors.New("coda responded w/o mutate id")
}
var (
// mutate string
sep string = ":"
)
if !strings.Contains(whResponse.ReqID, sep) {
return "", fmt.Errorf("unexpected coda response: %s", whResponse.ReqID)
}
// arr := strings.Split(whResponse.ReqID, sep)
// if arr[0] == "mutate" {
// mutate = arr[1]
// }
// mutateResponse, err := c.R().
// SetContentType("application/json").
// SetBearerAuthToken(c.Config.Develop).
// Get(fmt.Sprintf("/mutationStatus/%s", mutate))
// if err != nil {
// return "", fmt.Errorf("unable to get coda mutate result: %s", mutate)
// }
// _ = mutateResponse
return whResponse.ReqID, nil
}
func (c *Coda) CreateTask(title string, desc string, creatorName string, creatorID string) (string, error) {

View File

@ -1,4 +1,4 @@
package services
package external
import (
"ticket-pimp/internal/domain"

View File

@ -1,4 +1,4 @@
package services
package external
import (
"fmt"