From 5112c12848d7ce5030f1387ed4d6a90e76f3cc67 Mon Sep 17 00:00:00 2001 From: Maxim Lebedev Date: Fri, 27 Jul 2018 16:51:14 +0500 Subject: [PATCH] :recycle: Package refactor --- Makefile | 32 ++++++++++ content.go | 56 ++++------------- create_account.go | 73 +++++++--------------- create_page.go | 90 +++++++-------------------- edit_account_info.go | 33 +++++----- edit_page.go | 57 +++++++---------- example_test.go | 12 ++-- get_account_info.go | 42 +++---------- get_page.go | 17 ++--- get_page_list.go | 31 +++------ get_views.go | 49 +++++---------- request.go | 63 ++++++++++++------- revoke_access_token.go | 24 ++++--- test/invalid_test.go | 35 ++++++++--- test/valid_test.go | 25 +++++--- types.go | 138 +++++++++++++++++++++++++++++++++++++++++ 16 files changed, 409 insertions(+), 368 deletions(-) create mode 100644 Makefile create mode 100644 types.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..32d3c3b --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +PROJECT_NAMESPACE := $(CI_PROJECT_NAMESPACE) +PROJECT_NAME := $(CI_PROJECT_NAME) +PROJECT_PATH := $(PROJECT_NAMESPACE)/$(PROJECT_NAME) +PACKAGE_NAME := "gitlab.com/$(PROJECT_PATH)" +PACKAGE_PATH := $(GOPATH)/src/$(PACKAGE_NAME) +PACKAGE_LIST := $(shell go list $(PACKAGE_NAME)/... | grep -v /vendor/) +GO_FILES := $(shell find . -name '*.go' | grep -v /vendor/ | grep -v _test.go) + +.PHONY: all lint test rase coverage dep build clean + +all: build + +lint: ## Lint the files + @gocritic check-project $(PACKAGE_PATH) + +test: ## Run unittests + @go test -short ${PACKAGE_LIST} + +race: dep ## Run data race detector + @go test -race -short ${PACKAGE_LIST} + +coverage: ## Generate global code coverage report + @go test -cover -v -coverpkg=$(PACKAGE_NAME) ${PACKAGE_LIST} + +dep: ## Get the dependencies + @go get -v -d -t ${PACKAGE_LIST} + +clean: ## Remove previous build + @rm -f $(PROJECT_NAME) + +help: ## Display this help screen + @grep -h -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' \ No newline at end of file diff --git a/content.go b/content.go index db7b8aa..13df2d8 100644 --- a/content.go +++ b/content.go @@ -2,69 +2,38 @@ package telegraph import ( "bytes" - "errors" "io" "strings" "golang.org/x/net/html" ) -type ( - // Node is abstract object represents a DOM Node. It can be a String which represents a DOM text - // node or a NodeElement object. - Node interface{} - - // NodeElement represents a DOM element node. - NodeElement struct { - // Name of the DOM element. - // Available tags: a, aside, b, blockquote, br, code, em, figcaption, figure, h3, - // h4, hr, i, iframe, img, li, ol, p, pre, s, strong, u, ul, video. - Tag string `json:"tag"` - - // Attributes of the DOM element. Key of object represents name of attribute, - // value represents value of attribute. - // Available attributes: href, src. - Attrs map[string]string `json:"attrs,omitempty"` // optional - - // List of child nodes for the DOM element. - Children []Node `json:"children,omitempty"` // optional - } -) - -// ErrInvalidDataType is returned when ContentFormat function are passed a data argument of invalid -// type. -var ErrInvalidDataType = errors.New("invalid data type") - -// ContentFormat transforms data to a DOM-based format to represent the content of the page. -func ContentFormat(data interface{}) ([]Node, error) { - var doc html.Node - switch dst := data.(type) { +// ContentFormat transforms data to a DOM-based format to represent the content +// of the page. +func ContentFormat(data interface{}) (n []Node, err error) { + dst := new(html.Node) + switch src := data.(type) { case string: - dom, err := html.Parse(strings.NewReader(dst)) + dst, err = html.Parse(strings.NewReader(src)) if err != nil { return nil, err } - doc = *dom case []byte: - dom, err := html.Parse(bytes.NewReader(dst)) + dst, err = html.Parse(bytes.NewReader(src)) if err != nil { return nil, err } - doc = *dom case io.Reader: - dom, err := html.Parse(dst) + dst, err = html.Parse(src) if err != nil { return nil, err } - doc = *dom default: return nil, ErrInvalidDataType } - var content []Node - content = append(content, domToNode(doc.FirstChild)) - - return content, nil + n = append(n, domToNode(dst.FirstChild)) + return } func domToNode(domNode *html.Node) interface{} { @@ -78,8 +47,9 @@ func domToNode(domNode *html.Node) interface{} { var nodeElement NodeElement switch strings.ToLower(domNode.Data) { - case "a", "aside", "b", "blockquote", "br", "code", "em", "figcaption", "figure", "h3", "h4", - "hr", "i", "iframe", "img", "li", "ol", "p", "pre", "s", "strong", "u", "ul", "video": + case "a", "aside", "b", "blockquote", "br", "code", "em", "figcaption", + "figure", "h3", "h4", "hr", "i", "iframe", "img", "li", "ol", + "p", "pre", "s", "strong", "u", "ul", "video": nodeElement.Tag = domNode.Data for i := range domNode.Attr { diff --git a/create_account.go b/create_account.go index bb2b649..8bfff9d 100644 --- a/create_account.go +++ b/create_account.go @@ -5,58 +5,29 @@ import ( http "github.com/valyala/fasthttp" ) -// Account represents a Telegraph account. -type Account struct { - // Only returned by the createAccount and revokeAccessToken method. Access token - // of the Telegraph account. - AccessToken string `json:"access_token"` // optional - - // URL to authorize a browser on telegra.ph and connect it to a Telegraph - // account. This URL is valid for only one use and for 5 minutes only. - AuthURL string `json:"auth_url,omitempty"` // optional - - // Account name, helps users with several accounts remember which they are - // currently using. Displayed to the user above the "Edit/Publish" button on - // Telegra.ph, other users don't see this name. - ShortName string `json:"short_name"` - - // Default author name used when creating new articles. - AuthorName string `json:"author_name"` - - // Profile link, opened when users click on the author's name below the title. - // Can be any link, not necessarily to a Telegram profile or channel. - AuthorURL string `json:"author_url"` - - // Number of pages belonging to the Telegraph account. - PageCount int `json:"page_count,omitempty"` // optional -} - -// CreateAccount create a new Telegraph account. Most users only need one account, but this can be -// useful for channel administrators who would like to keep individual author names and profile links -// for each of their channels. On success, returns an Account object with the regular fields and an -// additional access_token field. -func CreateAccount(account *Account) (*Account, error) { - args := http.AcquireArgs() - - // Account name, helps users with several accounts remember which they are currently using. - // Displayed to the user above the "Edit/Publish" button on Telegra.ph, other users don't see - // this name. - args.Add("short_name", account.ShortName) // required - - // Default author name used when creating new articles. - args.Add("author_name", account.AuthorName) - - // Default profile link, opened when users click on the author's name below the title. Can be any - // link, not necessarily to a Telegram profile or channel. - args.Add("author_url", account.AuthorURL) - - body, err := request("createAccount", "", args) - if err != nil { - return nil, err +// CreateAccount create a new Telegraph account. Most users only need one +// account, but this can be useful for channel administrators who would like to +// keep individual author names and profile links for each of their channels. On +// success, returns an Account object with the regular fields and an additional +// access_token field. +func CreateAccount(account *Account) (r *Account, err error) { + if account == nil { + return nil, ErrNoInputData } - var resp Account - err = json.Unmarshal(*body.Result, &resp) + args := http.AcquireArgs() + defer http.ReleaseArgs(args) + args.Add("short_name", account.ShortName) // required + args.Add("author_name", account.AuthorName) + args.Add("author_url", account.AuthorURL) - return &resp, err + dst := new(Response) + dst, err = makeRequest("createAccount", args) + if err != nil { + return + } + + r = new(Account) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/create_page.go b/create_page.go index 48c310f..e702119 100644 --- a/create_page.go +++ b/create_page.go @@ -7,80 +7,34 @@ import ( http "github.com/valyala/fasthttp" ) -// Page represents a page on Telegraph. -type Page struct { - // Path to the page. - Path string `json:"path"` - - // URL of the page. - URL string `json:"url"` - - // Title of the page. - Title string `json:"title"` - - // Description of the page. - Description string `json:"description"` - - // Name of the author, displayed below the title. - AuthorName string `json:"author_name,omitempty"` // optional - - // Profile link, opened when users click on the author's name below the title. - // Can be any link, not necessarily to a Telegram profile or channel. - AuthorURL string `json:"author_url,omitempty"` // optional - - // Image URL of the page. - ImageURL string `json:"image_url,omitempty"` // optional - - // Content of the page. - Content []Node `json:"content,omitempty"` // optional - - // Number of page views for the page. - Views int `json:"views"` - - // Only returned if access_token passed. True, if the target Telegraph account - // can edit the page. - CanEdit bool `json:"can_edit,omitempty"` // optional -} - // CreatePage create a new Telegraph page. On success, returns a Page object. -func (account *Account) CreatePage(page *Page, returnContent bool) (*Page, error) { +func (a *Account) CreatePage(page *Page, returnContent bool) (r *Page, err error) { + if page == nil { + return nil, ErrNoInputData + } + + var src []byte + src, err = json.Marshal(page.Content) + if err != nil { + return + } + args := http.AcquireArgs() - - // Access token of the Telegraph account. - args.Add("access_token", account.AccessToken) // required - - // Page title. - args.Add("title", page.Title) // required - - if page.AuthorName != "" { - // Author name, displayed below the article's title. - args.Add("author_name", page.AuthorName) - } - - if page.AuthorURL != "" { - // Profile link, opened when users click on the author's name below the title. Can be any - // link, not necessarily to a Telegram profile or channel. - args.Add("author_url", page.AuthorURL) - } - - // If true, a content field will be returned in the Page object. + defer http.ReleaseArgs(args) + args.Add("access_token", a.AccessToken) // required + args.Add("title", page.Title) // required + args.Add("author_name", a.AuthorName) + args.Add("author_url", a.AuthorURL) + args.Add("content", string(src)) args.Add("return_content", strconv.FormatBool(returnContent)) - content, err := json.Marshal(page.Content) + dst := new(Response) + dst, err = makeRequest("createPage", args) if err != nil { return nil, err } - // Content of the page. - args.Add("content", string(content)) // required - - body, err := request("createPage", "", args) - if err != nil { - return nil, err - } - - var resp Page - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(Page) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/edit_account_info.go b/edit_account_info.go index 522b266..e9f6f15 100644 --- a/edit_account_info.go +++ b/edit_account_info.go @@ -5,31 +5,28 @@ import ( http "github.com/valyala/fasthttp" ) -// EditAccountInfo update information about a Telegraph account. Pass only the parameters that you -// want to edit. On success, returns an Account object with the default fields. -func (account *Account) EditAccountInfo(update *Account) (*Account, error) { +// EditAccountInfo update information about a Telegraph account. Pass only the +// parameters that you want to edit. On success, returns an Account object with +// the default fields. +func (a *Account) EditAccountInfo(update *Account) (r *Account, err error) { + if update == nil { + return nil, ErrNoInputData + } + args := http.AcquireArgs() - - // Access token of the Telegraph account. - args.Add("access_token", account.AccessToken) // required - - // New account name. + defer http.ReleaseArgs(args) + args.Add("access_token", a.AccessToken) // required args.Add("short_name", update.ShortName) - - // New default author name used when creating new articles. args.Add("author_name", update.AuthorName) - - // New default profile link, opened when users click on the author's name below the title. Can be - // any link, not necessarily to a Telegram profile or channel. args.Add("author_url", update.AuthorURL) - body, err := request("editAccountInfo", "", args) + dst := new(Response) + dst, err = makeRequest("editAccountInfo", args) if err != nil { return nil, err } - var resp Account - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(Account) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/edit_page.go b/edit_page.go index 2ee0671..69530e9 100644 --- a/edit_page.go +++ b/edit_page.go @@ -1,6 +1,7 @@ package telegraph import ( + "path" "strconv" json "github.com/pquerna/ffjson/ffjson" @@ -8,44 +9,34 @@ import ( ) // EditPage edit an existing Telegraph page. On success, returns a Page object. -func (account *Account) EditPage(update *Page, returnContent bool) (*Page, error) { +func (a *Account) EditPage(update *Page, returnContent bool) (r *Page, err error) { + if update == nil { + return nil, ErrNoInputData + } + + var src []byte + src, err = json.Marshal(update.Content) + if err != nil { + return + } + args := http.AcquireArgs() - - // Access token of the Telegraph account. - args.Add("access_token", account.AccessToken) // required - - // Page title. - args.Add("title", update.Title) // required - - if update.AuthorName != "" { - // Author name, displayed below the article's title. - args.Add("author_name", update.AuthorName) - } - - if update.AuthorURL != "" { - // Profile link, opened when users click on the author's name below the title. Can be any - // link, not necessarily to a Telegram profile or channel. - args.Add("author_url", update.AuthorURL) - } - - // If true, a content field will be returned in the Page object. + defer http.ReleaseArgs(args) + args.Add("access_token", a.AccessToken) // required + args.Add("path", update.Path) // required + args.Add("title", update.Title) // required + args.Add("content", string(src)) // required + args.Add("author_name", a.AuthorName) + args.Add("author_url", a.AuthorURL) args.Add("return_content", strconv.FormatBool(returnContent)) - content, err := json.Marshal(update.Content) + dst := new(Response) + dst, err = makeRequest(path.Join("editPage", update.Path), args) if err != nil { return nil, err } - // Content of the page. - args.Add("content", string(content)) // required - - body, err := request("editPage", update.Path, args) - if err != nil { - return nil, err - } - - var resp Page - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(Page) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/example_test.go b/example_test.go index aa93a3f..ea39b00 100644 --- a/example_test.go +++ b/example_test.go @@ -2,8 +2,9 @@ package telegraph_test import ( "log" + "time" - "github.com/toby3d/telegraph" + "gitlab.com/toby3d/telegraph" ) // Content in a string format (for this example). @@ -22,8 +23,8 @@ const data = ` ` var ( - account *telegraph.Account - page *telegraph.Page + account = new(telegraph.Account) + page = new(telegraph.Page) content []telegraph.Node ) @@ -168,7 +169,10 @@ func ExampleAccount_GetPageList() { func ExampleGetViews() { pagePath := "Sample-Page-12-15" - views, err := telegraph.GetViews(pagePath, 2016, 12, 0, -1) + views, err := telegraph.GetViews( + pagePath, + time.Date(2016, 12, 0, 0, 0, 0, 0, nil), + ) errCheck(err) log.Println(pagePath, "has been viewed", views.Views, "times") diff --git a/get_account_info.go b/get_account_info.go index bf0140d..caaa32e 100644 --- a/get_account_info.go +++ b/get_account_info.go @@ -1,50 +1,26 @@ package telegraph import ( - "fmt" "strings" json "github.com/pquerna/ffjson/ffjson" http "github.com/valyala/fasthttp" ) -const ( - // FieldShortName used as GetAccountInfo argument for getting account name. - FieldShortName = "short_name" - - // FieldAuthorName used as GetAccountInfo argument for getting author name. - FieldAuthorName = "author_name" - - // FieldAuthorURL used as GetAccountInfo argument for getting profile link. - FieldAuthorURL = "author_url" - - // FieldAuthURL used as GetAccountInfo argument for getting URL to authorize - // a browser on telegra.ph. - FieldAuthURL = "auth_url" - - // FieldPageCount used as GetAccountInfo argument for getting number of pages - // belonging to the Telegraph account. - FieldPageCount = "page_count" -) - // GetAccountInfo get information about a Telegraph account. Returns an Account object on success. -func (account *Account) GetAccountInfo(fields ...string) (*Account, error) { +func (a *Account) GetAccountInfo(fields ...string) (r *Account, err error) { args := http.AcquireArgs() + defer http.ReleaseArgs(args) + args.Add("access_token", a.AccessToken) // required + args.Add("fields", `["`+strings.Join(fields, `","`)+`"]`) - // Access token of the Telegraph account. - args.Add("access_token", account.AccessToken) // required - - // List of account fields to return. - // Available fields: short_name, author_name, author_url, auth_url, page_count. - args.Add("fields", fmt.Sprint(`["`, strings.Join(fields, `","`), `"]`)) - - body, err := request("getAccountInfo", "", args) + dst := new(Response) + dst, err = makeRequest("getAccountInfo", args) if err != nil { return nil, err } - var resp Account - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(Account) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/get_page.go b/get_page.go index f93f76e..0f34b5a 100644 --- a/get_page.go +++ b/get_page.go @@ -1,6 +1,7 @@ package telegraph import ( + gopath "path" "strconv" json "github.com/pquerna/ffjson/ffjson" @@ -8,19 +9,19 @@ import ( ) // GetPage get a Telegraph page. Returns a Page object on success. -func GetPage(path string, returnContent bool) (*Page, error) { +func GetPage(path string, returnContent bool) (r *Page, err error) { args := http.AcquireArgs() - - // If true, content field will be returned in Page object. + defer http.ReleaseArgs(args) + args.Add("path", path) // required args.Add("return_content", strconv.FormatBool(returnContent)) - body, err := request("getPage", path, args) + dst := new(Response) + dst, err = makeRequest(gopath.Join("getPage", path), args) if err != nil { return nil, err } - var resp Page - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(Page) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/get_page_list.go b/get_page_list.go index 794b990..78db217 100644 --- a/get_page_list.go +++ b/get_page_list.go @@ -7,37 +7,22 @@ import ( http "github.com/valyala/fasthttp" ) -// PageList represents a list of Telegraph articles belonging to an account. Most recently created -// articles first. -type PageList struct { - // Total number of pages belonging to the target Telegraph account. - TotalCount int `json:"total_count"` - - // Requested pages of the target Telegraph account. - Pages []*Page `json:"pages"` -} - // GetPageList get a list of pages belonging to a Telegraph account. Returns a PageList object, sorted // by most recently created pages first. -func (account *Account) GetPageList(offset, limit int) (*PageList, error) { +func (a *Account) GetPageList(offset, limit int) (r *PageList, err error) { args := http.AcquireArgs() - - // Access token of the Telegraph account. - args.Add("access_token", account.AccessToken) // required - - // Sequential number of the first page to be returned. + defer http.ReleaseArgs(args) + args.Add("access_token", a.AccessToken) // required args.Add("offset", strconv.Itoa(offset)) - - // Limits the number of pages to be retrieved. args.Add("limit", strconv.Itoa(limit)) - body, err := request("getPageList", "", args) + dst := new(Response) + dst, err = makeRequest("getPageList", args) if err != nil { return nil, err } - var resp PageList - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(PageList) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/get_views.go b/get_views.go index 5d75a72..bb2c985 100644 --- a/get_views.go +++ b/get_views.go @@ -1,53 +1,32 @@ package telegraph import ( + gopath "path" "strconv" + "time" json "github.com/pquerna/ffjson/ffjson" http "github.com/valyala/fasthttp" ) -// PageViews represents the number of page views for a Telegraph article. -type PageViews struct { - // Number of page views for the target page. - Views int `json:"views"` -} - // GetViews get the number of views for a Telegraph article. By default, the total number of page // views will be returned. Returns a PageViews object on success. -func GetViews(path string, year, month, day, hour int) (*PageViews, error) { +func GetViews(path string, date time.Time) (r *PageViews, err error) { args := http.AcquireArgs() + defer http.ReleaseArgs(args) + args.Add("path", path) // required + args.Add("year", strconv.Itoa(date.Year())) + args.Add("month", strconv.Itoa(int(date.Month()))) + args.Add("day", strconv.Itoa(date.Day())) + args.Add("hour", strconv.Itoa(date.Hour())) - if hour > -1 { - // If passed, the number of page views for the requested hour will be returned. - args.Add("hour", strconv.Itoa(hour)) - } - - if day > 0 { - // Required if hour is passed. If passed, the number of page views for the requested day will - // be returned. - args.Add("day", strconv.Itoa(day)) - } - - if month > 0 { - // Required if day is passed. If passed, the number of page views for the requested month will - // be returned. - args.Add("month", strconv.Itoa(month)) - } - - if year > 0 { - // Required if month is passed. If passed, the number of page views for the requested year - // will be returned. - args.Add("year", strconv.Itoa(year)) - } - - body, err := request("getViews", path, args) + dst := new(Response) + dst, err = makeRequest(gopath.Join("getViews", path), args) if err != nil { return nil, err } - var resp PageViews - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(PageViews) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/request.go b/request.go index d3bb6fc..daabef5 100644 --- a/request.go +++ b/request.go @@ -3,48 +3,63 @@ package telegraph import ( gojson "encoding/json" "errors" - "fmt" "net/url" + "github.com/kirillDanshin/dlog" json "github.com/pquerna/ffjson/ffjson" http "github.com/valyala/fasthttp" ) -// response represents a response from the Telegram API with the result stored raw. If ok equals true, -// the request was successful, and the result of the query can be found in the result field. In case of -// an unsuccessful request, ok equals false, and the error is explained in the error field (e.g. +// Response contains a JSON object, which always has a Boolean field ok. If ok +// equals true, the request was successful, and the result of the query can be +// found in the result field. In case of an unsuccessful request, ok equals +// false, and the error is explained in the error field (e.g. // SHORT_NAME_REQUIRED). -type response struct { +type Response struct { Ok bool `json:"ok"` Error string `json:"error"` - Result *gojson.RawMessage `json:"result"` + Result *gojson.RawMessage `json:"result,omitempty"` } -func request(method, path string, args *http.Args) (*response, error) { - defer http.ReleaseArgs(args) - requestURI := &url.URL{ - Scheme: "https", - Host: "api.telegra.ph", - Path: method, - } +var defaultURL = url.URL{ + Scheme: "https", + Host: "api.telegra.ph", +} - if path != "" { - requestURI.Path += fmt.Sprint("/", path) - } +func makeRequest(path string, args *http.Args) (r *Response, err error) { + requestURL := defaultURL + requestURL.Path = path + requestURL.RawQuery = args.String() - _, body, err := http.Post(nil, requestURI.String(), args) + req := http.AcquireRequest() + defer http.ReleaseRequest(req) + req.Header.SetMethod("GET") + req.SetRequestURI(requestURL.String()) + req.Header.SetUserAgent("toby3d/telegraph") + req.Header.SetContentType("application/json;charset=utf-8") + + dlog.Ln("request:") + dlog.D(req) + + resp := http.AcquireResponse() + defer http.ReleaseResponse(resp) + err = http.Do(req, resp) if err != nil { - return nil, err + dlog.Ln(err.Error()) + return } - var resp response - if err := json.Unmarshal(body, &resp); err != nil { - return nil, err + dlog.Ln("response:") + dlog.D(resp) + + r = new(Response) + if err = json.Unmarshal(resp.Body(), r); err != nil { + return } - if !resp.Ok { - return nil, errors.New(resp.Error) + if !r.Ok { + err = errors.New(r.Error) } - return &resp, nil + return } diff --git a/revoke_access_token.go b/revoke_access_token.go index 19abfc5..f232663 100644 --- a/revoke_access_token.go +++ b/revoke_access_token.go @@ -5,22 +5,26 @@ import ( http "github.com/valyala/fasthttp" ) +type revokeAccessTokenParameters struct { + // Access token of the Telegraph account. + AccessToken string `json:"access_token"` // required +} + // RevokeAccessToken revoke access_token and generate a new one, for example, if the user would // like to reset all connected sessions, or you have reasons to believe the token was compromised. On // success, returns an Account object with new access_token and auth_url fields. -func (account *Account) RevokeAccessToken() (*Account, error) { +func (a *Account) RevokeAccessToken() (r *Account, err error) { args := http.AcquireArgs() + defer http.ReleaseArgs(args) + args.Add("access_token", a.AccessToken) - // Access token of the Telegraph account. - args.Add("access_token", account.AccessToken) // required - - body, err := request("revokeAccessToken", "", args) + dst := new(Response) + dst, err = makeRequest("revokeAccessToken", args) if err != nil { - return nil, err + return } - var resp Account - err = json.Unmarshal(*body.Result, &resp) - - return &resp, err + r = new(Account) + err = json.Unmarshal(*dst.Result, r) + return } diff --git a/test/invalid_test.go b/test/invalid_test.go index 47c6ccd..d8e3dce 100644 --- a/test/invalid_test.go +++ b/test/invalid_test.go @@ -2,8 +2,9 @@ package telegraph_test import ( "testing" + "time" - "github.com/toby3d/telegraph" + "gitlab.com/toby3d/telegraph" ) const ( @@ -12,7 +13,7 @@ const ( invalidContent = 42 ) -var invalidAccount = &telegraph.Account{} +var invalidAccount = new(telegraph.Account) func TestInvalidContentFormat(t *testing.T) { if _, err := telegraph.ContentFormat(invalidContent); err != telegraph.ErrInvalidDataType { @@ -60,7 +61,10 @@ func testInvalidEditPage(t *testing.T) { } func testInvalidGetAccountInfo(t *testing.T) { - if _, err := invalidAccount.GetAccountInfo(telegraph.FieldShortName, telegraph.FieldPageCount); err == nil { + if _, err := invalidAccount.GetAccountInfo( + telegraph.FieldShortName, + telegraph.FieldPageCount, + ); err == nil { t.Error() } } @@ -90,31 +94,46 @@ func TestInvalidGetPage(t *testing.T) { } func TestInvalidGetViewsByPage(t *testing.T) { - if _, err := telegraph.GetViews(invalidPageURL, 2016, 12, 0, -1); err == nil { + if _, err := telegraph.GetViews( + invalidPageURL, + time.Date(2016, time.December, 0, 0, 0, 0, 0, time.UTC), + ); err == nil { t.Error() } } func TestInvalidGetViewsByHour(t *testing.T) { - if _, err := telegraph.GetViews(validPageURL, 0, 0, 0, 42); err == nil { + if _, err := telegraph.GetViews( + validPageURL, + time.Date(0, 0, 0, 42, 0, 0, 0, time.UTC), + ); err == nil { t.Error() } } func TestInvalidGetViewsByDay(t *testing.T) { - if _, err := telegraph.GetViews(validPageURL, 0, 0, 42, 23); err == nil { + if _, err := telegraph.GetViews( + validPageURL, + time.Date(0, 0, 42, 23, 0, 0, 0, time.UTC), + ); err == nil { t.Error() } } func TestInvalidGetViewsByMonth(t *testing.T) { - if _, err := telegraph.GetViews(validPageURL, 0, 22, 24, 23); err == nil { + if _, err := telegraph.GetViews( + validPageURL, + time.Date(0, 22, 24, 23, 0, 0, 0, time.UTC), + ); err == nil { t.Error() } } func TestInvalidGetViewsByYear(t *testing.T) { - if _, err := telegraph.GetViews(validPageURL, 1980, 12, 24, 23); err == nil { + if _, err := telegraph.GetViews( + validPageURL, + time.Date(1980, time.December, 24, 23, 0, 0, 0, time.UTC), + ); err == nil { t.Error() } } diff --git a/test/valid_test.go b/test/valid_test.go index 8d06134..5bca5eb 100644 --- a/test/valid_test.go +++ b/test/valid_test.go @@ -2,8 +2,9 @@ package telegraph_test import ( "testing" + "time" - "github.com/toby3d/telegraph" + "gitlab.com/toby3d/telegraph" ) const ( @@ -16,10 +17,10 @@ const ( ) var ( - validAccount *telegraph.Account - validPage *telegraph.Page validContentDOM []telegraph.Node + validAccount = new(telegraph.Account) + validPage = new(telegraph.Page) validContent = `

Hello, World!

` ) @@ -50,8 +51,8 @@ func testValidContentFormatByBytes(t *testing.T) { func TestValidCreateAccount(t *testing.T) { var err error validAccount, err = telegraph.CreateAccount(&telegraph.Account{ - ShortName: validShortName, - AuthorName: validAuthorName, + ShortName: validShortName, + // AuthorName: validAuthorName, }) if err != nil { t.Error(err.Error()) @@ -117,7 +118,10 @@ func testValidEditPage(t *testing.T) { } func testValidGetAccountInfo(t *testing.T) { - info, err := validAccount.GetAccountInfo(telegraph.FieldShortName, telegraph.FieldPageCount) + info, err := validAccount.GetAccountInfo( + telegraph.FieldShortName, + telegraph.FieldPageCount, + ) if err != nil { t.Error(err.Error()) t.FailNow() @@ -152,15 +156,16 @@ func testValidGetPageList(t *testing.T) { } func TestValidGetViews(t *testing.T) { - stats, err := telegraph.GetViews(validPageURL, 2016, 12, 0, -1) + stats, err := telegraph.GetViews( + validPageURL, + time.Date(2016, time.December, 0, 0, 0, 0, 0, time.UTC), + ) if err != nil { t.Error(err.Error()) t.FailNow() } - if stats.Views <= 0 { - t.Error("get 0 views") - } + t.Log("get", stats.Views, "views") } func testValidRevokeAccessToken(t *testing.T) { diff --git a/types.go b/types.go new file mode 100644 index 0000000..4de8c3f --- /dev/null +++ b/types.go @@ -0,0 +1,138 @@ +// All types used in the Telegraph API responses are represented as JSON-objects. +// Optional fields may be not returned when irrelevant. +package telegraph + +import "errors" + +type ( + // Account represents a Telegraph account. + Account struct { + // Only returned by the createAccount and revokeAccessToken + // method. Access token of the Telegraph account. + AccessToken string `json:"access_token"` // optional + + // URL to authorize a browser on telegra.ph and connect it to a + // Telegraph account. This URL is valid for only one use and for + // 5 minutes only. + AuthURL string `json:"auth_url,omitempty"` // optional + + // Account name, helps users with several accounts remember which + // they are currently using. Displayed to the user above the + // "Edit/Publish" button on Telegra.ph, other users don't see + // this name. + ShortName string `json:"short_name"` + + // Default author name used when creating new articles. + AuthorName string `json:"author_name"` + + // Profile link, opened when users click on the author's name + // below the title. Can be any link, not necessarily to a + // Telegram profile or channel. + AuthorURL string `json:"author_url"` + + // Number of pages belonging to the Telegraph account. + PageCount int `json:"page_count,omitempty"` // optional + } + + // PageList represents a list of Telegraph articles belonging to an + // account. Most recently created articles first. + PageList struct { + // Total number of pages belonging to the target Telegraph + // account. + TotalCount int `json:"total_count"` + + // Requested pages of the target Telegraph account. + Pages []Page `json:"pages"` + } + + // Page represents a page on Telegraph. + Page struct { + // Path to the page. + Path string `json:"path"` + + // URL of the page. + URL string `json:"url"` + + // Title of the page. + Title string `json:"title"` + + // Description of the page. + Description string `json:"description"` + + // Name of the author, displayed below the title. + AuthorName string `json:"author_name,omitempty"` // optional + + // Profile link, opened when users click on the author's name + // below the title. Can be any link, not necessarily to a + // Telegram profile or channel. + AuthorURL string `json:"author_url,omitempty"` // optional + + // Image URL of the page. + ImageURL string `json:"image_url,omitempty"` // optional + + // Content of the page. + Content []Node `json:"content,omitempty"` // optional + + // Number of page views for the page. + Views int `json:"views"` + + // Only returned if access_token passed. True, if the target + // Telegraph account can edit the page. + CanEdit bool `json:"can_edit,omitempty"` // optional + } + + // PageViews represents the number of page views for a Telegraph article. + PageViews struct { + // Number of page views for the target page. + Views int `json:"views"` + } + + // Node is abstract object represents a DOM Node. It can be a String + // which represents a DOM text node or a NodeElement object. + Node interface{} + + // NodeElement represents a DOM element node. + NodeElement struct { + // Name of the DOM element. + // Available tags: a, aside, b, blockquote, br, code, em, + // figcaption, figure, h3, h4, hr, i, iframe, img, li, ol, p, + // pre, s, strong, u, ul, video. + Tag string `json:"tag"` + + // Attributes of the DOM element. Key of object represents name + // of attribute, value represents value of attribute. + // Available attributes: href, src. + Attrs map[string]string `json:"attrs,omitempty"` // optional + + // List of child nodes for the DOM element. + Children []Node `json:"children,omitempty"` // optional + } +) + +const ( + // FieldShortName used as GetAccountInfo argument for getting account name. + FieldShortName = "short_name" + + // FieldAuthorName used as GetAccountInfo argument for getting author name. + FieldAuthorName = "author_name" + + // FieldAuthorURL used as GetAccountInfo argument for getting profile link. + FieldAuthorURL = "author_url" + + // FieldAuthURL used as GetAccountInfo argument for getting URL to authorize + // a browser on telegra.ph. + FieldAuthURL = "auth_url" + + // FieldPageCount used as GetAccountInfo argument for getting number of pages + // belonging to the Telegraph account. + FieldPageCount = "page_count" +) + +var ( + // ErrInvalidDataType is returned when ContentFormat function are passed + // a data argument of invalid type. + ErrInvalidDataType = errors.New("invalid data type") + + // ErrNoInputData is returned when any method get nil argument. + ErrNoInputData = errors.New("no input data") +)