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:
parent
a9ff088af9
commit
ec5d95586c
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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!",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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]
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
}
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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"`
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
package storage
|
|
||||||
|
|
||||||
import "ticket-pimp/internal/domain"
|
|
||||||
|
|
||||||
type TaskRepository interface {
|
|
||||||
GetOrCreate(tg string) *domain.TgUser
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue