♻️ Package refactor

This commit is contained in:
Maxim Lebedev 2018-07-27 16:51:14 +05:00
parent fe6abc89bc
commit 5112c12848
No known key found for this signature in database
GPG Key ID: F8978F46FF0FFA4F
16 changed files with 409 additions and 368 deletions

32
Makefile Normal file
View File

@ -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}'

View File

@ -2,69 +2,38 @@ package telegraph
import ( import (
"bytes" "bytes"
"errors"
"io" "io"
"strings" "strings"
"golang.org/x/net/html" "golang.org/x/net/html"
) )
type ( // ContentFormat transforms data to a DOM-based format to represent the content
// Node is abstract object represents a DOM Node. It can be a String which represents a DOM text // of the page.
// node or a NodeElement object. func ContentFormat(data interface{}) (n []Node, err error) {
Node interface{} dst := new(html.Node)
switch src := data.(type) {
// 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) {
case string: case string:
dom, err := html.Parse(strings.NewReader(dst)) dst, err = html.Parse(strings.NewReader(src))
if err != nil { if err != nil {
return nil, err return nil, err
} }
doc = *dom
case []byte: case []byte:
dom, err := html.Parse(bytes.NewReader(dst)) dst, err = html.Parse(bytes.NewReader(src))
if err != nil { if err != nil {
return nil, err return nil, err
} }
doc = *dom
case io.Reader: case io.Reader:
dom, err := html.Parse(dst) dst, err = html.Parse(src)
if err != nil { if err != nil {
return nil, err return nil, err
} }
doc = *dom
default: default:
return nil, ErrInvalidDataType return nil, ErrInvalidDataType
} }
var content []Node n = append(n, domToNode(dst.FirstChild))
content = append(content, domToNode(doc.FirstChild)) return
return content, nil
} }
func domToNode(domNode *html.Node) interface{} { func domToNode(domNode *html.Node) interface{} {
@ -78,8 +47,9 @@ func domToNode(domNode *html.Node) interface{} {
var nodeElement NodeElement var nodeElement NodeElement
switch strings.ToLower(domNode.Data) { switch strings.ToLower(domNode.Data) {
case "a", "aside", "b", "blockquote", "br", "code", "em", "figcaption", "figure", "h3", "h4", case "a", "aside", "b", "blockquote", "br", "code", "em", "figcaption",
"hr", "i", "iframe", "img", "li", "ol", "p", "pre", "s", "strong", "u", "ul", "video": "figure", "h3", "h4", "hr", "i", "iframe", "img", "li", "ol",
"p", "pre", "s", "strong", "u", "ul", "video":
nodeElement.Tag = domNode.Data nodeElement.Tag = domNode.Data
for i := range domNode.Attr { for i := range domNode.Attr {

View File

@ -5,58 +5,29 @@ import (
http "github.com/valyala/fasthttp" http "github.com/valyala/fasthttp"
) )
// Account represents a Telegraph account. // CreateAccount create a new Telegraph account. Most users only need one
type Account struct { // account, but this can be useful for channel administrators who would like to
// Only returned by the createAccount and revokeAccessToken method. Access token // keep individual author names and profile links for each of their channels. On
// of the Telegraph account. // success, returns an Account object with the regular fields and an additional
AccessToken string `json:"access_token"` // optional // access_token field.
func CreateAccount(account *Account) (r *Account, err error) {
// URL to authorize a browser on telegra.ph and connect it to a Telegraph if account == nil {
// account. This URL is valid for only one use and for 5 minutes only. return nil, ErrNoInputData
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
} }
var resp Account args := http.AcquireArgs()
err = json.Unmarshal(*body.Result, &resp) 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
} }

View File

@ -7,80 +7,34 @@ import (
http "github.com/valyala/fasthttp" 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. // 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() args := http.AcquireArgs()
defer http.ReleaseArgs(args)
// Access token of the Telegraph account. args.Add("access_token", a.AccessToken) // required
args.Add("access_token", account.AccessToken) // required args.Add("title", page.Title) // required
args.Add("author_name", a.AuthorName)
// Page title. args.Add("author_url", a.AuthorURL)
args.Add("title", page.Title) // required args.Add("content", string(src))
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.
args.Add("return_content", strconv.FormatBool(returnContent)) args.Add("return_content", strconv.FormatBool(returnContent))
content, err := json.Marshal(page.Content) dst := new(Response)
dst, err = makeRequest("createPage", args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Content of the page. r = new(Page)
args.Add("content", string(content)) // required err = json.Unmarshal(*dst.Result, r)
return
body, err := request("createPage", "", args)
if err != nil {
return nil, err
}
var resp Page
err = json.Unmarshal(*body.Result, &resp)
return &resp, err
} }

View File

@ -5,31 +5,28 @@ import (
http "github.com/valyala/fasthttp" http "github.com/valyala/fasthttp"
) )
// EditAccountInfo update information about a Telegraph account. Pass only the parameters that you // EditAccountInfo update information about a Telegraph account. Pass only the
// want to edit. On success, returns an Account object with the default fields. // parameters that you want to edit. On success, returns an Account object with
func (account *Account) EditAccountInfo(update *Account) (*Account, error) { // the default fields.
func (a *Account) EditAccountInfo(update *Account) (r *Account, err error) {
if update == nil {
return nil, ErrNoInputData
}
args := http.AcquireArgs() args := http.AcquireArgs()
defer http.ReleaseArgs(args)
// Access token of the Telegraph account. args.Add("access_token", a.AccessToken) // required
args.Add("access_token", account.AccessToken) // required
// New account name.
args.Add("short_name", update.ShortName) args.Add("short_name", update.ShortName)
// New default author name used when creating new articles.
args.Add("author_name", update.AuthorName) 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) args.Add("author_url", update.AuthorURL)
body, err := request("editAccountInfo", "", args) dst := new(Response)
dst, err = makeRequest("editAccountInfo", args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var resp Account r = new(Account)
err = json.Unmarshal(*body.Result, &resp) err = json.Unmarshal(*dst.Result, r)
return
return &resp, err
} }

View File

@ -1,6 +1,7 @@
package telegraph package telegraph
import ( import (
"path"
"strconv" "strconv"
json "github.com/pquerna/ffjson/ffjson" json "github.com/pquerna/ffjson/ffjson"
@ -8,44 +9,34 @@ import (
) )
// EditPage edit an existing Telegraph page. On success, returns a Page object. // 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() args := http.AcquireArgs()
defer http.ReleaseArgs(args)
// Access token of the Telegraph account. args.Add("access_token", a.AccessToken) // required
args.Add("access_token", account.AccessToken) // required args.Add("path", update.Path) // required
args.Add("title", update.Title) // required
// Page title. args.Add("content", string(src)) // required
args.Add("title", update.Title) // required args.Add("author_name", a.AuthorName)
args.Add("author_url", a.AuthorURL)
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.
args.Add("return_content", strconv.FormatBool(returnContent)) 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 { if err != nil {
return nil, err return nil, err
} }
// Content of the page. r = new(Page)
args.Add("content", string(content)) // required err = json.Unmarshal(*dst.Result, r)
return
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
} }

View File

@ -2,8 +2,9 @@ package telegraph_test
import ( import (
"log" "log"
"time"
"github.com/toby3d/telegraph" "gitlab.com/toby3d/telegraph"
) )
// Content in a string format (for this example). // Content in a string format (for this example).
@ -22,8 +23,8 @@ const data = `
` `
var ( var (
account *telegraph.Account account = new(telegraph.Account)
page *telegraph.Page page = new(telegraph.Page)
content []telegraph.Node content []telegraph.Node
) )
@ -168,7 +169,10 @@ func ExampleAccount_GetPageList() {
func ExampleGetViews() { func ExampleGetViews() {
pagePath := "Sample-Page-12-15" 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) errCheck(err)
log.Println(pagePath, "has been viewed", views.Views, "times") log.Println(pagePath, "has been viewed", views.Views, "times")

View File

@ -1,50 +1,26 @@
package telegraph package telegraph
import ( import (
"fmt"
"strings" "strings"
json "github.com/pquerna/ffjson/ffjson" json "github.com/pquerna/ffjson/ffjson"
http "github.com/valyala/fasthttp" 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. // 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() 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. dst := new(Response)
args.Add("access_token", account.AccessToken) // required dst, err = makeRequest("getAccountInfo", args)
// 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)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var resp Account r = new(Account)
err = json.Unmarshal(*body.Result, &resp) err = json.Unmarshal(*dst.Result, r)
return
return &resp, err
} }

View File

@ -1,6 +1,7 @@
package telegraph package telegraph
import ( import (
gopath "path"
"strconv" "strconv"
json "github.com/pquerna/ffjson/ffjson" json "github.com/pquerna/ffjson/ffjson"
@ -8,19 +9,19 @@ import (
) )
// GetPage get a Telegraph page. Returns a Page object on success. // 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() args := http.AcquireArgs()
defer http.ReleaseArgs(args)
// If true, content field will be returned in Page object. args.Add("path", path) // required
args.Add("return_content", strconv.FormatBool(returnContent)) 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 { if err != nil {
return nil, err return nil, err
} }
var resp Page r = new(Page)
err = json.Unmarshal(*body.Result, &resp) err = json.Unmarshal(*dst.Result, r)
return
return &resp, err
} }

View File

@ -7,37 +7,22 @@ import (
http "github.com/valyala/fasthttp" 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 // GetPageList get a list of pages belonging to a Telegraph account. Returns a PageList object, sorted
// by most recently created pages first. // 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() args := http.AcquireArgs()
defer http.ReleaseArgs(args)
// Access token of the Telegraph account. args.Add("access_token", a.AccessToken) // required
args.Add("access_token", account.AccessToken) // required
// Sequential number of the first page to be returned.
args.Add("offset", strconv.Itoa(offset)) args.Add("offset", strconv.Itoa(offset))
// Limits the number of pages to be retrieved.
args.Add("limit", strconv.Itoa(limit)) args.Add("limit", strconv.Itoa(limit))
body, err := request("getPageList", "", args) dst := new(Response)
dst, err = makeRequest("getPageList", args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var resp PageList r = new(PageList)
err = json.Unmarshal(*body.Result, &resp) err = json.Unmarshal(*dst.Result, r)
return
return &resp, err
} }

View File

@ -1,53 +1,32 @@
package telegraph package telegraph
import ( import (
gopath "path"
"strconv" "strconv"
"time"
json "github.com/pquerna/ffjson/ffjson" json "github.com/pquerna/ffjson/ffjson"
http "github.com/valyala/fasthttp" 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 // 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. // 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() 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 { dst := new(Response)
// If passed, the number of page views for the requested hour will be returned. dst, err = makeRequest(gopath.Join("getViews", path), args)
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)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var resp PageViews r = new(PageViews)
err = json.Unmarshal(*body.Result, &resp) err = json.Unmarshal(*dst.Result, r)
return
return &resp, err
} }

View File

@ -3,48 +3,63 @@ package telegraph
import ( import (
gojson "encoding/json" gojson "encoding/json"
"errors" "errors"
"fmt"
"net/url" "net/url"
"github.com/kirillDanshin/dlog"
json "github.com/pquerna/ffjson/ffjson" json "github.com/pquerna/ffjson/ffjson"
http "github.com/valyala/fasthttp" http "github.com/valyala/fasthttp"
) )
// response represents a response from the Telegram API with the result stored raw. If ok equals true, // Response contains a JSON object, which always has a Boolean field ok. If ok
// the request was successful, and the result of the query can be found in the result field. In case of // equals true, the request was successful, and the result of the query can be
// an unsuccessful request, ok equals false, and the error is explained in the error field (e.g. // 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). // SHORT_NAME_REQUIRED).
type response struct { type Response struct {
Ok bool `json:"ok"` Ok bool `json:"ok"`
Error string `json:"error"` 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) { var defaultURL = url.URL{
defer http.ReleaseArgs(args) Scheme: "https",
requestURI := &url.URL{ Host: "api.telegra.ph",
Scheme: "https", }
Host: "api.telegra.ph",
Path: method,
}
if path != "" { func makeRequest(path string, args *http.Args) (r *Response, err error) {
requestURI.Path += fmt.Sprint("/", path) 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 { if err != nil {
return nil, err dlog.Ln(err.Error())
return
} }
var resp response dlog.Ln("response:")
if err := json.Unmarshal(body, &resp); err != nil { dlog.D(resp)
return nil, err
r = new(Response)
if err = json.Unmarshal(resp.Body(), r); err != nil {
return
} }
if !resp.Ok { if !r.Ok {
return nil, errors.New(resp.Error) err = errors.New(r.Error)
} }
return &resp, nil return
} }

View File

@ -5,22 +5,26 @@ import (
http "github.com/valyala/fasthttp" 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 // 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 // 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. // 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() args := http.AcquireArgs()
defer http.ReleaseArgs(args)
args.Add("access_token", a.AccessToken)
// Access token of the Telegraph account. dst := new(Response)
args.Add("access_token", account.AccessToken) // required dst, err = makeRequest("revokeAccessToken", args)
body, err := request("revokeAccessToken", "", args)
if err != nil { if err != nil {
return nil, err return
} }
var resp Account r = new(Account)
err = json.Unmarshal(*body.Result, &resp) err = json.Unmarshal(*dst.Result, r)
return
return &resp, err
} }

View File

@ -2,8 +2,9 @@ package telegraph_test
import ( import (
"testing" "testing"
"time"
"github.com/toby3d/telegraph" "gitlab.com/toby3d/telegraph"
) )
const ( const (
@ -12,7 +13,7 @@ const (
invalidContent = 42 invalidContent = 42
) )
var invalidAccount = &telegraph.Account{} var invalidAccount = new(telegraph.Account)
func TestInvalidContentFormat(t *testing.T) { func TestInvalidContentFormat(t *testing.T) {
if _, err := telegraph.ContentFormat(invalidContent); err != telegraph.ErrInvalidDataType { if _, err := telegraph.ContentFormat(invalidContent); err != telegraph.ErrInvalidDataType {
@ -60,7 +61,10 @@ func testInvalidEditPage(t *testing.T) {
} }
func testInvalidGetAccountInfo(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() t.Error()
} }
} }
@ -90,31 +94,46 @@ func TestInvalidGetPage(t *testing.T) {
} }
func TestInvalidGetViewsByPage(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() t.Error()
} }
} }
func TestInvalidGetViewsByHour(t *testing.T) { 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() t.Error()
} }
} }
func TestInvalidGetViewsByDay(t *testing.T) { 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() t.Error()
} }
} }
func TestInvalidGetViewsByMonth(t *testing.T) { 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() t.Error()
} }
} }
func TestInvalidGetViewsByYear(t *testing.T) { 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() t.Error()
} }
} }

View File

@ -2,8 +2,9 @@ package telegraph_test
import ( import (
"testing" "testing"
"time"
"github.com/toby3d/telegraph" "gitlab.com/toby3d/telegraph"
) )
const ( const (
@ -16,10 +17,10 @@ const (
) )
var ( var (
validAccount *telegraph.Account
validPage *telegraph.Page
validContentDOM []telegraph.Node validContentDOM []telegraph.Node
validAccount = new(telegraph.Account)
validPage = new(telegraph.Page)
validContent = `<p>Hello, World!</p>` validContent = `<p>Hello, World!</p>`
) )
@ -50,8 +51,8 @@ func testValidContentFormatByBytes(t *testing.T) {
func TestValidCreateAccount(t *testing.T) { func TestValidCreateAccount(t *testing.T) {
var err error var err error
validAccount, err = telegraph.CreateAccount(&telegraph.Account{ validAccount, err = telegraph.CreateAccount(&telegraph.Account{
ShortName: validShortName, ShortName: validShortName,
AuthorName: validAuthorName, // AuthorName: validAuthorName,
}) })
if err != nil { if err != nil {
t.Error(err.Error()) t.Error(err.Error())
@ -117,7 +118,10 @@ func testValidEditPage(t *testing.T) {
} }
func testValidGetAccountInfo(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 { if err != nil {
t.Error(err.Error()) t.Error(err.Error())
t.FailNow() t.FailNow()
@ -152,15 +156,16 @@ func testValidGetPageList(t *testing.T) {
} }
func TestValidGetViews(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 { if err != nil {
t.Error(err.Error()) t.Error(err.Error())
t.FailNow() t.FailNow()
} }
if stats.Views <= 0 { t.Log("get", stats.Views, "views")
t.Error("get 0 views")
}
} }
func testValidRevokeAccessToken(t *testing.T) { func testValidRevokeAccessToken(t *testing.T) {

138
types.go Normal file
View File

@ -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")
)