diff --git a/discord/handler/handle_folder.go b/discord/handler/handle_folder.go index 50ce21d..0373596 100644 --- a/discord/handler/handle_folder.go +++ b/discord/handler/handle_folder.go @@ -53,11 +53,11 @@ func (h *router) CreateFolderHandler(nameMinLenght int) route { optionMap[opt.Name] = opt } + // Creating request: + var req controller.FolderRequest name, insertedValueNotNil := optionMap[nameOption] dchan, err := s.Channel(i.ChannelID) - // Creating request: - var req controller.FolderRequest if err != nil { log.Printf("error while identifying channel: %v", err) } else { diff --git a/discord/handler/handle_git.go b/discord/handler/handle_git.go new file mode 100644 index 0000000..5816b9f --- /dev/null +++ b/discord/handler/handle_git.go @@ -0,0 +1,131 @@ +package handler + +import ( + "context" + "fmt" + "log" + "strconv" + "ticket-pimp/internal/controller" + + "github.com/bwmarrin/discordgo" +) + +func (h *router) CreateRepoHandler(repoNameMinLength int) route { + const ( + repoType = "repo_type" + projectRepo = "project_repo" + buildRepo = "build_repo" + nameOption = "repo_name" + ) + + return route{ + Command: discordgo.ApplicationCommand{ + Name: "repo", + Description: "Command for repository creation", + 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: &repoNameMinLength, + }, + }, + }, + Handler: func(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 = "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 == strconv.Itoa(1150719794853716028) { + 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 { + result = resp.Message.Error() + } else { + result = fmt.Sprintf( + "## Project info:\n🔑 key: %s\n📂 folder: %s\n👾 project git: %s\n🚀 build git: %s\n\nErrors: %v", + resp.Project.ShortName, + resp.Project.Cloud, + resp.Project.ProjectGit, + resp.Project.BuildGit, + resp.Message, + ) + } + // Sending result: + _, err = s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{ + Content: result, + }) + + if err != nil { + s.FollowupMessageCreate(i.Interaction, true, &discordgo.WebhookParams{ + Content: fmt.Sprintf("Something went wrong: %v", err), + }) + return + } + }, + } +} diff --git a/discord/handler/handle_repo.go b/discord/handler/handle_repo.go deleted file mode 100644 index a62d7fa..0000000 --- a/discord/handler/handle_repo.go +++ /dev/null @@ -1,109 +0,0 @@ -package handler - -import ( - "context" - "fmt" - - "github.com/bwmarrin/discordgo" -) - -func (h *router) CreateRepoHandler(repoNameMinLength int) route { - const ( - projectRepo = "project_repo" - buildRepo = "build_repo" - ) - - return route{ - Command: discordgo.ApplicationCommand{ - Name: "repo", - Description: "Command for repository creation", - Options: []*discordgo.ApplicationCommandOption{ - { - Type: discordgo.ApplicationCommandOptionString, - Name: "repo_type", - 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: "repo_name", - Description: "Type the repository's name", - Required: false, - MinLength: &repoNameMinLength, - }, - }, - }, - Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) { - 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 - } - - var str string = "" - - project, err := h.controller.GetProjectByChannelID(context.TODO(), i.ChannelID) - if err != nil { - result = fmt.Sprintf("unable to retrieve project from db, error: %v", err) - } else { - var suffix string - if option, ok := optionMap["repo_type"]; ok { - switch option.Value { - case projectRepo: - suffix = "" - case buildRepo: - suffix = "-build" - } - } - - if project == nil { - if option, ok := optionMap["repo_name"]; ok { - str = option.StringValue() - } else { - str = "" - } - } else { - str = project.ShortName - } - - if str == "" { - result = "Ты, либо в проекте репо создавай, либо имя напиши, блет!" - } else { - str = str + suffix - - // var g *domain.Git - - g, err := h.controller.IGit.CreateRepo(str) - if err != nil { - result = fmt.Sprintf("error while repo creation: %v", err) - } else { - result = "🚀 " + g.HtmlUrl + " was created" - } - } - } - - resp := &discordgo.InteractionResponse{ - Type: discordgo.InteractionResponseChannelMessageWithSource, - Data: &discordgo.InteractionResponseData{ - Content: result, - }, - } - - s.InteractionRespond(i.Interaction, resp) - }, - } -} diff --git a/internal/controller/control_folder.go b/internal/controller/control_folder.go index a445ee6..7a8f61b 100644 --- a/internal/controller/control_folder.go +++ b/internal/controller/control_folder.go @@ -17,11 +17,6 @@ type FolderRequest struct { InsertedName string } -type ProjectResponse struct { - Project *domain.Project - Message error -} - func (wc *WorkflowController) CreateFolder(ctx context.Context, req FolderRequest) *ProjectResponse { project, err := wc.GetProjectByChannelID(ctx, req.ChannelID) @@ -96,5 +91,4 @@ func (wc *WorkflowController) CreateFolder(ctx context.Context, req FolderReques } return &result - } diff --git a/internal/controller/control_git.go b/internal/controller/control_git.go new file mode 100644 index 0000000..c9e1f0d --- /dev/null +++ b/internal/controller/control_git.go @@ -0,0 +1,168 @@ +package controller + +import ( + "context" + "errors" + "fmt" + "log" + "ticket-pimp/internal/domain" + "ticket-pimp/internal/storage/db" + "time" + + "github.com/jackc/pgx/v5/pgtype" +) + +type GitRequest struct { + ChannelID string + InsertedName string + IsBuildGit bool +} + +func (wc *WorkflowController) createGitForExistingProject(ctx context.Context, req GitRequest, p *domain.Project) *ProjectResponse { + var ( + name string = "" + dbticket db.Ticket + ) + switch { + case p.ShortName != "": + name = p.ShortName + if req.IsBuildGit { + name += "-build" + } + case req.InsertedName != "": + name = req.InsertedName + if req.IsBuildGit { + name += "-build" + } + } + + // response := wc.ICloud.CreateFolder(name) + git, err := wc.IGit.CreateRepo(name) + if err != nil { + return &ProjectResponse{ + Project: p, + Message: fmt.Errorf("unable to create git w/ an error: %v", err), + } + } + + if req.IsBuildGit { + dbticket, err = wc.q.UpdateTicketBuildGit( + ctx, + db.UpdateTicketBuildGitParams{ + BuildGit: pgtype.Text{String: git.HtmlUrl, Valid: true}, + UpdatedAt: pgtype.Timestamptz{Time: time.Now(), InfinityModifier: 0, Valid: true}, + Channelid: pgtype.Text{String: req.ChannelID, Valid: true}, + }) + if err != nil { + log.Printf("unable to scan row from db: %v", err) + return &ProjectResponse{ + Project: p, + Message: fmt.Errorf("unable to update project: %v", err), + } + } + } else { + dbticket, err = wc.q.UpdateTicketProjectGit( + ctx, + db.UpdateTicketProjectGitParams{ + ProjectGit: pgtype.Text{String: git.HtmlUrl, Valid: true}, + UpdatedAt: pgtype.Timestamptz{Time: time.Now(), InfinityModifier: 0, Valid: true}, + Channelid: pgtype.Text{String: req.ChannelID, Valid: true}, + }, + ) + if err != nil { + log.Printf("unable to scan row from db: %v", err) + return &ProjectResponse{ + Project: p, + Message: fmt.Errorf("unable to update project: %v", err), + } + } + } + + return &ProjectResponse{ + Project: &domain.Project{ + ID: string(dbticket.ID), + ShortName: dbticket.Key.String, + ChannelID: dbticket.Channelid.String, + ProjectGit: dbticket.ProjectGit.String, + BuildGit: dbticket.BuildGit.String, + Cloud: dbticket.Folder.String, + }, + Message: err, + } +} + +func (wc *WorkflowController) CreateGit(ctx context.Context, req GitRequest) *ProjectResponse { + + // [ ] Валидация на пустой канал? + p, err := wc.GetProjectByChannelID(ctx, req.ChannelID) + if err != nil { + return &ProjectResponse{ + Project: nil, + Message: fmt.Errorf("unable to retrieve project from db: %v", err), + } + } + + // var ( + // name string + // dbticket db.Ticket + // result ProjectResponse + // ) + + switch { + case p != nil && req.IsBuildGit: + if p.BuildGit != "" { + return &ProjectResponse{ + Project: p, + Message: errors.New("build git already exists"), + } + } else { + // [x] + return wc.createGitForExistingProject(ctx, req, p) + } + case p != nil && !req.IsBuildGit: + if p.ProjectGit != "" { + return &ProjectResponse{ + Project: p, + Message: errors.New("project git already exists"), + } + } else { + // [x] + return wc.createGitForExistingProject(ctx, req, p) + } + default: + if req.InsertedName != "" { + + if req.IsBuildGit { + req.InsertedName += "-build" + } + + git, err := wc.IGit.CreateRepo(req.InsertedName) + if err != nil || git == nil { + return &ProjectResponse{ + Project: nil, + Message: err, + } + } else { + if req.IsBuildGit { + return &ProjectResponse{ + Project: &domain.Project{ + BuildGit: git.HtmlUrl, + }, + Message: err, + } + } + return &ProjectResponse{ + Project: &domain.Project{ + ProjectGit: git.HtmlUrl, + }, + Message: err, + } + } + } else { + return &ProjectResponse{ + Project: nil, + Message: errors.New("передано пустое имя"), + } + } + } +} diff --git a/internal/controller/project.go b/internal/controller/control_project.go similarity index 100% rename from internal/controller/project.go rename to internal/controller/control_project.go diff --git a/internal/controller/control_workflow.go b/internal/controller/control_workflow.go new file mode 100644 index 0000000..c24fdbb --- /dev/null +++ b/internal/controller/control_workflow.go @@ -0,0 +1,84 @@ +package controller + +import ( + "context" + "fmt" + "log" + "strings" + "sync" + "ticket-pimp/internal/domain" + "ticket-pimp/internal/storage/db" + + "github.com/jackc/pgx/v5/pgtype" +) + +func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, error) { + + appKey := fmt.Sprintf("%s-%s", key, id) + + var ( + git, gitBuild *domain.Git + cloud *domain.Folder + ) + + var wg sync.WaitGroup + wg.Add(3) + + go func(ref **domain.Git) { + defer wg.Done() + *ref, _ = wc.IGit.CreateRepo(appKey) + }(&git) + + go func(ref **domain.Git) { + defer wg.Done() + *ref, _ = wc.IGit.CreateRepo(appKey + "-build") + }(&gitBuild) + + go func(ref **domain.Folder) { + defer wg.Done() + + *ref = wc.ICloud.CreateFolder(appKey).Folder + }(&cloud) + + wg.Wait() + + var gitResult, gitBuildResult, cloudResult string + + if git == nil { + gitResult = "cannot create git" + } else { + gitResult = git.HtmlUrl + } + + if gitBuild == nil { + gitBuildResult = "cannot create git" + } else { + gitBuildResult = fmt.Sprintf("ssh://%s/%s.git", gitBuild.SshUrl, gitBuild.FullName) + } + + if cloud == nil { + cloudResult = "cannot create folder" + } else { + cloudResult = cloud.PrivateURL + } + ctx := context.TODO() + + insertedTicket, err := wc.q.CreateTicket(ctx, db.CreateTicketParams{ + Key: pgtype.Text{String: appKey, Valid: true}, + Channelid: pgtype.Text{}, + }) + if err != nil { + log.Fatal(err) + } + log.Print(insertedTicket) + + wc.ICoda.CreateApp(domain.CodaApplication{ + ID: appKey, + Summary: strings.TrimSpace(name), + Git: gitResult, + GitBuild: gitBuildResult, + Folder: cloudResult, + }) + + return appKey, nil +} diff --git a/internal/controller/controller.go b/internal/controller/controller.go index a804b29..c65d97d 100644 --- a/internal/controller/controller.go +++ b/internal/controller/controller.go @@ -1,16 +1,10 @@ package controller import ( - "context" - "fmt" - "log" - "strings" - "sync" "ticket-pimp/internal/domain" "ticket-pimp/internal/services" "ticket-pimp/internal/storage/db" - "github.com/jackc/pgx/v5/pgtype" "github.com/jackc/pgx/v5/pgxpool" ) @@ -37,73 +31,7 @@ func NewWorkflowController( } } -func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, error) { - - appKey := fmt.Sprintf("%s-%s", key, id) - - var ( - git, gitBuild *domain.Git - cloud *domain.Folder - ) - - var wg sync.WaitGroup - wg.Add(3) - - go func(ref **domain.Git) { - defer wg.Done() - *ref, _ = wc.IGit.CreateRepo(appKey) - }(&git) - - go func(ref **domain.Git) { - defer wg.Done() - *ref, _ = wc.IGit.CreateRepo(appKey + "-build") - }(&gitBuild) - - go func(ref **domain.Folder) { - defer wg.Done() - - *ref = wc.ICloud.CreateFolder(appKey).Folder - }(&cloud) - - wg.Wait() - - var gitResult, gitBuildResult, cloudResult string - - if git == nil { - gitResult = "cannot create git" - } else { - gitResult = git.HtmlUrl - } - - if gitBuild == nil { - gitBuildResult = "cannot create git" - } else { - gitBuildResult = fmt.Sprintf("ssh://%s/%s.git", gitBuild.SshUrl, gitBuild.FullName) - } - - if cloud == nil { - cloudResult = "cannot create folder" - } else { - cloudResult = cloud.PrivateURL - } - ctx := context.TODO() - - insertedTicket, err := wc.q.CreateTicket(ctx, db.CreateTicketParams{ - Key: pgtype.Text{String: appKey, Valid: true}, - Channelid: pgtype.Text{}, - }) - if err != nil { - log.Fatal(err) - } - log.Print(insertedTicket) - - wc.ICoda.CreateApp(domain.CodaApplication{ - ID: appKey, - Summary: strings.TrimSpace(name), - Git: gitResult, - GitBuild: gitBuildResult, - Folder: cloudResult, - }) - - return appKey, nil +type ProjectResponse struct { + Project *domain.Project + Message error } diff --git a/internal/controller/tickets_config.go b/internal/controller/tickets_config.go deleted file mode 100644 index b4a5392..0000000 --- a/internal/controller/tickets_config.go +++ /dev/null @@ -1,22 +0,0 @@ -package controller - -import ( - "context" - "ticket-pimp/internal/domain" - db "ticket-pimp/internal/storage/db" -) - -type IConfigController interface { - Get(context.Context) (domain.ApplicationConfig, error) - Update(context.Context) (domain.ApplicationConfig, error) -} - -type AppConfig struct { - db *db.Queries -} - -func NewAppConfig(db *db.Queries) AppConfig { - return AppConfig{ - db: db, - } -} diff --git a/internal/storage/db/queries.sql.go b/internal/storage/db/queries.sql.go index d760019..a425106 100644 --- a/internal/storage/db/queries.sql.go +++ b/internal/storage/db/queries.sql.go @@ -195,6 +195,36 @@ func (q *Queries) SetNewConfig(ctx context.Context) (Appconfig, error) { return i, err } +const updateTicketBuildGit = `-- name: UpdateTicketBuildGit :one +UPDATE tickets +SET build_git = $1, updated_at = $2 +WHERE channelID = $3 +RETURNING id, key, channelid, project_git, build_git, folder, created_at, deleted_at, updated_at +` + +type UpdateTicketBuildGitParams struct { + BuildGit pgtype.Text + UpdatedAt pgtype.Timestamptz + Channelid pgtype.Text +} + +func (q *Queries) UpdateTicketBuildGit(ctx context.Context, arg UpdateTicketBuildGitParams) (Ticket, error) { + row := q.db.QueryRow(ctx, updateTicketBuildGit, arg.BuildGit, arg.UpdatedAt, arg.Channelid) + var i Ticket + err := row.Scan( + &i.ID, + &i.Key, + &i.Channelid, + &i.ProjectGit, + &i.BuildGit, + &i.Folder, + &i.CreatedAt, + &i.DeletedAt, + &i.UpdatedAt, + ) + return i, err +} + const updateTicketByID = `-- name: UpdateTicketByID :exec UPDATE tickets SET project_git = $1, build_git = $2, folder = $3 WHERE id = $4 ` @@ -245,3 +275,33 @@ func (q *Queries) UpdateTicketFolder(ctx context.Context, arg UpdateTicketFolder ) return i, err } + +const updateTicketProjectGit = `-- name: UpdateTicketProjectGit :one +UPDATE tickets +SET project_git = $1, updated_at = $2 +WHERE channelID = $3 +RETURNING id, key, channelid, project_git, build_git, folder, created_at, deleted_at, updated_at +` + +type UpdateTicketProjectGitParams struct { + ProjectGit pgtype.Text + UpdatedAt pgtype.Timestamptz + Channelid pgtype.Text +} + +func (q *Queries) UpdateTicketProjectGit(ctx context.Context, arg UpdateTicketProjectGitParams) (Ticket, error) { + row := q.db.QueryRow(ctx, updateTicketProjectGit, arg.ProjectGit, arg.UpdatedAt, arg.Channelid) + var i Ticket + err := row.Scan( + &i.ID, + &i.Key, + &i.Channelid, + &i.ProjectGit, + &i.BuildGit, + &i.Folder, + &i.CreatedAt, + &i.DeletedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/internal/storage/sqlc/queries.sql b/internal/storage/sqlc/queries.sql index 69c3280..d5320ee 100644 --- a/internal/storage/sqlc/queries.sql +++ b/internal/storage/sqlc/queries.sql @@ -21,6 +21,18 @@ SET folder = $1, updated_at = $2 WHERE channelID = $3 RETURNING *; +-- name: UpdateTicketProjectGit :one +UPDATE tickets +SET project_git = $1, updated_at = $2 +WHERE channelID = $3 +RETURNING *; + +-- name: UpdateTicketBuildGit :one +UPDATE tickets +SET build_git = $1, updated_at = $2 +WHERE channelID = $3 +RETURNING *; + -- name: ListTickets :many SELECT * FROM tickets WHERE deleted_at IS NULL;