- fix folder creation process;

This commit is contained in:
naudachu 2023-11-08 15:49:09 +05:00
parent 6752028e00
commit 6c07f434fc
15 changed files with 389 additions and 317 deletions

View File

@ -7,7 +7,6 @@ RUN apk add git
RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install -ldflags '-extldflags "-static"' -tags timetzdata ./cmd/main.go RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go install -ldflags '-extldflags "-static"' -tags timetzdata ./cmd/main.go
FROM scratch FROM scratch
# the test program:
COPY --from=app-builder /go/bin/main /ticket-pimp COPY --from=app-builder /go/bin/main /ticket-pimp
COPY --from=app-builder /go/src/ticket-pimp/cmd/prod.env / COPY --from=app-builder /go/src/ticket-pimp/cmd/prod.env /
# the tls certificates: # the tls certificates:

View File

@ -12,12 +12,12 @@ import (
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
) )
func initBotWith(token string) (*discordgo.Session, error) { func initBotWith(token string) *discordgo.Session {
discord, err := discordgo.New("Bot " + token) discord, err := discordgo.New("Bot " + token)
if err != nil { if err != nil {
return nil, err log.Fatalf("unable to create discord session: %v", err)
} }
return discord, nil return discord
} }
type DiscordOptions struct { type DiscordOptions struct {
@ -28,10 +28,7 @@ type DiscordOptions struct {
func Run(conf domain.Config, opts DiscordOptions) error { func Run(conf domain.Config, opts DiscordOptions) error {
token := conf.Discord.Token token := conf.Discord.Token
session, err := initBotWith(token) session := initBotWith(token)
if err != nil {
return err
}
router := handler.InitRouter(*opts.Controller) router := handler.InitRouter(*opts.Controller)
@ -41,7 +38,6 @@ func Run(conf domain.Config, opts DiscordOptions) error {
} }
session.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) { session.AddHandler(func(s *discordgo.Session, i *discordgo.InteractionCreate) {
if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok { if h, ok := commandHandlers[i.ApplicationCommandData().Name]; ok {
h(s, i) h(s, i)
} }
@ -73,7 +69,7 @@ func Run(conf domain.Config, opts DiscordOptions) error {
log.Println("Removing commands...") log.Println("Removing commands...")
for _, h := range cmds { for _, h := range cmds {
err = session.ApplicationCommandDelete(session.State.User.ID, "", h.ID) err := session.ApplicationCommandDelete(session.State.User.ID, "", h.ID)
if err != nil { if err != nil {
log.Panicf("Cannot delete '%v' command: %v", h.Name, err) log.Panicf("Cannot delete '%v' command: %v", h.Name, err)
} }

View File

@ -0,0 +1,100 @@
package handler
import (
"context"
"fmt"
"log"
"strconv"
"github.com/bwmarrin/discordgo"
)
func (h *router) CreateFolderHandler(nameMinLenght int) route {
const (
nameOption string = "folder_name"
)
return route{
Command: discordgo.ApplicationCommand{
Name: "folder",
Description: "Command for cloud folder creation",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: nameOption,
Description: "Type the folder's name",
Required: false,
MinLength: &nameMinLenght,
},
},
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
initialResponse := discordgo.InteractionResponse{
// Ignore type for now, they will be discussed in "responses"
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Flags: discordgo.MessageFlagsEphemeral,
Content: "..folder is going to be created",
Title: "📂 Folder creation",
},
}
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
}
var str string = ""
dchan, err := s.Channel(i.ChannelID)
if err != nil {
log.Printf("error while identifying channel: %v", err)
}
if dchan.ParentID == strconv.Itoa(1150719794853716028) {
log.Println("yes, channel is from `Projects`")
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 {
switch {
case project == nil:
if option, ok := optionMap[nameOption]; ok {
str = option.StringValue()
} else {
str = "Ты, либо в проекте директорию создавай, либо имя напиши, блет!"
}
default:
str = project.ShortName
}
resp := h.controller.ICloud.CreateFolder(str)
if resp.ErrMessage != nil {
result = fmt.Sprintf("Command executed w/ errors: ``` %v``` \n But check this link: %s\n", resp.ErrMessage, resp.Folder.PrivateURL)
} else {
result = fmt.Sprintf("📂 Folder was created: %s", resp.Folder.PrivateURL)
}
}
_, 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
}
}
},
}
}

View File

@ -0,0 +1,30 @@
package handler
import (
"log"
"github.com/bwmarrin/discordgo"
)
func (h *router) Ping() route {
return route{
Command: discordgo.ApplicationCommand{
Name: "ping",
Description: "pongs in a reply",
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
log.Println("ok, I'm here..")
err := s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: "`pong`",
Title: "Pong reply",
},
})
if err != nil {
log.Println(err)
}
},
}
}

View File

@ -0,0 +1,109 @@
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)
},
}
}

View File

@ -0,0 +1,78 @@
package handler
import (
"context"
"fmt"
"log"
"ticket-pimp/internal/domain"
"github.com/bwmarrin/discordgo"
)
func (h *router) CreateTicketHandler(repoNameMinLength int) route {
return route{
Command: discordgo.ApplicationCommand{
Name: "project",
Description: "Create new development ticket",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "project_name",
Description: "Temporary project name",
Required: true,
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
}
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)
} else {
edit := discordgo.ChannelEdit{
Name: p.ShortName,
ParentID: "1150719794853716028",
}
dchan, err = s.ChannelEdit(dchan.ID, &edit)
if err != nil {
result = fmt.Sprintf("channel created, but unable to edit: %v\n", err)
} else {
_, err = s.ChannelMessageSend(dchan.ID, "Hello!")
if err != nil {
log.Printf("message send problem: %v\n", err)
}
result = dchan.ID
}
}
}
}
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
// Ignore type for now, they will be discussed in "responses"
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: result,
},
})
},
}
}

View File

@ -1,11 +1,7 @@
package handler package handler
import ( import (
"context"
"fmt"
"log"
"ticket-pimp/internal/controller" "ticket-pimp/internal/controller"
"ticket-pimp/internal/domain"
"github.com/bwmarrin/discordgo" "github.com/bwmarrin/discordgo"
) )
@ -21,10 +17,10 @@ func InitRouter(wc controller.WorkflowController) *router {
var r router var r router
r.Routes = append( r.Routes = append(
r.Routes, r.Routes,
// r.CreateRepoHandler(3), r.CreateRepoHandler(3),
r.CreateFolderHandler(3), r.CreateFolderHandler(3),
r.Ping(), r.Ping(),
// r.CreateTicketHandler(3), r.CreateTicketHandler(3),
) )
r.controller = wc r.controller = wc
@ -35,284 +31,3 @@ type route struct {
Command discordgo.ApplicationCommand Command discordgo.ApplicationCommand
Handler func(s *discordgo.Session, i *discordgo.InteractionCreate) Handler func(s *discordgo.Session, i *discordgo.InteractionCreate)
} }
func (h *router) Ping() route {
return route{
Command: discordgo.ApplicationCommand{
Name: "ping",
Description: "pongs in a reply",
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
log.Println("ok, I'm here..")
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
Type: discordgo.InteractionResponseDeferredMessageUpdate,
Data: &discordgo.InteractionResponseData{
Content: "`pong`",
Title: "Pong reply",
},
})
},
}
}
func (h *router) CreateFolderHandler(nameMinLenght int) route {
const (
nameOption string = "folder_name"
)
return route{
Command: discordgo.ApplicationCommand{
Name: "folder",
Description: "Command for cloud folder creation",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: nameOption,
Description: "Type the folder's name",
Required: false,
MinLength: &nameMinLenght,
},
},
},
Handler: func(s *discordgo.Session, i *discordgo.InteractionCreate) {
var result string
resp := discordgo.InteractionResponse{
Type: discordgo.InteractionResponseUpdateMessage,
Data: &discordgo.InteractionResponseData{
Content: "Folder is going to be created..",
},
}
err := s.InteractionRespond(i.Interaction, &resp)
if err != nil {
log.Println(err)
return
}
options := i.ApplicationCommandData().Options
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 {
if project == nil {
if option, ok := optionMap[nameOption]; ok {
str = option.StringValue()
} else {
str = ""
}
} else {
str = project.ShortName
}
if str == "" {
result = "Ты, либо в проекте директорию создавай, либо имя напиши, блет!"
} else {
f, err := h.controller.ICloud.CreateFolder(str)
if err != nil {
result = fmt.Sprintf("error while cloud folder creation: %v", err)
} else {
result = fmt.Sprint(f.PrivateURL)
}
}
}
// resp = discordgo.InteractionResponse{
// // Ignore type for now, they will be discussed in "responses"
// Type: discordgo.InteractionResponseUpdateMessage,
// Data: &discordgo.InteractionResponseData{
// Content: result,
// Title: "📂 Folder was created",
// },
// }
webhookEdit := discordgo.WebhookEdit{
Content: &result,
}
s.InteractionResponseEdit(i.Interaction, &webhookEdit)
// discerr := s.InteractionRespond(i.Interaction, &resp)
// if discerr != nil {
// log.Println(discerr)
// }
},
}
}
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)
},
}
}
func (h *router) CreateTicketHandler(repoNameMinLength int) route {
return route{
Command: discordgo.ApplicationCommand{
Name: "project",
Description: "Create new development ticket",
Options: []*discordgo.ApplicationCommandOption{
{
Type: discordgo.ApplicationCommandOptionString,
Name: "project_name",
Description: "Temporary project name",
Required: true,
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
}
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)
} else {
edit := discordgo.ChannelEdit{
Name: p.ShortName,
ParentID: "1150719794853716028",
}
dchan, err = s.ChannelEdit(dchan.ID, &edit)
if err != nil {
result = fmt.Sprintf("channel created, but unable to edit: %v\n", err)
} else {
_, err = s.ChannelMessageSend(dchan.ID, "Hello!")
if err != nil {
log.Printf("message send problem: %v\n", err)
}
result = dchan.ID
}
}
}
}
s.InteractionRespond(i.Interaction, &discordgo.InteractionResponse{
// Ignore type for now, they will be discussed in "responses"
Type: discordgo.InteractionResponseChannelMessageWithSource,
Data: &discordgo.InteractionResponseData{
Content: result,
},
})
},
}
}

View File

@ -61,7 +61,8 @@ func (wc *WorkflowController) FullProjectInit(name, key, id string) (string, err
go func(ref **domain.Folder) { go func(ref **domain.Folder) {
defer wg.Done() defer wg.Done()
*ref, _ = wc.ICloud.CreateFolder(appKey)
*ref = wc.ICloud.CreateFolder(appKey).Folder
}(&cloud) }(&cloud)
wg.Wait() wg.Wait()

View File

@ -0,0 +1,5 @@
package helpers
type ErrorMessage struct {
Message string `json:"message"`
}

View File

@ -7,7 +7,7 @@ import (
"strings" "strings"
) )
func GitNaming(input string) string { func ValidNaming(input string) string {
// Remove leading and trailing whitespace // Remove leading and trailing whitespace
input = strings.TrimSpace(input) input = strings.TrimSpace(input)

View File

@ -18,7 +18,7 @@ var tests = []test{
func TestGitNaming(t *testing.T) { func TestGitNaming(t *testing.T) {
for _, test := range tests { for _, test := range tests {
if output := GitNaming(test.arg); output != test.expected { if output := ValidNaming(test.arg); output != test.expected {
t.Errorf("Output %q not equal to expected %q", output, test.expected) t.Errorf("Output %q not equal to expected %q", output, test.expected)
} }
} }

View File

@ -2,7 +2,9 @@ package services
import ( import (
"fmt" "fmt"
"log"
"strconv" "strconv"
"strings"
"ticket-pimp/internal/domain" "ticket-pimp/internal/domain"
"ticket-pimp/internal/helpers" "ticket-pimp/internal/helpers"
"time" "time"
@ -14,7 +16,7 @@ type Cloud struct {
} }
type ICloud interface { type ICloud interface {
CreateFolder(name string) (*domain.Folder, error) CreateFolder(name string) Response
} }
func NewCloud(conf domain.CloudConfig) *Cloud { func NewCloud(conf domain.CloudConfig) *Cloud {
@ -32,40 +34,76 @@ func NewCloud(conf domain.CloudConfig) *Cloud {
} }
} }
func (c *Cloud) CreateFolder(name string) (*domain.Folder, error) { type Response struct {
Folder *domain.Folder
ErrMessage error
}
func (c *Cloud) CreateFolder(name string) Response {
var R Response
rootDir := c.Config.RootDir rootDir := c.Config.RootDir
user := c.Config.User user := c.Config.User
davPath := "/remote.php/dav/files/" davPath := "/remote.php/dav/files/"
parentPath := "/apps/files/?dir=" parentPath := "/apps/files/?dir="
name = helpers.GitNaming(name) name = helpers.ValidNaming(name)
cloud := domain.Folder{ R.Folder = &domain.Folder{
Title: name, Title: name,
PrivateURL: "", PrivateURL: "",
} }
// cloud := domain.Folder{
// Title: name,
// PrivateURL: "",
// }
requestPath := davPath + user + rootDir + name requestPath := davPath + user + rootDir + name
cloud.PathTo = parentPath + rootDir + name R.Folder.PathTo = parentPath + rootDir + name
resp, _ := c.R(). var errMessage helpers.ErrorMessage
resp, err := c.R().
SetErrorResult(&errMessage).
Send("MKCOL", requestPath) Send("MKCOL", requestPath)
if err != nil { // Error handling.
log.Println("error:", err)
// Херовая обработка ошибки:
// error while cloud folder creation: bad response, raw content:
// <?xml version="1.0" encoding="utf-8"?>
// <d:error xmlns:d="DAV:" xmlns:s="http://sabredav.org/ns">
// <s:exception>Sabre\DAV\Exception\MethodNotAllowed</s:exception>
// <s:message>The resource you tried to create already exists</s:message>
// </d:error>
if strings.Contains(err.Error(), "already exists") {
R.Folder.PrivateURL = c.BaseURL + R.Folder.PathTo
R.ErrMessage = err
// Try to set short URL to the d entity
if err := c.setPrivateURL(requestPath, R.Folder); err != nil {
R.ErrMessage = err
return R
}
return R
}
return R
}
if resp.IsSuccessState() { if resp.IsSuccessState() {
// Set stupid URL to the d entity // Set stupid URL to the d entity
cloud.PrivateURL = c.BaseURL + cloud.PathTo R.Folder.PrivateURL = c.BaseURL + R.Folder.PathTo
// Try to set short URL to the d entity // Try to set short URL to the d entity
if err := c.setPrivateURL(requestPath, &cloud); err != nil { if err := c.setPrivateURL(requestPath, R.Folder); err != nil {
return &cloud, err return R
} }
} else {
fmt.Println(resp.Status)
} }
return &cloud, nil return R
} }
func (c *Cloud) setPrivateURL(requestPath string, cloud *domain.Folder) error { func (c *Cloud) setPrivateURL(requestPath string, cloud *domain.Folder) error {

View File

@ -55,7 +55,7 @@ type gitCreateRequest struct {
} }
func (gb *Git) newRepo(name string) (*domain.Git, error) { func (gb *Git) newRepo(name string) (*domain.Git, error) {
name = helpers.GitNaming(name) name = helpers.ValidNaming(name)
payload := gitCreateRequest{ payload := gitCreateRequest{
Name: name, Name: name,

View File

@ -17,10 +17,10 @@ func (h *Handler) NewFolderHandler(ctx context.Context, mu *tgb.MessageUpdate) e
return errors.New("empty command provided") return errors.New("empty command provided")
} }
cloud, err := h.cloud.CreateFolder(str) resp := h.cloud.CreateFolder(str)
if err != nil { if resp.ErrMessage != nil {
answer := errorAnswer(err.Error()) answer := errorAnswer(resp.ErrMessage.Error())
h.LogMessage(ctx, mu, answer) h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx) return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx)
} }
@ -28,7 +28,7 @@ func (h *Handler) NewFolderHandler(ctx context.Context, mu *tgb.MessageUpdate) e
answer := tg.HTML.Text( answer := tg.HTML.Text(
tg.HTML.Line( tg.HTML.Line(
"✨ Shiny folder", "✨ Shiny folder",
tg.HTML.Link(cloud.Title, cloud.PrivateURL), tg.HTML.Link(resp.Folder.Title, resp.Folder.PrivateURL),
"has been created!", "has been created!",
), ),
) )

View File

@ -45,6 +45,7 @@ func Run(ctx context.Context, opts TelegramOptions) error {
// Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")). // Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")).
Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task")) Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task"))
log.Print("Success init. Start poller.")
return tgb.NewPoller( return tgb.NewPoller(
router, router,
client, client,