Merge pull request #3 from naudachu/refactoring

Refactoring
This commit is contained in:
naudachu 2023-06-25 19:28:20 +05:00 committed by GitHub
commit 45beec029e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 418 additions and 173 deletions

View File

@ -16,7 +16,7 @@ import (
func main() { func main() {
log.Print("started") log.Print("started")
env(".env") env(".dev.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)
@ -36,12 +36,24 @@ func env(envFilePath string) {
} }
func run(ctx context.Context) error { func run(ctx context.Context) error {
client := tg.New(os.Getenv("TG_API")) client := tg.New(os.Getenv("TG_API"))
h := handler.NewHandler(
os.Getenv("GIT_BASE_URL"),
os.Getenv("GIT_TOKEN"),
os.Getenv("CLOUD_BASE_URL"),
os.Getenv("CLOUD_USER"),
os.Getenv("CLOUD_PASS"),
os.Getenv("YT_URL"),
os.Getenv("YT_TOKEN"),
)
router := tgb.NewRouter(). router := tgb.NewRouter().
Message(handler.NewTicketHandler, tgb.TextHasPrefix("/new")). Message(h.NewTicketHandler, tgb.TextHasPrefix("/new")).
Message(handler.PingHandler, tgb.Command("ping")). Message(h.PingHandler, tgb.Command("ping")).
Message(handler.NewRepoHandler, tgb.TextHasPrefix("/repo")) Message(h.NewRepoHandler, tgb.TextHasPrefix("/repo")).
Message(h.NewFolderHandler, tgb.TextHasPrefix("/folder"))
return tgb.NewPoller( return tgb.NewPoller(
router, router,

View File

@ -2,13 +2,41 @@ package controller
import ( import (
"fmt" "fmt"
"os"
"sync" "sync"
d "ticket-pimp/domain"
"ticket-pimp/ext" "ticket-pimp/ext"
) )
func Workflow(name string) (string, error) { type WorkflowController struct {
yt := ext.NewYT(os.Getenv("YT_URL"), os.Getenv("YT_TOKEN")) iGit ext.IGit
iCloud ext.ICloud
iYouTrack ext.IYouTrack
}
func NewWorkflowController(
gitBaseURL,
gitToken,
cloudBaseURL,
cloudAuthUser,
cloudAuthPass,
ytBaseURL,
ytToken string,
) *WorkflowController {
return &WorkflowController{
iGit: ext.NewGit(gitBaseURL, gitToken),
iCloud: ext.NewCloud(cloudBaseURL, cloudAuthUser, cloudAuthPass),
iYouTrack: ext.NewYT(ytBaseURL, ytToken),
}
}
type IWorkflowController interface {
Workflow(name string) (string, error)
CreateRepo(name string) (*d.Git, error)
CreateFolder(name string) (*d.Folder, error)
}
func (wc *WorkflowController) Workflow(name string) (string, error) {
yt := wc.iYouTrack
projects, err := yt.GetProjects() projects, err := yt.GetProjects()
@ -16,7 +44,7 @@ func Workflow(name string) (string, error) {
return "", err return "", err
} }
issue, err := yt.CreateIssue(projects[0].ID, name) issue, err := yt.CreateIssue(projects[1].ID, name)
if err != nil { if err != nil {
return "", err return "", err
@ -24,60 +52,66 @@ func Workflow(name string) (string, error) {
if issue != nil { if issue != nil {
var ( var (
git, gitBuild, folder string git, gitBuild *d.Git
cloud *d.Folder
) )
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(3) wg.Add(3)
go func() { go func(ref **d.Git) {
defer wg.Done() defer wg.Done()
git, _ = CreateRepo(issue.Key, 0) *ref, _ = wc.CreateRepo(issue.Key)
}() }(&git)
go func() { go func(ref **d.Git) {
defer wg.Done() defer wg.Done()
gitBuild, _ = CreateRepo(issue.Key+"-build", 1) *ref, _ = wc.CreateRepo(issue.Key + "-build")
}() }(&gitBuild)
go func() { go func(ref **d.Folder) {
defer wg.Done() defer wg.Done()
folder = CreateFolder(issue.Key + " - " + issue.Summary) *ref, _ = wc.CreateFolder(issue.Key + " - " + issue.Summary)
}() }(&cloud)
wg.Wait() wg.Wait()
yt.UpdateIssue(issue, folder, git, gitBuild) yt.UpdateIssue(
issue,
cloud.PrivateURL,
git.HtmlUrl,
fmt.Sprintf("ssh://%s/%s.git", gitBuild.SshUrl, gitBuild.FullName))
} }
return issue.Key, nil return issue.Key, nil
} }
func CreateRepo(name string, param uint) (string, error) { func (wc *WorkflowController) CreateRepo(name string) (*d.Git, error) {
gb := ext.NewGit(os.Getenv("GIT_BASE_URL"), os.Getenv("GIT_TOKEN")) //Create git repository with iGit interface;
repo, err := gb.NewRepo(name) repo, err := wc.iGit.NewRepo(name)
gb.AppsAsCollaboratorTo(repo) if err != nil {
return nil, err
// Result string formatting:
if repo != nil {
switch param {
case 0:
return repo.HtmlUrl, err
case 1:
return fmt.Sprintf("ssh://%s/%s.git", repo.SshUrl, repo.FullName), err
default:
return repo.CloneUrl, err
}
} }
return "", err //Set 'apps' as collaborator to created repository;
_, err = wc.iGit.AppsAsCollaboratorTo(repo)
if err != nil {
return nil, err
} }
func CreateFolder(name string) string { return repo, nil
oc := ext.NewCloud(os.Getenv("CLOUD_BASE_URL"), os.Getenv("CLOUD_USER"), os.Getenv("CLOUD_PASS")) }
cloud, _ := oc.CreateFolder(name) func (wc *WorkflowController) CreateFolder(name string) (*d.Folder, error) {
if cloud != nil {
return cloud.FolderPath //Create ownCloud folder w/ iCloud interface;
cloud, err := wc.iCloud.CreateFolder(name)
if cloud == nil {
return nil, err
} }
return "no-folder"
/* [ ] Experimental call:
wc.iCloud.ShareToExternals(cloud)
*/
return cloud, err
} }

7
domain/cloud.go Normal file
View File

@ -0,0 +1,7 @@
package domain
type Folder struct {
Title string // k
PathTo string // /temp/k
PrivateURL string // http://domain/apps/files/?dir=/temp/k OR http://domain/f/3333
}

View File

@ -1,11 +1,11 @@
package domain package domain
type Git struct { type Git struct {
Name string `json:"name"` Name string `json:"name"` // "poop"
FullName string `json:"full_name"` FullName string `json:"full_name"` // "developer/poop"
Private bool `json:"private"` Private bool `json:"private"`
Url string `json:"url"` Url string `json:"url"` // "http://localhost:8081/api/v3/repos/developer/poop"
CloneUrl string `json:"clone_url"` CloneUrl string `json:"clone_url"` // "http://localhost:8081/git/developer/poop.git"
HtmlUrl string `json:"Html_url"` HtmlUrl string `json:"Html_url"` // "http://localhost:8081/developer/poop"
SshUrl string `json:"ssh_url"` SshUrl string `json:"ssh_url"` // ?!
} }

32
domain/youtrack.go Normal file
View File

@ -0,0 +1,32 @@
package domain
type Project struct {
ID string `json:"id"`
ShortName string `json:"shortName"`
Name string `json:"name"`
}
type ProjectID struct {
ID string `json:"id"`
}
type IssueCreateRequest struct {
ProjectID ProjectID `json:"project"`
Key string `json:"idReadable"`
ID string `json:"id"`
Summary string `json:"summary"`
Description string `json:"description"`
}
// [ ] try `,omitempty` to remove extra struct;
type IssueUpdateRequest struct {
IssueCreateRequest
CustomFields []CustomField `json:"customFields"`
}
type CustomField struct {
Name string `json:"name"`
Type string `json:"$type"`
Value string `json:"value"`
}

View File

@ -1,42 +1,103 @@
package ext package ext
import ( import (
"fmt"
"os" "os"
"strconv"
d "ticket-pimp/domain"
"ticket-pimp/helpers"
"time" "time"
) )
func NewCloud(base, user, pass string) *Client { type Cloud struct {
*Client
}
type ICloud interface {
CreateFolder(name string) (*d.Folder, error)
ShareToExternals(cloud *d.Folder) (*d.Folder, error)
}
func NewCloud(base, user, pass string) *Cloud {
client := NewClient(). client := NewClient().
SetTimeout(5*time.Second). SetTimeout(5*time.Second).
SetCommonBasicAuth(user, pass). SetCommonBasicAuth(user, pass).
SetBaseURL(base) SetBaseURL(base)
return &Client{ return &Cloud{
Client: &Client{
client, client,
},
} }
} }
type Cloud struct { func (c *Cloud) CreateFolder(name string) (*d.Folder, error) {
FolderName string rootDir := os.Getenv("ROOTDIR")
FolderPath string user := os.Getenv("CLOUD_USER")
davPath := "/remote.php/dav/files/"
parentPath := "/apps/files/?dir="
name = helpers.GitNaming(name)
cloud := d.Folder{
Title: name,
PrivateURL: "",
} }
func (c *Client) CreateFolder(name string) (*Cloud, error) { requestPath := davPath + user + rootDir + name
cloud := Cloud{ cloud.PathTo = parentPath + rootDir + name
FolderName: name,
FolderPath: "",
}
pathName := os.Getenv("HOMEPATH") + name resp, _ := c.R().
Send("MKCOL", requestPath)
resp, err := c.R().
Send("MKCOL", pathName)
if resp.IsSuccessState() { if resp.IsSuccessState() {
cloud.FolderPath = c.BaseURL + os.Getenv("FOLDER_PATH") + name // Set stupid URL to the d entity
} cloud.PrivateURL = c.BaseURL + cloud.PathTo
// Try to set short URL to the d entity
if err := c.setPrivateURL(requestPath, &cloud); err != nil {
return &cloud, err return &cloud, err
} }
}
return &cloud, nil
}
func (c *Cloud) setPrivateURL(requestPath string, cloud *d.Folder) error {
payload := []byte(`<?xml version="1.0"?><a:propfind xmlns:a="DAV:" xmlns:oc="http://owncloud.org/ns"><a:prop><oc:fileid/></a:prop></a:propfind>`)
// Deprecated: Read XML file
/*
xmlFile, err := ioutil.ReadFile("./fileid.xml") // moved into this method as a string..
if err != nil {
return fmt.Errorf("request xml file error: %v", err)
}
*/
resp, _ := c.R().
SetBody(payload).
Send("PROPFIND", requestPath)
if resp.Err != nil {
return resp.Err
}
id := helpers.GetFileIDFromRespBody(resp.Bytes())
if id == 0 {
return fmt.Errorf("unable to get fileid")
}
cloud.PrivateURL = c.BaseURL + "/f/" + strconv.Itoa(id)
return nil
}
func (c *Cloud) ShareToExternals(cloud *d.Folder) (*d.Folder, error) {
return nil, nil
}

View File

@ -10,7 +10,11 @@ import (
type Git struct { type Git struct {
*Client *Client
*domain.Git }
type IGit interface {
NewRepo(string) (*domain.Git, error)
AppsAsCollaboratorTo(*domain.Git) (*domain.Git, error)
} }
func NewGit(base, token string) *Git { func NewGit(base, token string) *Git {
@ -28,15 +32,6 @@ func NewGit(base, token string) *Git {
return &Git{ return &Git{
Client: &Client{client}, Client: &Client{client},
Git: &domain.Git{
Name: "",
FullName: "",
Private: true,
Url: "",
CloneUrl: "",
HtmlUrl: "",
SshUrl: "",
},
} }
} }
@ -58,32 +53,37 @@ func (gb *Git) NewRepo(name string) (*domain.Git, error) {
} }
var git domain.Git var git domain.Git
git.Private = true
resp, err := gb.R(). resp, _ := gb.R().
SetBody(&payload). SetBody(&payload).
SetSuccessResult(&git). SetSuccessResult(&git).
Post("/user/repos") Post("/user/repos")
//Post("/orgs/apps/repos")
if err != nil { if resp.Err != nil {
log.Print(resp) log.Print(resp.Err)
return nil, resp.Err
} }
return &git, err return &git, nil
} }
func (gb *Client) AppsAsCollaboratorTo(git *domain.Git) (*domain.Git, error) { func (gb *Git) AppsAsCollaboratorTo(git *domain.Git) (*domain.Git, error) {
payloadPermission := permissionRequest{
payload := permissionRequest{
Perm: "admin", Perm: "admin",
} }
resp, err := gb.R(). respURL := "/repos/" + os.Getenv("GIT_USER") + "/" + git.Name + "/collaborators/apps"
SetBody(&payloadPermission).
Put("/repos/" + os.Getenv("GIT_USER") + "/" + git.Name + "/collaborators/apps")
if err != nil { resp, _ := gb.R().
log.Print(resp) SetBody(&payload).
Put(respURL)
if resp.Err != nil {
log.Print(resp.Err)
return nil, resp.Err
} }
return git, err return git, nil
} }

View File

@ -5,6 +5,8 @@ import (
"log" "log"
"time" "time"
d "ticket-pimp/domain"
"github.com/imroc/req/v3" "github.com/imroc/req/v3"
) )
@ -12,6 +14,12 @@ type youtrack struct {
*req.Client *req.Client
} }
type IYouTrack interface {
GetProjects() ([]d.Project, error)
CreateIssue(projectID, name string) (*d.IssueCreateRequest, error)
UpdateIssue(issue *d.IssueCreateRequest, folder, git, gitBuild string) (*d.IssueUpdateRequest, error)
}
func NewYT(base, token string) *youtrack { func NewYT(base, token string) *youtrack {
headers := map[string]string{ headers := map[string]string{
"Accept": "application/json", "Accept": "application/json",
@ -29,51 +37,33 @@ func NewYT(base, token string) *youtrack {
} }
} }
type Project struct {
ID string `json:"id"`
ShortName string `json:"shortName"`
Name string `json:"name"`
}
// GetProjects // GetProjects
// provides an array of existing projects; // provides an array of existing projects;
func (yt *youtrack) GetProjects() ([]Project, error) { func (yt *youtrack) GetProjects() ([]d.Project, error) {
var projects []Project var projects []d.Project
_, err := yt.R(). resp, _ := yt.R().
EnableDump(). EnableDump().
SetQueryParam("fields", "id,name,shortName"). SetQueryParam("fields", "id,name,shortName").
SetSuccessResult(&projects). SetSuccessResult(&projects).
Get("/admin/projects") Get("/admin/projects")
// Check if the request failed; // Check if the request failed;
if err != nil { if resp.Err != nil {
return nil, fmt.Errorf("some problem with YT request. error message: %v", err) return nil, fmt.Errorf("some problem with YT request. error message: %v", resp.Err)
} }
return projects, nil return projects, nil
} }
type ProjectID struct {
ID string `json:"id"`
}
type IssueCreateRequest struct {
ProjectID ProjectID `json:"project"`
Key string `json:"idReadable"`
ID string `json:"id"`
Summary string `json:"summary"`
Description string `json:"description"`
}
// CreateIssue // CreateIssue
// example: newIssue := yt.CreateIssue("0-2", "Summary", "Description"); // example: newIssue := yt.CreateIssue("0-2", "Summary", "Description");
func (yt *youtrack) CreateIssue(projectID, name string) (*IssueCreateRequest, error) { func (yt *youtrack) CreateIssue(projectID, name string) (*d.IssueCreateRequest, error) {
// Create an issue with the provided:, Project ID, Name, Description; // Create an issue with the provided:, Project ID, Name, Description;
issue := IssueCreateRequest{ issue := d.IssueCreateRequest{
ProjectID: ProjectID{ ProjectID: d.ProjectID{
ID: projectID, //"id":"0-2" ID: projectID, //"id":"0-2"
}, },
Summary: name, Summary: name,
@ -81,40 +71,25 @@ func (yt *youtrack) CreateIssue(projectID, name string) (*IssueCreateRequest, er
} }
// Push issue to the YT; // Push issue to the YT;
_, err := yt.R(). resp, _ := yt.R().
SetQueryParam("fields", "idReadable,id"). SetQueryParam("fields", "idReadable,id").
SetBody(&issue). SetBody(&issue).
SetSuccessResult(&issue). SetSuccessResult(&issue).
Post("/issues") Post("/issues")
// Check if the request failed; // Check if the request failed;
if err != nil { if resp.Err != nil {
return nil, fmt.Errorf("some problem with YT request. error message: %v", err) return nil, fmt.Errorf("some problem with YT request. error message: %v", resp.Err)
} }
return &issue, nil return &issue, nil
} }
type IssueUpdateRequest struct { func (yt *youtrack) UpdateIssue(issue *d.IssueCreateRequest, folder, git, gitBuild string) (*d.IssueUpdateRequest, error) {
IssueCreateRequest
CustomFields []CustomField `json:"customFields"`
}
type CustomFields struct {
List []CustomField `json:"customFields"`
}
type CustomField struct {
Name string `json:"name"`
Type string `json:"$type"`
Value string `json:"value"`
}
func (yt *youtrack) UpdateIssue(issue *IssueCreateRequest, folder, git, gitBuild string) (*IssueUpdateRequest, error) {
// Set Folder, Git, GitBuild to the Issue: // Set Folder, Git, GitBuild to the Issue:
update := IssueUpdateRequest{ update := d.IssueUpdateRequest{
IssueCreateRequest: *issue, IssueCreateRequest: *issue,
CustomFields: []CustomField{ CustomFields: []d.CustomField{
{ {
Name: "Директория графики", Name: "Директория графики",
Type: "SimpleIssueCustomField", Type: "SimpleIssueCustomField",
@ -134,14 +109,14 @@ func (yt *youtrack) UpdateIssue(issue *IssueCreateRequest, folder, git, gitBuild
} }
// Push issue update to YT // Push issue update to YT
resp, err := yt.R(). resp, _ := yt.R().
SetBody(&update). SetBody(&update).
SetSuccessResult(&issue). SetSuccessResult(&issue).
Post("/issues/" + issue.Key) Post("/issues/" + issue.Key)
// Check if the request failed; // Check if the request failed;
if err != nil { if resp.Err != nil {
return nil, fmt.Errorf("some problem with YT request. error message: %v", err) return nil, fmt.Errorf("some problem with YT request. error message: %v", resp.Err)
} }
if !resp.IsSuccessState() { if !resp.IsSuccessState() {

1
go.mod
View File

@ -19,6 +19,7 @@ require (
github.com/quic-go/qtls-go1-19 v0.3.2 // indirect github.com/quic-go/qtls-go1-19 v0.3.2 // indirect
github.com/quic-go/qtls-go1-20 v0.2.2 // indirect github.com/quic-go/qtls-go1-20 v0.2.2 // indirect
github.com/quic-go/quic-go v0.35.1 // indirect github.com/quic-go/quic-go v0.35.1 // indirect
github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2 // indirect
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce // indirect
golang.org/x/crypto v0.9.0 // indirect golang.org/x/crypto v0.9.0 // indirect
golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 // indirect

2
go.sum
View File

@ -38,6 +38,8 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+
github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c= github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2 h1:VsBj3UD2xyAOu7kJw6O/2jjG2UXLFoBzihqDU9Ofg9M=
github.com/studio-b12/gowebdav v0.0.0-20230203202212-3282f94193f2/go.mod h1:bHA7t77X/QFExdeAnDzK6vKM34kEZAcE1OX4MfiwjkE=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce h1:fb190+cK2Xz/dvi9Hv8eCYJYvIGUTN2/KLq1pT6CjEc=
github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4= github.com/tomasen/realip v0.0.0-20180522021738-f0c99a92ddce/go.mod h1:o8v6yHRoik09Xen7gje4m9ERNah1d1PPsVq1VEx9vE4=
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=

View File

@ -6,11 +6,108 @@ import (
"fmt" "fmt"
"strings" "strings"
"ticket-pimp/controller" "ticket-pimp/controller"
d "ticket-pimp/domain"
"github.com/mr-linch/go-tg" "github.com/mr-linch/go-tg"
"github.com/mr-linch/go-tg/tgb" "github.com/mr-linch/go-tg/tgb"
) )
type Handler struct {
workflow controller.IWorkflowController
}
func NewHandler(gitBaseURL, gitToken, cloudBaseURL, cloudAuthUser, cloudAuthPass, ytBaseURL, ytToken string) *Handler {
return &Handler{
workflow: controller.NewWorkflowController(
gitBaseURL,
gitToken,
cloudBaseURL,
cloudAuthUser,
cloudAuthPass,
ytBaseURL,
ytToken),
}
}
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(d *d.Git) *git {
return &git{
name: d.Name,
url: d.HtmlUrl,
git: d.CloneUrl,
ssh: fmt.Sprintf("ssh://%s/%s.git", d.SshUrl, d.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 *d.Git
g, err := h.workflow.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.workflow.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 { func errorAnswer(errorMsg string) string {
return tg.HTML.Text( return tg.HTML.Text(
tg.HTML.Line( tg.HTML.Line(
@ -19,7 +116,7 @@ func errorAnswer(errorMsg string) string {
) )
} }
func NewTicketHandler(ctx context.Context, mu *tgb.MessageUpdate) error { func (h *Handler) NewTicketHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/new", "", 1) str := strings.Replace(mu.Text, "/new", "", 1)
@ -27,7 +124,7 @@ func NewTicketHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
return errors.New("empty command provided") return errors.New("empty command provided")
} }
issueKeyStr, err := controller.Workflow(str) issueKeyStr, err := h.workflow.Workflow(str)
if err != nil { if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx) return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
@ -45,34 +142,3 @@ func newTicketAnswer(name string) string {
), ),
) )
} }
func NewRepoHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
str := strings.Replace(mu.Text, "/repo", "", 1)
if str == "" {
return errors.New("empty command provided")
}
repoStr, err := controller.CreateRepo(str, 0)
if err != nil {
return mu.Answer(errorAnswer(err.Error())).ParseMode(tg.HTML).DoVoid(ctx)
}
return mu.Answer(newRepoAnswer(repoStr)).ParseMode(tg.HTML).DoVoid(ctx)
}
func newRepoAnswer(name string) string {
return tg.HTML.Text(
tg.HTML.Line(
"Repo ",
name,
"has been created!",
),
)
}
func PingHandler(ctx context.Context, mu *tgb.MessageUpdate) error {
return mu.Answer("pong").DoVoid(ctx)
}

View File

@ -1,7 +1,9 @@
package helpers package helpers
import ( import (
"encoding/xml"
"regexp" "regexp"
"strconv"
"strings" "strings"
) )
@ -22,3 +24,37 @@ func GitNaming(input string) string {
// Join words and return // Join words and return
return strings.Join(words, "-") return strings.Join(words, "-")
} }
type MultistatusObj struct {
XMLName xml.Name `xml:"multistatus"`
Multistatus struct {
XMLName xml.Name `xml:"response"`
Propstat struct {
XMLName xml.Name `xml:"propstat"`
Prop struct {
XMLName xml.Name `xml:"prop"`
FileID struct {
XMLName xml.Name `xml:"fileid"`
ID string `xml:",chardata"`
}
}
}
}
}
func GetFileIDFromRespBody(str []byte) int {
var multi MultistatusObj
err := xml.Unmarshal(str, &multi)
if err != nil {
return 0
}
id, err := strconv.Atoi(multi.Multistatus.Propstat.Prop.FileID.ID)
if err != nil {
return 0
}
return id
}

View File

@ -1,6 +1,8 @@
package helpers package helpers
import "testing" import (
"testing"
)
type test struct { type test struct {
arg, expected string arg, expected string

17
helpers/xml_test.go Normal file
View File

@ -0,0 +1,17 @@
package helpers
import (
"testing"
)
const (
EXAMPLE = "<?xml version=\"1.0\"?>\n<d:multistatus xmlns:d=\"DAV:\" xmlns:s=\"http://sabredav.org/ns\" xmlns:oc=\"http://owncloud.org/ns\"><d:response><d:href>/remote.php/dav/files/naudachu/temp/id/</d:href><d:propstat><d:prop><oc:fileid>33225</oc:fileid></d:prop><d:status>HTTP/1.1 200 OK</d:status></d:propstat></d:response></d:multistatus>\n"
)
// [ ] todo normal test...
func TestGetFileID(t *testing.T) {
if output := GetFileIDFromRespBody([]byte(EXAMPLE)); output != 33225 {
t.Errorf("Output %q not equal to expected %q", output, 33225)
}
}