Huge refactoring:

- removed deprecated methods from controller;
- moved handlers to a separate files;
- create initiation handler;
- moved farmer tasks to coda!
This commit is contained in:
Volkomurov 2023-09-06 14:52:31 +05:00
parent a9ff088af9
commit ec5d95586c
12 changed files with 406 additions and 327 deletions

View File

@ -1,15 +1,11 @@
package controller package controller
import ( import (
"encoding/csv"
"fmt" "fmt"
"io"
"strings" "strings"
"sync" "sync"
"ticket-pimp/internal/domain" "ticket-pimp/internal/domain"
"ticket-pimp/internal/services" "ticket-pimp/internal/services"
"github.com/imroc/req/v3"
) )
type WorkflowController struct { type WorkflowController struct {
@ -38,96 +34,6 @@ func NewWorkflowController(
type IWorkflowController interface { type IWorkflowController interface {
Workflow(name string) (string, error) Workflow(name string) (string, error)
NewTask(summ, desc, c, cLink string) *Task
CreateTask(t *Task) (*Task, error)
ThrowConversions(f io.ReadCloser, appID string, token string) *domain.ConversionLog
}
func (wc *WorkflowController) ThrowConversions(f io.ReadCloser, appID string, token string) *domain.ConversionLog {
c := req.C().
SetBaseURL("https://graph.facebook.com/v15.0/").
DevMode()
const currency = "USD"
r := csv.NewReader(f)
conversionLog := domain.ConversionLog{}
for {
record, err := r.Read()
if err == io.EOF {
break
}
if err != nil {
return nil
}
advertiser := strings.Split(record[0], ";")[0]
params := map[string]string{
"advertiser_id": advertiser,
"event": "CUSTOM_APP_EVENTS",
"application_tracking_enabled": "1",
"advertiser_tracking_enabled": "1",
"custom_events": `[{"_eventName":"fb_mobile_purchase"}]`,
}
res, _ := c.R().
SetQueryString(token).
SetQueryParams(params).
Post(appID + "/activities")
if res.Err != nil {
conversionLog.Advertiser = append(conversionLog.Advertiser, advertiser)
}
}
return &conversionLog
}
type Task struct {
Summary string
Description string
Creator string
CreatorLink string
Key string
URL string
}
func (wc *WorkflowController) NewTask(summ, desc, c, cLink string) *Task {
return &Task{
Summary: summ,
Description: desc,
Creator: c,
CreatorLink: cLink,
}
}
func (wc *WorkflowController) CreateTask(t *Task) (*Task, error) {
yt := wc.additionalYT
projectID, err := yt.GetProjectIDByName("E")
if err != nil {
return nil, err
}
t.Description += fmt.Sprintf("\n\n Created by: [%s](%s)", t.Creator, t.CreatorLink)
issue, err := yt.CreateIssue(projectID, t.Creator+" | "+t.Summary, t.Description)
if err != nil {
return nil, err
}
t.Key = issue.Key
t.URL = fmt.Sprintf("https://mobmarlerino.youtrack.cloud/issue/%s", issue.Key)
return t, nil
} }
func (wc *WorkflowController) Workflow(name string) (string, error) { func (wc *WorkflowController) Workflow(name string) (string, error) {
@ -192,7 +98,7 @@ func (wc *WorkflowController) Workflow(name string) (string, error) {
cloudResult = cloud.PrivateURL cloudResult = cloud.PrivateURL
} }
wc.iCoda.CreateApp(domain.CodaIssue{ wc.iCoda.CreateApp(domain.CodaApplication{
ID: issue.Key, ID: issue.Key,
Summary: strings.TrimSpace(name), Summary: strings.TrimSpace(name),
Git: gitResult, Git: gitResult,

View File

@ -0,0 +1,42 @@
package handler
import (
"context"
"errors"
"fmt"
"strings"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
)
func (h *Handler) DevelopmentTaskHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/new", "", 1)
if str == "" {
return errors.New("empty command provided")
}
issueKeyStr, err := h.workflow.Workflow(str)
if err != nil {
answer := errorAnswer(err.Error())
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx)
}
answer := newTicketAnswer(issueKeyStr)
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx)
}
func newTicketAnswer(name string) string {
return tg.HTML.Text(
tg.HTML.Line(
"🤘 Ticket ",
tg.HTML.Link(name, fmt.Sprintf("https://marlerino.youtrack.cloud/issue/%s", name)),
"has been created!",
),
)
}

71
bot/handler/farmtask.go Normal file
View File

@ -0,0 +1,71 @@
package handler
import (
"context"
"fmt"
"log"
"strings"
"ticket-pimp/internal/domain"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
)
func (h *Handler) FarmTaskHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
msgID := mu.Message.ID
taskText := strings.TrimSpace(strings.Replace(mu.Text, "/task", "", 1))
var summaryTail string
sentances := strings.Split(taskText, "\n")
if len(sentances) < 2 {
words := strings.Split(taskText, " ")
if len(words) > 2 {
summaryTail = strings.Join(words[0:2], " ")
} else {
summaryTail = strings.Join(words, " ")
}
} else {
summaryTail = sentances[0]
}
t := domain.NewTask(
summaryTail,
taskText,
mu.From.Username.PeerID(),
mu.Chat.ID.PeerID(),
)
id, err := h.coda.CreateTask(t.Summary, t.Description, t.Creator, t.CreatorLink)
if err != nil {
answer := errorAnswer(err.Error())
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx)
}
if id == "" {
answer := errorAnswer("task wasn't created")
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx)
}
err = mu.Answer(fmt.Sprintf("Задача с id: %s была создана, жду ссылку", id)).DoVoid(ctx)
if err != nil {
log.Println("бот не смог ответить про создание задачи")
}
url, err := h.coda.GetRowLink(id)
if err != nil {
answer := err.Error()
h.LogMessage(ctx, mu, answer)
return err
}
t.URL = url
answer := tg.HTML.Text(
tg.HTML.Line(tg.HTML.Link("🤘 Задача", t.URL), "была создана!"))
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).
ReplyToMessageID(msgID).ParseMode(tg.HTML).DisableWebPagePreview(true).DoVoid(ctx)
}

48
bot/handler/folder.go Normal file
View File

@ -0,0 +1,48 @@
package handler
import (
"context"
"errors"
"strings"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
)
func (h *Handler) NewFolderHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/folder", "", 1)
if str == "" {
return errors.New("empty command provided")
}
cloud, err := h.cloud.CreateFolder(str)
if err != nil {
answer := errorAnswer(err.Error())
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).ParseMode(tg.HTML).DoVoid(ctx)
}
answer := tg.HTML.Text(
tg.HTML.Line(
"✨ Shiny folder",
tg.HTML.Link(cloud.Title, cloud.PrivateURL),
"has been created!",
),
)
h.LogMessage(ctx, mu, answer)
return mu.Answer(answer).
ParseMode(tg.HTML).
DoVoid(ctx)
}
func errorAnswer(errorMsg string) string {
return tg.HTML.Text(
tg.HTML.Line(
tg.HTML.Italic(errorMsg),
),
)
}

62
bot/handler/git.go Normal file
View File

@ -0,0 +1,62 @@
package handler
import (
"context"
"errors"
"fmt"
"strings"
"ticket-pimp/internal/domain"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
)
type git struct {
name string
url string
git string
ssh string
}
func newGit(domain *domain.Git) *git {
return &git{
name: domain.Name,
url: domain.HtmlUrl,
git: domain.CloneUrl,
ssh: fmt.Sprintf("ssh://%s/%s.git", domain.SshUrl, domain.FullName),
}
}
// FYI: Telegram doesn't renders this hyperlink, if the url is localhost 🤷‍♂️
func (g *git) PrepareAnswer() string {
return tg.HTML.Text(
tg.HTML.Line(
"Repo ",
tg.HTML.Link(g.name, g.url),
"has been created!",
),
)
}
func (h *Handler) NewRepoHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/repo", "", 1)
if str == "" {
return errors.New("empty command provided")
}
var g *domain.Git
g, err := h.git.CreateRepo(str)
if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
}
resp := newGit(g).PrepareAnswer()
h.LogMessage(ctx, mu, resp)
return mu.Answer(resp).ParseMode(tg.HTML).DoVoid(ctx)
}

View File

@ -1,23 +1,15 @@
package handler package handler
import ( import (
"context"
"errors"
"fmt"
"log"
"strings"
"ticket-pimp/bot/controller" "ticket-pimp/bot/controller"
"ticket-pimp/internal/domain"
"ticket-pimp/internal/services" "ticket-pimp/internal/services"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
) )
type Handler struct { type Handler struct {
workflow controller.IWorkflowController workflow controller.IWorkflowController
git services.IGit git services.IGit
cloud services.ICloud cloud services.ICloud
coda services.ICoda
} }
func NewHandler( func NewHandler(
@ -32,202 +24,6 @@ func NewHandler(
workflow: controller.NewWorkflowController(git, cloud, devyt, farmyt, coda), workflow: controller.NewWorkflowController(git, cloud, devyt, farmyt, coda),
git: git, git: git,
cloud: cloud, cloud: cloud,
coda: coda,
} }
} }
func (h *Handler) PingHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
return mu.Answer("pong").DoVoid(ctx)
}
type git struct {
name string
url string
git string
ssh string
}
func newGit(domain *domain.Git) *git {
return &git{
name: domain.Name,
url: domain.HtmlUrl,
git: domain.CloneUrl,
ssh: fmt.Sprintf("ssh://%s/%s.git", domain.SshUrl, domain.FullName),
}
}
// FYI: Telegram doesn't renders this hyperlink, if the url is localhost 🤷‍♂️
func (g *git) PrepareAnswer() string {
return tg.HTML.Text(
tg.HTML.Line(
"Repo ",
tg.HTML.Link(g.name, g.url),
"has been created!",
),
)
}
func (h *Handler) NewRepoHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/repo", "", 1)
if str == "" {
return errors.New("empty command provided")
}
var g *domain.Git
g, err := h.git.CreateRepo(str)
if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
}
resp := newGit(g).PrepareAnswer()
return mu.Answer(resp).ParseMode(tg.HTML).DoVoid(ctx)
}
func (h *Handler) NewFolderHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/folder", "", 1)
if str == "" {
return errors.New("empty command provided")
}
cloud, err := h.cloud.CreateFolder(str)
if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
}
answer := tg.HTML.Text(
tg.HTML.Line(
"✨ Shiny folder",
tg.HTML.Link(cloud.Title, cloud.PrivateURL),
"has been created!",
),
)
return mu.Answer(answer).
ParseMode(tg.HTML).
DoVoid(ctx)
}
func errorAnswer(errorMsg string) string {
return tg.HTML.Text(
tg.HTML.Line(
tg.HTML.Italic(errorMsg),
),
)
}
func (h *Handler) DevelopmentTaskHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/new", "", 1)
if str == "" {
return errors.New("empty command provided")
}
issueKeyStr, err := h.workflow.Workflow(str)
if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
}
return mu.Answer(newTicketAnswer(issueKeyStr)).ParseMode(tg.HTML).DoVoid(ctx)
}
func newTicketAnswer(name string) string {
return tg.HTML.Text(
tg.HTML.Line(
"🤘 Ticket ",
tg.HTML.Link(name, fmt.Sprintf("https://marlerino.youtrack.cloud/issue/%s", name)),
"has been created!",
),
)
}
func (h *Handler) FarmTaskHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
taskText := strings.TrimSpace(strings.Replace(mu.Text, "/task", "", 1))
words := strings.Split(taskText, " ")
var summaryTail string
if len(words) > 3 {
summaryTail = strings.Join(words[0:3], " ")
} else {
summaryTail = strings.Join(words, " ")
}
task := h.workflow.NewTask(
summaryTail,
taskText,
mu.From.Username.PeerID(),
mu.From.Username.Link(),
)
createdTicket, err := h.workflow.CreateTask(task)
if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
}
return mu.Answer(tg.HTML.Text(
tg.HTML.Line(
"🤘 Задача",
tg.HTML.Link(createdTicket.Key, createdTicket.URL),
"была создана!",
),
)).ParseMode(tg.HTML).DoVoid(ctx)
}
func (h *Handler) NewConversion(ctx context.Context, mu *tgb.MessageUpdate) error {
msg := strings.TrimSpace(strings.Replace(mu.Caption, "/conversion", "", 1))
appID, token := normalizeToken(msg)
fid := mu.Update.Message.Document.FileID
client := mu.Client
file, err := client.GetFile(fid).Do(ctx)
if err != nil {
return err
}
f, err := client.Download(ctx, file.FilePath)
if err != nil {
return err
}
defer f.Close()
l := h.workflow.ThrowConversions(f, appID, token)
if len(l.Advertiser) != 0 {
return mu.Answer(tg.HTML.Text(
"Неуспешные запросы:",
tg.HTML.Code(strings.Join(l.Advertiser, ", ")),
)).ParseMode(tg.HTML).DoVoid(ctx)
}
return mu.Answer(tg.HTML.Text(
"Конверсии отправлены",
)).ParseMode(tg.HTML).DoVoid(ctx)
}
func normalizeToken(msg string) (string, string) {
msg = strings.TrimSpace(msg)
args := strings.Split(msg, "|")
if len(args) != 2 {
log.Print(len(args))
return "", ""
}
return args[0], args[0] + "|" + args[1]
}

45
bot/handler/init.go Normal file
View File

@ -0,0 +1,45 @@
package handler
import (
"context"
"fmt"
"log"
"os"
"strconv"
"github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb"
)
func (h *Handler) LogMessage(ctx context.Context, mu *tgb.MessageUpdate, msg string) error {
env := os.Getenv("TGSPAM")
id, err := strconv.ParseInt(env, 10, 64)
if err == nil {
log.Println("fatal while parsing chatID")
}
msg += " <i>from:</i>" + string(mu.From.Username)
return mu.Client.SendMessage(tg.ChatID(id), msg).ParseMode(tg.HTML).DoVoid(ctx)
}
func (h *Handler) Init(ctx context.Context, mu *tgb.MessageUpdate) error {
msgID := mu.Message.ID
peer := mu.Chat.ID.PeerID()
if mu.From.ID == 2532580 {
os.Setenv("TGSPAM", peer)
answer := fmt.Sprintf("<i>this chat (%s) is now a logger chat</i>", peer)
return mu.Answer(answer).ReplyToMessageID(msgID).ParseMode(tg.HTML).DoVoid(ctx)
}
answer := "я тебя не знаю, уходи"
return mu.Answer(answer).ReplyToMessageID(msgID).ParseMode(tg.HTML).DoVoid(ctx)
}
func (h *Handler) PingHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
h.LogMessage(ctx, mu, "pong")
return mu.Answer("pong").DoVoid(ctx)
}

View File

@ -17,7 +17,7 @@ import (
func main() { func main() {
log.Print("started") log.Print("started")
env("dev.env") env("develop.env")
ctx := context.Background() ctx := context.Background()
ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, os.Kill, syscall.SIGTERM) ctx, cancel := signal.NotifyContext(ctx, os.Interrupt, os.Kill, syscall.SIGTERM)
@ -80,12 +80,12 @@ func runBot(ctx context.Context) error {
) )
router := tgb.NewRouter(). router := tgb.NewRouter().
Message(h.DevelopmentTaskHandler, tgb.TextHasPrefix("/new")). Message(h.Init, tgb.Command("init")).
Message(h.PingHandler, tgb.Command("ping")). Message(h.PingHandler, tgb.Command("ping")).
Message(h.DevelopmentTaskHandler, tgb.TextHasPrefix("/new")).
Message(h.NewRepoHandler, tgb.TextHasPrefix("/repo")). Message(h.NewRepoHandler, tgb.TextHasPrefix("/repo")).
Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")). Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder")).
Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task")). Message(h.FarmTaskHandler, tgb.TextHasPrefix("/task"))
Message(h.NewConversion, tgb.TextHasPrefix("/conversion"))
return tgb.NewPoller( return tgb.NewPoller(
router, router,

View File

@ -8,7 +8,7 @@ type Folder struct {
PrivateURL string // http://domain/apps/files/?dir=/temp/k OR http://domain/f/3333 PrivateURL string // http://domain/apps/files/?dir=/temp/k OR http://domain/f/3333
} }
type CodaIssue struct { type CodaApplication struct {
ID string `json:"id"` ID string `json:"id"`
Summary string `json:"summary"` Summary string `json:"summary"`
URL string `json:"url"` URL string `json:"url"`
@ -17,6 +17,57 @@ type CodaIssue struct {
Folder string `json:"folder"` Folder string `json:"folder"`
} }
type Insert struct {
Rows []Row `json:"rows"`
}
func NewTaskRequest() *Insert {
return &Insert{}
}
type Row struct {
Cells []Cell `json:"cells"`
}
func (req *Insert) NewRow() *Row {
row := Row{}
i := len(req.Rows)
req.Rows = append(req.Rows, row)
return &req.Rows[i]
}
type Cell struct {
Column string `json:"column"`
Value string `json:"value"`
}
func (r *Row) NewCell(col string, value string) *Row {
cell := Cell{
Column: col,
Value: value,
}
r.Cells = append(r.Cells, cell)
return r
}
type Task struct {
Summary string
Description string
Creator string
CreatorLink string
URL string
}
func NewTask(summ, desc, c, cLink string) *Task {
return &Task{
Summary: summ,
Description: desc,
Creator: c,
CreatorLink: cLink,
}
}
type ConversionLog struct { type ConversionLog struct {
Advertiser []string Advertiser []string
} }
@ -31,11 +82,6 @@ type Git struct {
SshUrl string `json:"ssh_url"` // ?! SshUrl string `json:"ssh_url"` // ?!
} }
type Task struct {
Description string
URL string
}
type Project struct { type Project struct {
ID string `json:"id"` ID string `json:"id"`
ShortName string `json:"shortName"` ShortName string `json:"shortName"`

View File

@ -14,14 +14,20 @@ func NewClient() *CommonClient {
return &CommonClient{req.C(). return &CommonClient{req.C().
OnAfterResponse(func(client *req.Client, resp *req.Response) error { OnAfterResponse(func(client *req.Client, resp *req.Response) error {
if resp.Err != nil { if resp.Err != nil {
if dump := resp.Dump(); dump != "" { if resp.String() != "" {
resp.Err = fmt.Errorf("%s\nraw content:\n%s", resp.Err.Error(), resp.Dump()) resp.Err = fmt.Errorf("%s\nraw content:\n%s", resp.Err.Error(), resp.String())
} else {
resp.Err = fmt.Errorf("bad request")
} }
return nil // Skip the following logic if there is an underlying error. return nil
} }
if !resp.IsSuccessState() { if !resp.IsSuccessState() {
resp.Err = fmt.Errorf("bad response, raw content:\n%s", resp.Dump()) if resp.String() != "" {
resp.Err = fmt.Errorf("bad response, raw content:\n%s", resp.String())
} else {
resp.Err = fmt.Errorf("bad response")
}
return nil return nil
} }
return nil return nil

View File

@ -5,6 +5,8 @@ import (
"log" "log"
"ticket-pimp/internal/domain" "ticket-pimp/internal/domain"
"time" "time"
"github.com/imroc/req/v3"
) )
type Coda struct { type Coda struct {
@ -13,13 +15,15 @@ type Coda struct {
type ICoda interface { type ICoda interface {
ListDocs() ListDocs()
CreateApp(task domain.CodaIssue) CreateApp(task domain.CodaApplication)
CreateTask(title string, desc string, creatorName string, creatorID string) (string, error)
GetRowLink(id string) (string, error)
} }
func NewCodaClient(token string) *Coda { func NewCodaClient(token string) *Coda {
client := NewClient(). client := NewClient().
SetTimeout(5 * time.Second). SetTimeout(15 * time.Second).
SetCommonBearerAuthToken(token). SetCommonBearerAuthToken(token).
SetBaseURL("https://coda.io/apis/v1") SetBaseURL("https://coda.io/apis/v1")
@ -35,8 +39,6 @@ func (c *Coda) ListDocs() {
const tableID = "grid-obBN3tWdeh" const tableID = "grid-obBN3tWdeh"
const docID = "Ic3IZpQ3Wk" const docID = "Ic3IZpQ3Wk"
//var i []RespObj
resp, _ := c.R(). resp, _ := c.R().
SetQueryParam("tableTypes", "table"). SetQueryParam("tableTypes", "table").
//SetSuccessResult(&i). //SetSuccessResult(&i).
@ -50,7 +52,7 @@ func (c *Coda) ListDocs() {
log.Print(resp) log.Print(resp)
} }
func (c *Coda) CreateApp(task domain.CodaIssue) { func (c *Coda) CreateApp(task domain.CodaApplication) {
resp, _ := c.R(). resp, _ := c.R().
SetBody(task). SetBody(task).
SetContentType("application/json"). SetContentType("application/json").
@ -58,3 +60,65 @@ func (c *Coda) CreateApp(task domain.CodaIssue) {
fmt.Print(resp) fmt.Print(resp)
} }
func (c *Coda) CreateTask(title string, desc string, creatorName string, creatorID string) (string, error) {
const (
docID = "vceN8BewiU"
tableID = "grid-GPdeq96hUq"
)
request := domain.NewTaskRequest()
request.
NewRow().
NewCell("c-rvWipOfkxr", title).
NewCell("c-fLsUoIqQG9", creatorName).
NewCell("c-psmWFHIoKl", creatorID).
NewCell("c-ASsOsB1hzH", desc)
type TaskURL struct {
ID []string `json:"addedRowIds"`
}
tasks := TaskURL{}
_, err := c.R().
SetContentType("application/json").
SetQueryParam("disableParsing", "true").
SetBodyJsonMarshal(&request).
SetSuccessResult(&tasks).
Post("/docs/" + docID + "/tables/" + tableID + "/rows")
if err != nil {
return "", err
}
return tasks.ID[0], nil
}
func (c *Coda) GetRowLink(id string) (string, error) {
const (
docID = "vceN8BewiU"
tableID = "grid-GPdeq96hUq"
)
type RowResponse struct {
Link string `json:"browserLink"`
}
rowResponse := RowResponse{}
resp, err := c.R().
SetRetryCount(20).
SetRetryBackoffInterval(1*time.Second, 5*time.Second).
SetSuccessResult(&rowResponse).
AddRetryHook(func(resp *req.Response, err error) {
req := resp.Request.RawRequest
fmt.Println("Retry request:", req.Method, req.URL)
fmt.Println("Retry to retrieve row")
}).
AddRetryCondition(func(resp *req.Response, err error) bool {
log.Println(resp.String())
return err != nil || resp.StatusCode == 404
}).
Get("/docs/" + docID + "/tables/" + tableID + "/rows/" + id)
if err != nil {
return "", err
}
_ = resp
return rowResponse.Link, nil
}

View File

@ -1,7 +0,0 @@
package storage
import "ticket-pimp/internal/domain"
type TaskRepository interface {
GetOrCreate(tg string) *domain.TgUser
}