From 1a48bad7ab168513bcd2f70985b85b2f62e30d74 Mon Sep 17 00:00:00 2001 From: Leonardo Javier Esparis Meza Date: Tue, 1 Aug 2017 14:56:39 -0400 Subject: [PATCH] First Commit. Gostagram, Unofficial instagram client, created with go programming language. Almost all instagram Endpoints are supported. Version: 1.0.0-alpha1 Go Version: go1.8.3 Operating System: Ubuntu 16.04.2 LTS Arquitecture: amd64 --- .editorconfig | 25 +++++ .gitattributes | 20 ++++ .gitignore | 21 ++++ Gopkg.lock | 45 +++++++++ Gopkg.toml | 30 ++++++ LICENSE.txt | 19 ++++ README.md | 90 +++++++++++++++++ comments.go | 88 ++++++++++++++++ comments_test.go | 52 ++++++++++ instagram.go | 183 ++++++++++++++++++++++++++++++++++ likes.go | 24 +++++ likes_test.go | 42 ++++++++ location.go | 56 +++++++++++ location_test.go | 36 +++++++ media.go | 221 +++++++++++++++++++++++++++++++++++++++++ media_test.go | 232 +++++++++++++++++++++++++++++++++++++++++++ relationship.go | 91 +++++++++++++++++ relationship_test.go | 87 ++++++++++++++++ signature.go | 24 +++++ tags.go | 49 +++++++++ tags_test.go | 33 ++++++ users.go | 96 ++++++++++++++++++ users_test.go | 180 +++++++++++++++++++++++++++++++++ 23 files changed, 1744 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 Gopkg.lock create mode 100644 Gopkg.toml create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 comments.go create mode 100644 comments_test.go create mode 100644 instagram.go create mode 100644 likes.go create mode 100644 likes_test.go create mode 100644 location.go create mode 100644 location_test.go create mode 100644 media.go create mode 100644 media_test.go create mode 100644 relationship.go create mode 100644 relationship_test.go create mode 100644 signature.go create mode 100644 tags.go create mode 100644 tags_test.go create mode 100644 users.go create mode 100644 users_test.go diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..b809561 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,25 @@ +# EditorConfig coding styles definitions. For more information about the +# properties used in this file, please see the EditorConfig documentation: +# http://editorconfig.org/ + +# indicate this is the root of the project +root = true + +[*] +charset = utf-8 + +end_of_line = LF +insert_final_newline = true +trim_trailing_whitespace = true + +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab + +[*.md] +trim_trailing_whitespace = false + +[*.go] +indent_style = tab \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..49b63e5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +# Automatically normalize line endings for all text-based files +# http://git-scm.com/docs/gitattributes#_end_of_line_conversion +* text=auto + +# For the following file types, normalize line endings to LF on checking and +# prevent conversion to CRLF when they are checked out (this is required in +# order to prevent newline related issues) +.* text eol=lf +*.go text eol=lf +*.yml text eol=lf +*.html text eol=lf +*.css text eol=lf +*.js text eol=lf +*.json text eol=lf +LICENSE text eol=lf + +# Exclude `website` and `cookbook` from GitHub's language statistics +# https://github.com/github/linguist#using-gitattributes +cookbook/* linguist-documentation +website/* linguist-documentation diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d29108e --- /dev/null +++ b/.gitignore @@ -0,0 +1,21 @@ +.idea +.DS_Store +coverage.txt +_test +vendor +*.iml + +# Binaries for programs and plugins +*.exe +*.dll +*.so +*.dylib + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Project-local glide cache, RE: https://github.com/Masterminds/glide/issues/736 +.glide/ diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..c972d3d --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,45 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + packages = ["."] + revision = "d0303fe809921458f417bcf828397a65db30a7e4" + +[[projects]] + branch = "master" + name = "github.com/moul/http2curl" + packages = ["."] + revision = "4e24498b31dba4683efb9d35c1c8a91e2eda28c8" + +[[projects]] + name = "github.com/parnurzeal/gorequest" + packages = ["."] + revision = "a578a48e8d6ca8b01a3b18314c43c6716bb5f5a3" + version = "v0.2.15" + +[[projects]] + name = "github.com/pkg/errors" + packages = ["."] + revision = "645ef00459ed84a119197bfb8d8205042c6df63d" + version = "v0.8.0" + +[[projects]] + branch = "master" + name = "golang.org/x/net" + packages = ["idna","publicsuffix"] + revision = "f5079bd7f6f74e23c4d65efa0f4ce14cbd6a3c0f" + +[[projects]] + branch = "master" + name = "golang.org/x/text" + packages = ["internal/gen","internal/triegen","internal/ucd","secure/bidirule","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable"] + revision = "3bd178b88a8180be2df394a1fbb81313916f0e7b" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "78c1ce29bfe11072f0df8bbf318492beb06edb9d34c5c289cfec4c09027a73ff" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..1c4a533 --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,30 @@ + +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + + +[[constraint]] + branch = "master" + name = "github.com/mitchellh/mapstructure" + +[[constraint]] + name = "github.com/parnurzeal/gorequest" + version = "0.2.15" diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..f67e962 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (C) 2017 Leonardo Esparis. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..7cf42b2 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +

+

Gostagram

+

Unofficial and easy to use instagram client for go.

+

+ +--- + +###Quick Start. + +**First step** + +Go to instagram developer [website](https://www.instagram.com/developer/) +and create a developer account, then register a new instagram client. + +**Download and Installation** +```text +go get github.com/leoxnidas/gostagram +``` + +**Usage** + +Basic example, using an client to +consume an instagram endpoint. + +```go +package main + +import ( + "fmt" + "github.com/leoxnidas/gostagram" +) + +func main() { + client := gostagram.NewClient("access_token") + user, err := client.GetCurrentUser() + + if err != nil { + fmt.Println(err) + } else { + fmt.Println(user.Id) + fmt.Println(user.Username) + fmt.Println(user.FullName) + } +} +``` + +If you want to enable instagram signed requests mode +you have to tell gostagram client, that you want to sig +a request. + +```go +package main + +import ( + "fmt" + "github.com/leoxnidas/gostagram" +) + +func main() { + client := gostagram.NewClient("access_token") + client.SetSignedRequest(true) + client.SetClientSecret("client secret") + + + user, err := client.GetCurrentUser() + + if err != nil { + fmt.Println(err) + } else { + fmt.Println(user.Id) + fmt.Println(user.Username) + fmt.Println(user.FullName) + } +} +``` + +###Support us. + * [donate](https://www.paypal.me/leoxnidas). + * [Contribute](https://github.com/leoxnidas/gostagram#contribute). + * Talk about the project. + +###Contribute. +Please use [Github issue tracker](https://github.com/leoxnidas/gostagram/issues) +for everything. + * Report issues. + * Improve/Fix documentation. + * Suggest new features or enhancements. + +###License. +gostagram license [MIT](./LICENSE.txt) diff --git a/comments.go b/comments.go new file mode 100644 index 0000000..bdb3540 --- /dev/null +++ b/comments.go @@ -0,0 +1,88 @@ +package gostagram + +import ( + "fmt" + "errors" + "strings" + "regexp" + + "github.com/mitchellh/mapstructure" +) + +var ( + CommentsUrlExeed = errors.New("Cannot contain more than 1 URL.") + CommentsHashtagExceed = errors.New("Comment cannot contain more than 4 hashtags.") + CommentsMaxLengthExceed = errors.New("Comment cannot exceed 300 characters.") + CommentsCapitalLettersError = errors.New("Comment cannot consist of all capital letters") +) + +var ( + // take this pattern it from + // https://stackoverflow.com/questions/6883049/regex-to-find-urls-in-string-in-python + // to match an url. + urlMatcher = regexp.MustCompile(`http[s]?://(?:[a-zA-Z]|[0-9]|[$-_@.&+]|[!*\(\),]|(?:%[0-9a-fA-F][0-9a-fA-F]))+`) + capitalLetterMatcher = regexp.MustCompile(`[A-Z]`) +) + +type Comment struct { + From User + + Id string + Text string + CreatedTime string `mapstructure:"created_time"` +} + +func (c *Client) GetMediaComments(media_id string) ([]*Comment, error) { + tmp, _, err := c.get(fmt.Sprintf("%smedia/%s/comments?access_token=%s", apiUrl, media_id, c.access_token)) + if err != nil { + return nil, err + } + + tmpComments := (*tmp).([]interface{}) + var comments []*Comment + for _, tmpComment := range tmpComments { + var comment Comment + + if err := mapstructure.Decode(tmpComment, &comment); err != nil { + return nil, err + } + + comments = append(comments, &comment) + } + + return comments, nil +} + +func (c *Client) PostMediaComment(text, media_id string) error { + if len(text) > 300 { + return CommentsMaxLengthExceed + } else if strings.Count(text, "#") > 4 { + return CommentsHashtagExceed + } else if len(urlMatcher.FindAllSubmatch([]byte(text), -1)) > 1 { + return CommentsUrlExeed + } else { + for _, c := range text { + if capitalLetterMatcher.Match([]byte(string(c))) { + return CommentsCapitalLettersError + } + } + } + + _, err := c.post(fmt.Sprintf("%smedia/%s/comments?access_token=%s", apiUrl, media_id, c.access_token), BodyData{ + "text": text, + }) + + if err != nil { + return err + } + + return nil +} + +func (c *Client) DeleteMediaComment(media_id, comment_id string) error { + _, err := c.delete(fmt.Sprintf("%smedia/%s/comments/%s?access_token=%s", apiUrl, media_id, comment_id, c.access_token)) + if err != nil { + return err + } + return nil +} diff --git a/comments_test.go b/comments_test.go new file mode 100644 index 0000000..307bd1a --- /dev/null +++ b/comments_test.go @@ -0,0 +1,52 @@ +package gostagram + +import ( + "testing" +) + +func TestClient_GetMediaComments(t *testing.T) { + client := CreateClient(t) + + comments, err := client.GetMediaComments("1499806890266583125_2451237325") + + if err != nil { + t.Fatal(err) + } + + if len(comments) > 0 { + for _, comment := range comments { + t.Log("------------------ Start Comment ------------------") + t.Log("Id: ", DefaultStringValueIfEmpty(comment.Id)) + t.Log("Text: ", DefaultStringValueIfEmpty(comment.Text)) + t.Log("Created Time: ", DefaultStringValueIfEmpty(comment.CreatedTime)) + t.Log("------------------ Start User Comment ------------------") + LogUser(&comment.From, t) + t.Log("------------------ End User Comment ------------------") + t.Log("------------------ End Comment ------------------") + } + } else { + t.Log("no comments.") + } +} + +func TestClient_PostMediaComment(t *testing.T) { + client := CreateClient(t) + err := client.PostMediaComment("api text", "1499806890266583125_2451237325") + if err != nil { + t.Fatal(err) + } else { + t.Log("Comment posted.!") + } +} + +func TestClient_DeleteMediaComment(t *testing.T) { + client := CreateClient(t) + + err := client.DeleteMediaComment("1499806890266583125_2451237325", "17876627794082799") + + if err != nil { + t.Fatal(err) + } else { + t.Log("Comment deleted.") + } +} diff --git a/instagram.go b/instagram.go new file mode 100644 index 0000000..2accf81 --- /dev/null +++ b/instagram.go @@ -0,0 +1,183 @@ +package gostagram + +import ( + "fmt" + "errors" + "encoding/json" + url2 "net/url" + "strings" + + "github.com/parnurzeal/gorequest" +) + +const ( + apiUrl = "https://api.instagram.com/v1/" + version = "1.0.0-alpha1" + userAgent = "gostagram/v1" +) + +type Params map[string]string +type BodyData map[string]interface{} +type Response map[string]interface{} + +type Client struct { + clientSecret string + access_token string + + sandboxMode bool + signedRequest bool +} + +func NewClient(access_token string) *Client { + return &Client{ + clientSecret: "", + access_token: access_token, + signedRequest: false, + sandboxMode: false, + } +} + +func (c *Client) Version() string { + return version +} + +func (c *Client) SetClientSecret(cs string) { + c.clientSecret = cs +} + +func (c *Client) SetSignedRequest(sr bool) { + c.signedRequest = sr +} + +func (c *Client) SetSandboxMode(sm bool) { + c.sandboxMode = sm +} + +func (c *Client) newRequest(method, uri string, response *Response, dataToSend ...BodyData) error { + if c.signedRequest && len(c.clientSecret) == 0 { + return errors.New("Client secret not set.") + } else if c.signedRequest { + + tmpUrl, err := url2.Parse(uri) + + if err != nil { + return err + } + + endpoint := strings.Replace(tmpUrl.EscapedPath(), "/v1", "", 1) + + if endpoint[len(endpoint) - 1] == '/' { + endpoint = endpoint[0:len(endpoint) - 1] + } + + params := make(Params) + for paramName, paramValue := range tmpUrl.Query() { + params[paramName] = paramValue[0] + } + + sig, err := c.generateSignature(endpoint, params) + + if err != nil { + return err + } + + uri = uri + "&sig=" + sig + } + + request := gorequest.New().Set("User-Agent", userAgent) + + switch method { + case gorequest.POST: + request = request.Post(uri).Type("multipart") + + if dataToSend != nil && len(dataToSend) > 0 { + request = request.SendMap(dataToSend[0]) + } + + break + case gorequest.GET: + request = request.Get(uri).Type("json") + break + case gorequest.DELETE: + request = request.Delete(uri).Type("json") + break + } + + _, body, errs := request.EndBytes() + json.Unmarshal(body, &response) + + if len(errs) > 0 { + return errs[0] + } + + if len(*response) > 0 { + var code int + var errorType, errorMessage string + + if (*response)["meta"] != nil { + meta := (*response)["meta"].(map[string]interface{}) + code = int(meta["code"].(float64)) + + if code != 200 { + errorType = meta["error_type"].(string) + errorMessage = meta["error_message"].(string) + } else { + errorType = "" + errorMessage = "" + } + } else { + code = int((*response)["code"].(float64)) + errorType = (*response)["error_type"].(string) + errorMessage = (*response)["error_message"].(string) + } + + if code != 200 { + return errors.New(fmt.Sprintf("[%s]: %s", errorType, errorMessage)) + } + } else { + return errors.New("Wrong endpoint.") + } + + return nil +} + +func (c *Client) get(url string) (*interface{}, *interface{}, error) { + var response Response + err := c.newRequest(gorequest.GET, url, &response) + + if err != nil { + return nil, nil, err + } + + tmp := response["data"] + tmpPagination := response["pagination"] + if tmpPagination != nil { + return &tmp, nil, nil + } + + return &tmp, &tmpPagination, nil +} + +func (c *Client) post(url string, dataToSend BodyData) (*interface{}, error) { + var response Response + err := c.newRequest(gorequest.POST, url, &response, dataToSend) + + if err != nil { + return nil, err + } + + tmp := response["data"] + return &tmp, nil +} + +func (c *Client) delete(url string) (*interface{}, error) { + var response Response + err := c.newRequest(gorequest.DELETE, url, &response) + + if err != nil { + return nil, err + } + + tmp := response["data"] + return &tmp, nil +} diff --git a/likes.go b/likes.go new file mode 100644 index 0000000..9971446 --- /dev/null +++ b/likes.go @@ -0,0 +1,24 @@ +package gostagram + +import "fmt" + +func (c *Client) GetMediaLikes(media_id string) ([]*User, error) { + return c.getUsers(fmt.Sprintf("%smedia/%s/likes?access_token=%s", apiUrl, media_id, c.access_token)) +} + +func (c *Client) PostMediaLike(media_id string) error { + _, err := c.post(fmt.Sprintf("%smedia/%s/likes?access_token=%s", apiUrl, media_id, c.access_token), nil) + if err != nil { + return err + } + + return nil +} + +func (c *Client) DeleteMediaLike(media_id string) error { + _, err := c.delete(fmt.Sprintf("%smedia/%s/likes?access_token=%s", apiUrl, media_id, c.access_token)) + if err != nil { + return err + } + return nil +} diff --git a/likes_test.go b/likes_test.go new file mode 100644 index 0000000..e3eeb69 --- /dev/null +++ b/likes_test.go @@ -0,0 +1,42 @@ +package gostagram + +import "testing" + +func TestClient_GetMediaLikes(t *testing.T) { + client := CreateClient(t) + users, err := client.GetMediaLikes("1499806890266583125_2451237325") + + if err != nil { + t.Fatal(err) + } + + if len(users) > 0 { + for _, user := range users { + t.Log("------------------ Start User ------------------") + LogUser(user, t) + t.Log("------------------ End User ------------------") + } + } else { + t.Log("Not found any user.!") + } +} + +func TestClient_PostMediaLike(t *testing.T) { + client := CreateClient(t) + err := client.PostMediaLike("1499806890266583125_2451237325") + if err != nil { + t.Fatal(err) + } + + t.Log("media photo liked.") +} + +func TestClient_DeleteMediaLike(t *testing.T) { + client := CreateClient(t) + err := client.DeleteMediaLike("1499806890266583125_2451237325") + if err != nil { + t.Fatal(err) + } + + t.Log("media photo disliked.") +} \ No newline at end of file diff --git a/location.go b/location.go new file mode 100644 index 0000000..11d8108 --- /dev/null +++ b/location.go @@ -0,0 +1,56 @@ +package gostagram + +import ( + "fmt" + "github.com/mitchellh/mapstructure" +) + +type Location struct { + Id string + Name string + Latitude float64 + Longitude float64 +} + +func (c *Client) GetLocationById(location_id string) (*Location, error) { + tmp, _, err := c.get(fmt.Sprintf("%slocations/%s?access_token=%s", apiUrl, location_id, c.access_token)) + if err != nil { + return nil, err + } + + tmpLocation := (*tmp).(map[string]interface{}) + var location Location + if err = mapstructure.Decode(tmpLocation, &location); err != nil { + return nil, err + } + + return &location, nil +} + +func GetLocationOfRecentMedia(max_id, min_id int, access_token string) { + +} + +func (c *Client) SearchLocations(latitude, longitude, distance, facebook_places_id string) ([]*Location, error) { + tmp, _, err := c.get(fmt.Sprintf("%slocations/search?lat=%s&lng=%s&distance=%s&facebook_places_id=%s&access_token=%s", + apiUrl, latitude, longitude, distance, facebook_places_id, c.access_token)) + + if err != nil { + return nil, err + } + + tmpLocations := (*tmp).([]interface{}) + + var locations []*Location + for _, tmplocation := range tmpLocations { + var location Location + + if err := mapstructure.Decode(tmplocation, &location); err != nil { + return nil, err + } + + locations = append(locations, &location) + } + + return locations, nil +} diff --git a/location_test.go b/location_test.go new file mode 100644 index 0000000..1b2489d --- /dev/null +++ b/location_test.go @@ -0,0 +1,36 @@ +package gostagram + +import "testing" + +func TestClient_GetLocationById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.GetLocationById("1898148680457787") + + if err != nil { + t.Fatal(err) + } + + t.Log(tmp.Name) + t.Log(tmp.Id) + t.Log(tmp.Longitude) + t.Log(tmp.Latitude) +} + +func TestClient_SearchLocations(t *testing.T) { + client := CreateClient(t) + tmp, err := client.SearchLocations("12.12", "23.1", "12312", "12312") + + if err != nil { + t.Fatal(err) + } + + for _, location := range tmp { + t.Log("------------------ Start Location ------------------") + t.Log(location.Name) + t.Log(location.Id) + t.Log(location.Longitude) + t.Log(location.Latitude) + t.Log("------------------ End Location ------------------") + } + +} diff --git a/media.go b/media.go new file mode 100644 index 0000000..ea47f90 --- /dev/null +++ b/media.go @@ -0,0 +1,221 @@ +package gostagram + +import ( + "fmt" + + "github.com/mitchellh/mapstructure" +) + +type MediaType uint8 + +func (mt MediaType) IsImage() bool { + return mt == imageMediaType +} + +func (mt MediaType) IsVideo() bool { + return mt == videoMediaType +} + +func (mt MediaType) IsCarousel() bool { + return mt == videoMediaType +} + +const ( + imageMediaType MediaType = 1 + videoMediaType MediaType = 2 + carouselMediaType MediaType = 3 +) + +type Media interface { + MediaType() MediaType +} + +type Image struct { + Url string + Width int + Height int +} + +type VideoResolution struct { + Url string + Width int + Height int +} + +type BaseMediaResource struct { + Id string + Type string + Link string + Filter string + CreatedTime string `mapstructure:"created_time"` + + User User + UserHasLiked bool `mapstructure:"user_has_liked"` + Attribution interface{} + Tags []interface{} + + UserInPhoto []struct { + User User + + Position struct { + X float64 + Y float64 + } + } `mapstructure:"user_in_photo"` + + Comments struct { + Count int + } + + Caption struct { + From User + Id string + Text string + CreatedTime string + } + + Likes struct { + Count int + } + + Images struct { + Thumbnail Image + LowResolution Image `mapstructure:"low_resolution"` + StandardResolution Image `mapstructure:"standard_resolution"` + } + + Location struct { + Id string + Name string + Latitude float64 + Longitude float64 + StreetAddress string `mapstructure:"street_address"` + } +} + +type MediaImage struct { + BaseMediaResource `mapstructure:",squash"` +} + +func (mi MediaImage) MediaType() MediaType { + return imageMediaType +} + +type MediaVideo struct { + BaseMediaResource `mapstructure:",squash"` + + Videos struct { + LowResolution VideoResolution `mapstructure:"low_resolution"` + StandardResolution VideoResolution `mapstructure:"standard_resolution"` + } +} + +func (mi MediaVideo) MediaType() MediaType { + return videoMediaType +} + +type MediaCarousel struct { + BaseMediaResource `mapstructure:",squash"` + + CarouselMedia []struct{} +} + +func (mi MediaCarousel) MediaType() MediaType { + return carouselMediaType +} + +func (c *Client) getMedia(uri string) ([]*Media, error) { + tmp, _, err := c.get(uri) + + if err != nil { + return nil, err + } + + var tmpMediaArray []interface{} + switch (*tmp).(type) { + case []interface{}: + tmpMediaArray = (*tmp).([]interface{}) + break + case map[string]interface{}: + tmpMediaArray = append(tmpMediaArray, (*tmp).(map[string]interface{})) + break + } + + var media_array []*Media + for _, tmpMedia := range tmpMediaArray { + tmp := tmpMedia.(map[string]interface{}) + mediaType := tmp["type"].(string) + if mediaType == "image" { + if tmp["carousel_media"] != nil { + + } else { + var media MediaImage + + if err := mapstructure.Decode(tmpMedia, &media); err != nil { + return nil, err + } + + tt := Media(media) + media_array = append(media_array, &tt) + } + } else if mediaType == "video" { + var media MediaVideo + + if err := mapstructure.Decode(tmpMedia, &media); err != nil { + return nil, err + } + + tt := Media(media) + media_array = append(media_array, &tt) + } + } + + return media_array, nil +} + +func (c *Client) getOnlyOneMediaContent(uri string) (*Media, error) { + media, err := c.getMedia(uri) + if err != nil { + return nil, err + } + + return media[0], nil +} + +func (c *Client) GetCurrentUserRecentMedia(max, min, count int) ([]*Media, error) { + return c.getMedia(fmt.Sprintf("%susers/self/media/recent/?max_id=%d&min_id=%d&count=%d&access_token=%s", + apiUrl, max, min, count, c.access_token, + )) +} + +func (c *Client) GetUserMedia(user_id string, max, min, count int, ) ([]*Media, error) { + return c.getMedia(fmt.Sprintf("%susers/%s/media/recent/?max_id=%d&min_id=%d&count=%d&access_token=%s", + apiUrl, user_id, max, min, count, c.access_token, + )) +} + +func (c *Client) GetCurrentUserMediaLiked(max_like_id string, count int) ([]*Media, error) { + return c.getMedia(fmt.Sprintf("%susers/self/media/liked?max_like_id=%s&count=%d&access_token=%s", + apiUrl, max_like_id, count, c.access_token, + )) +} + +func (c *Client) GetMediaById(media_id string) (*Media, error) { + return c.getOnlyOneMediaContent(fmt.Sprintf("%smedia/%s?access_token=%s", apiUrl, media_id, c.access_token)) +} + +func (c *Client) GetMediaByShortcode(short_code string) (*Media, error) { + return c.getOnlyOneMediaContent(fmt.Sprintf("%smedia/shortcode/%s?access_token=%s", apiUrl, short_code, c.access_token)) +} + +func (c *Client) SearchMedia(lat, long float64) ([]*Media, error) { + return c.getMedia(fmt.Sprintf("%smedia/search?lat=%f&lng=%f&access_token=%s", apiUrl, lat, long, c.access_token)) +} + +func (c *Client) GetRecentMediaTaggedByTagName(tagname string) ([]*Media, error) { + return c.getMedia(fmt.Sprintf("%stags/%s/media/recent?access_token=%s", apiUrl, tagname, c.access_token)) +} + +func (c *Client) GetRecentMediaLocation(location_id string) ([]*Media, error) { + return c.getMedia(fmt.Sprintf("%slocations/%s/media/recent?access_token=%s", apiUrl, location_id, c.access_token)) +} diff --git a/media_test.go b/media_test.go new file mode 100644 index 0000000..dde715f --- /dev/null +++ b/media_test.go @@ -0,0 +1,232 @@ +package gostagram + +import "testing" + +func LogMedia(media *Media, t *testing.T) { + if (*media).MediaType().IsImage() { + mediaImage := (*media).(MediaImage) + + t.Log("------------------ Start Image Media ------------------") + t.Log("Id: ", DefaultStringValueIfEmpty(mediaImage.Id)) + t.Log("Type: ", DefaultStringValueIfEmpty(mediaImage.Type)) + t.Log("Link: ", DefaultStringValueIfEmpty(mediaImage.Link)) + t.Log("Filter: ", DefaultStringValueIfEmpty(mediaImage.Filter)) + t.Log("Created Time: ", DefaultStringValueIfEmpty(mediaImage.CreatedTime)) + + t.Log("------------------ Media Start User ------------------") + LogUser(&mediaImage.User, t) + t.Log("------------------ Media End User ------------------") + + t.Log("User Has Liked: ", mediaImage.UserHasLiked) + t.Log("Attribution: ", mediaImage.Attribution) + t.Log("Tags: ", mediaImage.Tags) + + t.Log("User in Photo: ") + for _, tmp := range mediaImage.UserInPhoto { + t.Log("User in Photo User: ") + LogUser(&tmp.User, t) + t.Log("User In Photo Position X: ", tmp.Position.X) + t.Log("User In Photo Position Y: ", tmp.Position.Y) + } + + t.Log("Comments Count: ", mediaImage.Comments.Count) + t.Log("Caption Id: ", DefaultStringValueIfEmpty(mediaImage.Caption.Id)) + t.Log("Caption Created Time: ", DefaultStringValueIfEmpty(mediaImage.Caption.CreatedTime)) + t.Log("Caption Created Text: ", DefaultStringValueIfEmpty(mediaImage.Caption.Text)) + t.Log("Caption User: ") + LogUser(&mediaImage.Caption.From, t) + t.Log("Likes Count: : ", mediaImage.Likes.Count) + + t.Log("------------------ Start Thumbnail Videos ------------------") + LogImage(&mediaImage.Images.Thumbnail, t) + t.Log("------------------ End Thumbnail Videos ------------------") + + t.Log("------------------ Start Low Resolution Image ------------------") + LogImage(&mediaImage.Images.LowResolution, t) + t.Log("------------------ End Low Resolution Image ------------------") + + t.Log("------------------ Start Standard Resolution Image ------------------") + LogImage(&mediaImage.Images.StandardResolution, t) + t.Log("------------------ End Standard Resolution Image ------------------") + + t.Log("Location Id: ", DefaultStringValueIfEmpty(mediaImage.Location.Id)) + t.Log("Location Name: ", DefaultStringValueIfEmpty(mediaImage.Location.Name)) + t.Log("Location Latitude: ", mediaImage.Location.Latitude) + t.Log("Location Longitude: ", mediaImage.Location.Longitude) + t.Log("Location Street Address: ", DefaultStringValueIfEmpty(mediaImage.Location.StreetAddress)) + + t.Log("------------------ End Image Media ------------------") + + } else if (*media).MediaType().IsVideo() { + mediaVideo := (*media).(MediaVideo) + + t.Log("------------------ Start Video Media ------------------") + t.Log("Id: ", DefaultStringValueIfEmpty(mediaVideo.Id)) + t.Log("Type: ", DefaultStringValueIfEmpty(mediaVideo.Type)) + t.Log("Link: ", DefaultStringValueIfEmpty(mediaVideo.Link)) + t.Log("Filter: ", DefaultStringValueIfEmpty(mediaVideo.Filter)) + t.Log("Created Time: ", DefaultStringValueIfEmpty(mediaVideo.CreatedTime)) + + t.Log("------------------ Media Start User ------------------") + LogUser(&mediaVideo.User, t) + t.Log("------------------ Media End User ------------------") + + t.Log("User Has Liked: ", mediaVideo.UserHasLiked) + t.Log("Attribution: ", mediaVideo.Attribution) + t.Log("Tags: ", mediaVideo.Tags) + + t.Log("User in Photo: ") + for _, tmp := range mediaVideo.UserInPhoto { + t.Log("User in Photo User:") + LogUser(&tmp.User, t) + t.Log("User In Photo Position X: ", tmp.Position.X) + t.Log("User In Photo Position Y: ", tmp.Position.Y) + } + + t.Log("Comments Count: ", mediaVideo.Comments.Count) + t.Log("Caption Id: ", DefaultStringValueIfEmpty(mediaVideo.Caption.Id)) + t.Log("Caption Created Time: ", DefaultStringValueIfEmpty(mediaVideo.Caption.CreatedTime)) + t.Log("Caption Created Text: ", DefaultStringValueIfEmpty(mediaVideo.Caption.Text)) + t.Log("Caption User: ") + LogUser(&mediaVideo.Caption.From, t) + t.Log("Likes Count: : ", mediaVideo.Likes.Count) + + t.Log("------------------ Start Thumbnail Videos ------------------") + LogImage(&mediaVideo.Images.Thumbnail, t) + t.Log("------------------ End Thumbnail Videos ------------------") + + t.Log("------------------ Start Low Resolution Image ------------------") + LogImage(&mediaVideo.Images.LowResolution, t) + t.Log("------------------ End Low Resolution Image ------------------") + + t.Log("------------------ Start Standard Resolution Image ------------------") + LogImage(&mediaVideo.Images.StandardResolution, t) + t.Log("------------------ End Standard Resolution Image ------------------") + + t.Log("Location Id: ", DefaultStringValueIfEmpty(mediaVideo.Location.Id)) + t.Log("Location Name: ", DefaultStringValueIfEmpty(mediaVideo.Location.Name)) + t.Log("Location Latitude: ", mediaVideo.Location.Latitude) + t.Log("Location Longitude: ", mediaVideo.Location.Longitude) + t.Log("Location Street Address: ", DefaultStringValueIfEmpty(mediaVideo.Location.StreetAddress)) + + t.Log("------------------ Start Standard Resolution Videos ------------------") + LogVideo(&mediaVideo.Videos.StandardResolution, t) + t.Log("------------------ End Standard Resolution Videos ------------------") + + t.Log("------------------ End Start Resolution Videos ------------------") + LogVideo(&mediaVideo.Videos.LowResolution, t) + t.Log("------------------ End Low Resolution Videos ------------------") + + t.Log("------------------ End Video Media ------------------") + } +} + +func LogImage(image *Image, t *testing.T) { + t.Log("Image Url: ", DefaultStringValueIfEmpty(image.Url)) + t.Log("Image Height: ", image.Height) + t.Log("Image Width: ", image.Width) +} + +func LogVideo(video *VideoResolution, t *testing.T) { + t.Log("Video Url: ", DefaultStringValueIfEmpty(video.Url)) + t.Log("Video Width: ", video.Width) + t.Log("Video Height: ", video.Height) +} + +func IterateMedia(media_arr []*Media, t *testing.T) { + if len(media_arr) > 0 { + for _, media := range media_arr { + LogMedia(media, t) + } + } else { + t.Log("No content.") + } +} + +func TestClient_GetCurrentUserRecentMedia(t *testing.T) { + client := CreateClient(t) + media_arr, err := client.GetCurrentUserRecentMedia(1,1,1) + + if err != nil { + t.Fatal(err) + } + + IterateMedia(media_arr, t) +} + +func TestClient_GetUserMedia(t *testing.T) { + client := CreateClient(t) + media_arr, err := client.GetUserMedia("3066964584", 1,1,1) + + if err != nil { + t.Fatal(err) + } + + IterateMedia(media_arr, t) +} + +func TestClient_GetCurrentUserMediaLiked(t *testing.T) { + client := CreateClient(t) + media_arr, err := client.GetCurrentUserMediaLiked("1499806890266583125_2451237325", 1) + + if err != nil { + t.Fatal(err) + } + + IterateMedia(media_arr, t) +} + +func TestClient_GetMediaById(t *testing.T) { + client := CreateClient(t) + media, err := client.GetMediaById("1499806890266583125_2451237325") + + if err != nil { + t.Fatal(err) + } + + LogMedia(media, t) +} + +func TestClient_GetMediaByShortcode(t *testing.T) { + client := CreateClient(t) + media, err := client.GetMediaByShortcode("BTQYmueBeBV") + + if err != nil { + t.Fatal(err) + } + + LogMedia(media, t) +} + +func TestClient_SearchMedia(t *testing.T) { + client := CreateClient(t) + media_arr, err := client.SearchMedia(0, 0) + + if err != nil { + t.Fatal(err) + } + + IterateMedia(media_arr, t) +} + +func TestClient_GetRecentMediaTaggedByTagName(t *testing.T) { + client := CreateClient(t) + media_arr, err := client.GetRecentMediaTaggedByTagName("leoxnidas") + + if err != nil { + t.Fatal(err) + } + + IterateMedia(media_arr, t) +} + +func TestClient_GetRecentMediaLocation(t *testing.T) { + client := CreateClient(t) + media_arr, err := client.GetRecentMediaLocation("1898148680457787") + + if err != nil { + t.Fatal(err) + } + + IterateMedia(media_arr, t) +} diff --git a/relationship.go b/relationship.go new file mode 100644 index 0000000..67c7745 --- /dev/null +++ b/relationship.go @@ -0,0 +1,91 @@ +package gostagram + +import ( + "fmt" + + "github.com/mitchellh/mapstructure" +) + +type Relationship struct { + OutgoingStatus string `mapstructure:"outgoing_status"` + IncomingStatus string `mapstructure:"incoming_status"` +} + +func (r Relationship) Follows() bool { + return r.OutgoingStatus == "follows" +} + +func (r Relationship) Requested() bool { + return r.OutgoingStatus == "requested" +} + +func (r Relationship) FollowedBy() bool { + return r.IncomingStatus == "followed_by" +} + +func (r Relationship) RequestedBy() bool { + return r.IncomingStatus == "requested_by" +} + +func (r Relationship) BlockedByYou() bool { + return r.IncomingStatus == "blocked_by_you" +} + + +func (c *Client) doRelationshipAction(action, uri string) (*Relationship, error) { + tmp, err := c.post(uri, BodyData{ + "action": action, + }) + + if err != nil { + return nil, err + } + + tmpRel := (*tmp).(map[string]interface{}) + var relationship Relationship + if err = mapstructure.Decode(tmpRel, &relationship); err != nil { + return nil, err + } + + return &relationship, nil +} + +func (c *Client) GetCurrentUserRelationship(user_id string) (*Relationship, error) { + tmp, _, err := c.get(fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, user_id, c.access_token)) + if err != nil { + return nil, err + } + + tmpRel := (*tmp).(map[string]interface{}) + var relationship Relationship + if err = mapstructure.Decode(tmpRel, &relationship); err != nil { + return nil, err + } + + return &relationship, nil +} + +func (c *Client) FollowUserById(id string) (*Relationship, error) { + return c.doRelationshipAction("follow", fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, id, c.access_token)) +} + +func (c *Client) UnFollowUserById(id string) (*Relationship, error) { + return c.doRelationshipAction("unfollow", fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, id, c.access_token)) +} + +func (c *Client) ApproveUserById(id string) (*Relationship, error) { + return c.doRelationshipAction("approve", fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, id, c.access_token)) +} + +func (c *Client) IgnoreUserById(id string) (*Relationship, error) { + return c.doRelationshipAction("ignore", fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, id, c.access_token)) +} + +func (c *Client) BlockUserById(id string) (*Relationship, error) { + return c.doRelationshipAction("block", fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, id, c.access_token)) +} + +func (c *Client) UnBlockUserById(id string) (*Relationship, error) { + return c.doRelationshipAction("unblock", fmt.Sprintf("%susers/%s/relationship?access_token=%s", apiUrl, id, c.access_token)) +} + diff --git a/relationship_test.go b/relationship_test.go new file mode 100644 index 0000000..d3027e8 --- /dev/null +++ b/relationship_test.go @@ -0,0 +1,87 @@ +package gostagram + +import "testing" + +func TestClient_GetCurrentUserRelationship(t *testing.T) { + client := CreateClient(t) + tmp, err := client.GetCurrentUserRelationship("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} + +func TestClient_UnFollowUserById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.UnFollowUserById("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} + +func TestClient_FollowUserById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.FollowUserById("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} + +func TestClient_BlockUserById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.BlockUserById("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} + +func TestClient_UnBlockUserById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.UnBlockUserById("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} + +func TestClient_IgnoreUserById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.IgnoreUserById("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} + +func TestClient_ApproveUserById(t *testing.T) { + client := CreateClient(t) + tmp, err := client.ApproveUserById("3066964584") + + if err != nil { + t.Fatal(err) + } + + t.Log(DefaultStringValueIfEmpty(tmp.IncomingStatus)) + t.Log(DefaultStringValueIfEmpty(tmp.OutgoingStatus)) +} diff --git a/signature.go b/signature.go new file mode 100644 index 0000000..2163262 --- /dev/null +++ b/signature.go @@ -0,0 +1,24 @@ +package gostagram + +import ( + "crypto/hmac" + "crypto/sha256" + "encoding/hex" + "fmt" +) + +func (c *Client) generateSignature(endpoint string, params Params) (string, error) { + sig := endpoint + for key, val := range params { + sig += fmt.Sprintf("|%s=%s", key, val) + } + + + tmp := hmac.New(sha256.New, []byte(c.clientSecret)) + _, err := tmp.Write([]byte(sig)) + if err != nil { + return "", err + } + + return hex.EncodeToString(tmp.Sum(nil)), nil +} diff --git a/tags.go b/tags.go new file mode 100644 index 0000000..e47e3b8 --- /dev/null +++ b/tags.go @@ -0,0 +1,49 @@ +package gostagram + +import ( + "fmt" + "github.com/mitchellh/mapstructure" +) + +type Tag struct { + Name string + MediaCount int `mapstructure:"media_count"` +} + +func (c *Client) GetTagByName(tagname string) (*Tag, error) { + tmp, _, err := c.get(fmt.Sprintf("%stags/%s?access_token=%s", apiUrl, tagname, c.access_token)) + + if err != nil { + return nil, err + } + + tmpTag := (*tmp).(map[string]interface{}) + var tag Tag + if err = mapstructure.Decode(tmpTag, &tag); err != nil { + return nil, err + } + + return &tag, nil +} + +func (c *Client) SearchTags(query string) ([]*Tag, error) { + tmp, _, err := c.get(fmt.Sprintf("%stags/search?q=%s&access_token=%s", apiUrl, query, c.access_token)) + if err != nil { + return nil, err + } + + tmpUsers := (*tmp).([]interface{}) + + var tags []*Tag + for _, tmpUser := range tmpUsers { + var tag Tag + + if err := mapstructure.Decode(tmpUser, &tag); err != nil { + return nil, err + } + + tags = append(tags, &tag) + } + + return tags, nil +} diff --git a/tags_test.go b/tags_test.go new file mode 100644 index 0000000..9719910 --- /dev/null +++ b/tags_test.go @@ -0,0 +1,33 @@ +package gostagram + +import ( + "testing" +) + +func TestClient_GetTagByName(t *testing.T) { + client := CreateClient(t) + tmp, err := client.GetTagByName("leoxnidas") + + if err != nil { + t.Fatal(err) + } + + t.Log(tmp.Name) + t.Log(tmp.MediaCount) +} + +func TestClient_SearchTags(t *testing.T) { + client := CreateClient(t) + tmp, err := client.SearchTags("leoxn") + + if err != nil { + t.Fatal(err) + } + + for _, tag := range tmp { + t.Log("------------------ Start Tag ------------------") + t.Log(tag.Name) + t.Log(tag.MediaCount) + t.Log("------------------ End Tag ------------------") + } +} \ No newline at end of file diff --git a/users.go b/users.go new file mode 100644 index 0000000..acfaa0f --- /dev/null +++ b/users.go @@ -0,0 +1,96 @@ +package gostagram + +import ( + "fmt" + "github.com/mitchellh/mapstructure" +) + +type UserDetailed struct { + Id string + Bio string + Website string + Username string + FullName string `mapstructure:"full_name"` + ProfilePicture string `mapstructure:"profile_picture"` + + Counts struct { + Media int + Follows int + FollowedBy int `mapstructure:"followed_by"` + } +} + +type User struct { + Id string + Type string + Username string + LastName string `mapstructure:"last_name"` + FirstName string `mapstructure:"first_name"` + ProfilePicture string `mapstructure:"profile_picture"` +} + +func (c *Client) getUser(uri string) (*UserDetailed, error) { + tmp, _, err := c.get(uri) + + if err != nil { + return nil, err + } + + userDetailedMap := (*tmp).(map[string]interface{}) + var userDetailed UserDetailed + if err = mapstructure.Decode(userDetailedMap, &userDetailed); err != nil { + return nil, err + } + + return &userDetailed, nil +} + +func (c *Client) getUsers(uri string) ([]*User, error) { + tmp, _, err := c.get(uri) + if err != nil { + return nil, err + } + + tmpUsers := (*tmp).([]interface{}) + + var users []*User + for _, tmpUser := range tmpUsers { + var user User + + if err := mapstructure.Decode(tmpUser, &user); err != nil { + return nil, err + } + + users = append(users, &user) + } + + return users, nil +} + +func (c *Client) GetCurrentUser() (*UserDetailed, error) { + return c.getUser(fmt.Sprintf("%susers/self/?access_token=%s", apiUrl, c.access_token)) +} + +func (c *Client) GetUser(id string) (*UserDetailed, error) { + return c.getUser(fmt.Sprintf("%susers/%s/?access_token=%s", apiUrl, id, c.access_token)) +} + +func (c *Client) SearchUsers(query string, count int) ([]*User, error) { + return c.getUsers(fmt.Sprintf("%susers/search?q=%s&count=%d&access_token=%s", + apiUrl, query, count, c.access_token)) +} + +func (c *Client) GetCurrentUserFollows() ([]*User, error) { + return c.getUsers(fmt.Sprintf("%susers/self/follows?access_token=%s", + apiUrl, c.access_token)) +} + +func (c *Client) GetCurrentUserFollowedBy() ([]*User, error) { + return c.getUsers(fmt.Sprintf("%susers/self/followed-by?access_token=%s", + apiUrl, c.access_token)) +} + +func (c *Client) GetCurrentUserRequestedBy() ([]*User, error) { + return c.getUsers(fmt.Sprintf("%susers/self/requested-by?access_token=%s", + apiUrl, c.access_token)) +} diff --git a/users_test.go b/users_test.go new file mode 100644 index 0000000..a90781b --- /dev/null +++ b/users_test.go @@ -0,0 +1,180 @@ +package gostagram + +import ( + "testing" + "os" +) + +var ( + clientSecret = "94637a21fdab42dca158c6f6bd1fbe19" + accessToken = "2451237325.e0f323b.e8ab7baadad945e0856bebcae2032127" +) + +func GetAccessTokenFromEnv() string { + return os.Getenv("ACCESS_TOKEN") +} + +func GetClientSecret() string { + return os.Getenv("CLIENT_SECRET") +} + +func IsSecureRequest() bool { + return os.Getenv("SECURE") == "true" +} + +func GetUserId() string { + return os.Getenv("USER_ID") +} + +func CreateClient(t *testing.T) *Client { + //accessToken := GetAccessTokenFromEnv() + //if len(accessToken) == 0 { + // t.Error("Access token not set.") + //} + + client := NewClient(accessToken) + + //if IsSecureRequest() { + // client.SetSignedRequest(true) + // client_secret := GetClientSecret() + // if len(client_secret) == 0 { + // t.Error("Cannot send secure request without client secret") + // } else { + // client.SetClientSecret(client_secret) + // } + //} + + client.SetSignedRequest(true) + client.SetClientSecret(clientSecret) + + return client +} + +func DefaultStringValueIfEmpty(t string) string { + if len(t) > 0 { + return t + } + + return "None" +} + +func LogUserDetailed(user *UserDetailed, t *testing.T) { + t.Log("------------------ Start User ------------------") + t.Log("Username: ", DefaultStringValueIfEmpty(user.Username)) + t.Log("Profile Picture: ", DefaultStringValueIfEmpty(user.ProfilePicture)) + t.Log("Fullname: ", DefaultStringValueIfEmpty(user.FullName)) + t.Log("Website: ", DefaultStringValueIfEmpty(user.Website)) + t.Log("Bio: ", DefaultStringValueIfEmpty(user.Bio)) + t.Log("Id: ", DefaultStringValueIfEmpty(user.Id)) + t.Log("Followed by: ", user.Counts.FollowedBy) + t.Log("Follows: ", user.Counts.Follows) + t.Log("Media: ", user.Counts.Media) + t.Log("------------------ End User ------------------") +} + +func LogUser(user *User, t *testing.T) { + t.Log("Username: ", DefaultStringValueIfEmpty(user.Username)) + t.Log("Profile Picture: ", DefaultStringValueIfEmpty(user.ProfilePicture)) + t.Log("First Name: ", DefaultStringValueIfEmpty(user.FirstName)) + t.Log("Last Name: ", DefaultStringValueIfEmpty(user.LastName)) + t.Log("Id: ", DefaultStringValueIfEmpty(user.Id)) + t.Log("Type: ", DefaultStringValueIfEmpty(user.Type)) +} + +func TestClient_GetCurrentUser(t *testing.T) { + client := CreateClient(t) + tmp, err := client.GetCurrentUser() + + if err != nil { + t.Fatal(err) + } + + LogUserDetailed(tmp, t) +} + +func TestClient_GetUser(t *testing.T) { + client := CreateClient(t) + tmp, err := client.GetUser("3066964584") + + if err != nil { + t.Fatal(err) + } + + LogUserDetailed(tmp, t) +} + +func TestClient_SearchUsers(t *testing.T) { + client := CreateClient(t) + users, err := client.SearchUsers("leo", 1) + + if err != nil { + t.Fatal(err) + } + + if len(users) > 0 { + for _, user := range users { + t.Log("------------------ Start User ------------------") + LogUser(user, t) + t.Log("------------------ End User ------------------") + } + } else { + t.Log("Not found any user.!") + } +} + +func TestClient_GetCurrentUserFollows(t *testing.T) { + client := CreateClient(t) + users, err := client.GetCurrentUserFollows() + + if err != nil { + t.Fatal(err) + } + + if len(users) > 0 { + for _, user := range users { + t.Log("------------------ Start User ------------------") + LogUser(user, t) + t.Log("------------------ End User ------------------") + } + } else { + t.Log("Not found any user.!") + } +} + +func TestClient_GetCurrentUserFollowedBy(t *testing.T) { + client := CreateClient(t) + users, err := client.GetCurrentUserFollowedBy() + + if err != nil { + t.Fatal(err) + } + + if len(users) > 0 { + for _, user := range users { + t.Log("------------------ Start User ------------------") + LogUser(user, t) + t.Log("------------------ End User ------------------") + } + } else { + t.Log("Nothing found.!") + } +} + +func TestClient_GetCurrentUserRequestedBy(t *testing.T) { + client := CreateClient(t) + users, err := client.GetCurrentUserRequestedBy() + + if err != nil { + t.Fatal(err) + } + + if len(users) > 0 { + for _, user := range users { + t.Log("------------------ Start User ------------------") + LogUser(user, t) + t.Log("------------------ End User ------------------") + } + } else { + t.Log("Not found any user.!") + } +}