small changes;

This commit is contained in:
naudachu 2023-11-17 13:48:03 +05:00
parent f677ec5986
commit d42b590a14
9 changed files with 126 additions and 99 deletions

View File

@ -8,9 +8,10 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
) )
type router struct { type client struct {
Commands []CommandRoute Commands []Command
Components []ComponentRoute Components []Component
ListenPostsHandler func(s *discordgo.Session, th *discordgo.ThreadCreate)
Tags []discordgo.ForumTag Tags []discordgo.ForumTag
controller controller.WorkflowController controller controller.WorkflowController
@ -18,24 +19,24 @@ type router struct {
} }
// Подключение роутов к Discord боту // Подключение роутов к Discord боту
func InitRouter(wc controller.WorkflowController, conf *domain.DiscordConfig) *router { func InitRouter(wc controller.WorkflowController, conf *domain.DiscordConfig) *client {
var r router var r client
r.Commands = append(r.Commands,
// r.CreateRepoHandler(3),
// r.CreateFolderHandler(3),
r.Ping(),
// r.CreateTicketHandler(3),
// r.InitProjectFromChannel(3),
// r.GetInfo(),
r.CreateExternalTask(),
)
r.Components = append(r.Components,
r.StartTask(),
r.CloseTask(),
)
r.controller = wc r.controller = wc
r.conf = conf 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.Tags = append( r.Tags = append(
r.Tags, r.Tags,
discordgo.ForumTag{ discordgo.ForumTag{
@ -49,21 +50,25 @@ func InitRouter(wc controller.WorkflowController, conf *domain.DiscordConfig) *r
Moderated: true, Moderated: true,
EmojiName: "✅", EmojiName: "✅",
}) })
r.ListenPostsHandler = r.ListenPosts
return &r return &r
} }
type CommandRoute struct { //
// Подключение роутов к Discord боту
type Command struct {
Command discordgo.ApplicationCommand Command discordgo.ApplicationCommand
Handler func(s *discordgo.Session, i *discordgo.InteractionCreate) Handler func(s *discordgo.Session, i *discordgo.InteractionCreate)
} }
type ComponentRoute struct { type Component struct {
Component discordgo.MessageComponent Component discordgo.MessageComponent
Handler func(s *discordgo.Session, i *discordgo.InteractionCreate) Handler func(s *discordgo.Session, i *discordgo.InteractionCreate)
} }
func (h *router) defaultFollowUp(answer string, s *discordgo.Session, i *discordgo.InteractionCreate) { func (h *client) defaultFollowUp(answer string, s *discordgo.Session, i *discordgo.InteractionCreate) {
// Sending result: // Sending result:
_, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{ _, err := s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{

View File

@ -1,34 +0,0 @@
package handler
import (
"testing"
"ticket-pimp/internal/domain"
)
type test struct {
arg domain.Git
expected string
}
var tests = []test{
{domain.Git{
Name: "text",
FullName: "",
Private: false,
Url: "",
CloneUrl: "",
HtmlUrl: "https://reddit.com/",
SshUrl: "",
}, "Repo <a href=\"https://reddit.com/\">text</a> has been created!"},
}
func TestPrepareAnswer(t *testing.T) {
for _, test := range tests {
g := newGit(&test.arg)
if output := g.PrepareAnswer(); output != test.expected {
t.Errorf("Output %q not equal to expected %q", output, test.expected)
}
}
}

View File

@ -55,7 +55,7 @@ func run(conf domain.Config) {
go func() { go func() {
opts := discord.DiscordOptions{ opts := discord.DiscordOptions{
Controller: controller, Controller: controller,
AppConfig: &conf, Config: &conf,
} }
if err := discord.Run(conf, opts); err != nil { if err := discord.Run(conf, opts); err != nil {
log.Fatalf("discord bot cannot be runned: %v", err) log.Fatalf("discord bot cannot be runned: %v", err)

View File

@ -92,8 +92,13 @@ func (wc *WorkflowController) createGitForExistingProject(ctx context.Context, r
} }
func (wc *WorkflowController) CreateGit(ctx context.Context, req GitRequest) *ProjectResponse { func (wc *WorkflowController) CreateGit(ctx context.Context, req GitRequest) *ProjectResponse {
if req.ChannelID == "" {
return &ProjectResponse{
Project: nil,
Message: errors.New("empty channel string"),
}
}
// [ ] Валидация на пустой канал?
p, err := wc.GetProjectByChannelID(ctx, req.ChannelID) p, err := wc.GetProjectByChannelID(ctx, req.ChannelID)
if err != nil { if err != nil {
return &ProjectResponse{ return &ProjectResponse{
@ -116,7 +121,6 @@ func (wc *WorkflowController) CreateGit(ctx context.Context, req GitRequest) *Pr
Message: errors.New("build git already exists"), Message: errors.New("build git already exists"),
} }
} else { } else {
// [x]
return wc.createGitForExistingProject(ctx, req, p) return wc.createGitForExistingProject(ctx, req, p)
} }
case p != nil && !req.IsBuildGit: case p != nil && !req.IsBuildGit:
@ -126,7 +130,6 @@ func (wc *WorkflowController) CreateGit(ctx context.Context, req GitRequest) *Pr
Message: errors.New("project git already exists"), Message: errors.New("project git already exists"),
} }
} else { } else {
// [x]
return wc.createGitForExistingProject(ctx, req, p) return wc.createGitForExistingProject(ctx, req, p)
} }
default: default:

View File

@ -86,10 +86,10 @@ func (wc *WorkflowController) GetProjectByChannelID(ctx context.Context, id stri
return &proj, nil return &proj, nil
} }
// Saves current channel as project's channel;
func (wc *WorkflowController) InitProjectInChannel(ctx context.Context, channelID string, key string) (*domain.Project, error) { func (wc *WorkflowController) InitProjectInChannel(ctx context.Context, channelID string, key string) (*domain.Project, error) {
dbTicket, err := wc.q.GetTicketByChannelID(ctx, pgtype.Text{String: channelID, Valid: true}) dbTicket, err := wc.q.GetTicketByChannelID(ctx, pgtype.Text{String: channelID, Valid: true})
if err == pgx.ErrNoRows { if err == pgx.ErrNoRows {
// [ ] Логика инициализации проекта
dbTicket, err = wc.q.CreateTicket( dbTicket, err = wc.q.CreateTicket(
ctx, ctx,
db.CreateTicketParams{ db.CreateTicketParams{

View File

@ -4,7 +4,6 @@ import (
"context" "context"
"fmt" "fmt"
"os" "os"
"strconv"
"ticket-pimp/internal/domain" "ticket-pimp/internal/domain"
"ticket-pimp/internal/storage/db" "ticket-pimp/internal/storage/db"
"time" "time"
@ -13,9 +12,14 @@ import (
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) { // WriteTaskToDB
/*
// Записываем в базу созданную задачу ------------------------------------------ Makes an SQL query to create new tasks row from domain.Task entity
- Creator field: telegram nickname or Discord's Mention();
- Creator link (tg ID) in telegram case;
- Description from telegram/discord message bodies;
*/
func (wc *WorkflowController) WriteTaskToDB(t *domain.Task) (*domain.Task, error) {
dbtask, err := wc.q.InsertTask(context.TODO(), db.InsertTaskParams{ dbtask, err := wc.q.InsertTask(context.TODO(), db.InsertTaskParams{
Creator: pgtype.Text{String: t.Creator, Valid: true}, Creator: pgtype.Text{String: t.Creator, Valid: true},
CreatorLink: pgtype.Text{ CreatorLink: pgtype.Text{
@ -33,6 +37,29 @@ func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
// ------------------------------------------------------------------------------------ // ------------------------------------------------------------------------------------
task := newConvertable(&dbtask).ExtractDomain() task := newConvertable(&dbtask).ExtractDomain()
return task, nil
}
// InitTask
/*
Runs the following:
- Use WriteTaskToDB method to make a new task row in the db;
- init new discord bot instance;
-
Possible errors:
- db record couldn't be created;
- bot couldn't be inited;
- bot session couldn't be started;
- thread couldn't be started;
- first task message couldn't be edited;
*/
func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
task, err := wc.WriteTaskToDB(t)
if err != nil {
return nil, fmt.Errorf("unable to create task at the db: %v", err)
}
// Инициализируем новый клиент дискорда // Инициализируем новый клиент дискорда
// [ ] Нездоровое получение параметров клиента из os.. // [ ] Нездоровое получение параметров клиента из os..
@ -44,16 +71,14 @@ func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
s, err := discordgo.New("Bot " + token) s, err := discordgo.New("Bot " + token)
if err != nil { if err != nil {
return task, fmt.Errorf("unable to create discord session: %v", err) return task, fmt.Errorf("unable to create discord session: %v", err)
// [ ] Что делать, если не получилось создать задачу?
} }
if err := s.Open(); err != nil { if err := s.Open(); err != nil {
return task, fmt.Errorf("cannot open the session: %v", err) return task, fmt.Errorf("cannot open the session: %v", err)
// [ ] Что делать, если не получилось создать задачу?
} }
msg := discordgo.MessageSend{ msg := discordgo.MessageSend{
Content: task.NotStartedMessage(), Content: task.DiscordMessage(domain.NewTaskState()),
Components: []discordgo.MessageComponent{ Components: []discordgo.MessageComponent{
discordgo.ActionsRow{ discordgo.ActionsRow{
Components: []discordgo.MessageComponent{ Components: []discordgo.MessageComponent{
@ -77,7 +102,7 @@ func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
th, err := s.ForumThreadStartComplex( th, err := s.ForumThreadStartComplex(
forumChannelID, forumChannelID,
&discordgo.ThreadStart{ &discordgo.ThreadStart{
Name: "Task ID:" + strconv.Itoa(int(task.ID)), Name: fmt.Sprintf("Task ID: %d, by %s", task.ID, task.Creator),
}, },
&msg, &msg,
) )
@ -85,10 +110,7 @@ func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
return task, fmt.Errorf("unable to update channel: %v", err) return task, fmt.Errorf("unable to update channel: %v", err)
} }
err = wc.q.UpdateTaskWithMessageID(context.TODO(), db.UpdateTaskWithMessageIDParams{ err = wc.UpdateTasksMessageID(context.TODO(), th.ID, task.ID)
Messageid: pgtype.Text{String: th.ID, Valid: true},
ID: dbtask.ID,
})
if err != nil { if err != nil {
return task, fmt.Errorf("unable to set discord message to task: %v", err) return task, fmt.Errorf("unable to set discord message to task: %v", err)
} }
@ -96,6 +118,14 @@ func (wc *WorkflowController) InitTask(t *domain.Task) (*domain.Task, error) {
return task, nil return task, nil
} }
func (wc *WorkflowController) UpdateTasksMessageID(ctx context.Context, msgID string, taskID int32) error {
err := wc.q.UpdateTaskWithMessageID(context.TODO(), db.UpdateTaskWithMessageIDParams{
Messageid: pgtype.Text{String: msgID, Valid: true},
ID: taskID,
})
return err
}
func (wc *WorkflowController) UpdateTask(id string, opt int, user string) (*TaskConvertable, error) { func (wc *WorkflowController) UpdateTask(id string, opt int, user string) (*TaskConvertable, error) {
var ( var (
err error err error

View File

@ -12,6 +12,13 @@ import (
"github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgtype"
) )
// FullProjectInit
/*
Deprecated method to create a project with all related data:
- git;
- git for the project's build;
- cloud folder;
*/
func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, error) { func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, error) {
appKey := fmt.Sprintf("%s-%s", key, id) appKey := fmt.Sprintf("%s-%s", key, id)

View File

@ -50,6 +50,7 @@ type TelegramConfig struct {
type DiscordConfig struct { type DiscordConfig struct {
Token string Token string
IsProjectChannel string IsProjectChannel string
IsTaskForum string
} }
type ApplicationConfig struct { type ApplicationConfig struct {
@ -95,6 +96,7 @@ func InitConfig(envFilePath string) Config {
Discord: DiscordConfig{ Discord: DiscordConfig{
Token: os.Getenv("DISCORD_TOKEN"), Token: os.Getenv("DISCORD_TOKEN"),
IsProjectChannel: os.Getenv("PROJECTS_CHANNEL_GROUP"), IsProjectChannel: os.Getenv("PROJECTS_CHANNEL_GROUP"),
IsTaskForum: os.Getenv("TASKS_CHANNEL"),
}, },
} }
} }

View File

@ -69,38 +69,52 @@ type Task struct {
URL string URL string
} }
func (t *Task) NotStartedMessage() string { type TaskState int
return fmt.Sprintf( const (
"## TaskID: %d\nCreated by: %s\n>>> %s\n", new TaskState = iota
t.ID, inprogress
t.Creator, done
t.Description, )
)
func NewTaskState() TaskState {
return TaskState(0)
} }
func (t *Task) StartedMessage() string { func InrpogressTaskState() TaskState {
return TaskState(1)
}
func DoneTaskState() TaskState {
return TaskState(2)
}
// Creates a string for discordgo.DiscordMessage.Content
// State: New task;
func (t *Task) DiscordMessage(ts TaskState) string {
switch ts {
case new:
return fmt.Sprintf( return fmt.Sprintf(
"## TaskID: %d\nCreated by: %s\n Assignee: %s\n🚀 Started at: %s\n>>> %s\n", "Created at: %s \n>>> %s\n",
t.CreatedAt,
t.Description,
)
case inprogress:
return fmt.Sprintf(
"**TaskID: %d** Started by: %s\n🚀 Started at: %s\n",
t.ID, t.ID,
t.Creator,
t.Assignee, t.Assignee,
t.UpdatedAt, t.UpdatedAt,
t.Description,
) )
} case done:
func (t *Task) ClosedMessage() string {
return fmt.Sprintf( return fmt.Sprintf(
"## TaskID: %d\nCreated by: %s\n Assignee: %s\n✅ Closed at: %s\n>>> %s\n", "**TaskID: %d** Closed by: %s\n✅ Closed at: %s\n",
t.ID, t.ID,
t.Creator,
t.Assignee, t.Assignee,
t.DeletedAt, t.DeletedAt,
t.Description,
) )
}
return "task state not provided"
} }
func NewTask(summ, desc, c, cLink string) *Task { func NewTask(summ, desc, c, cLink string) *Task {