package YaDisk import ( "context" "encoding/json" "errors" "fmt" "github.com/Pena-Co-Ltd/amocrm_templategen_back/tools" "golang.org/x/oauth2" "io" "net/http" "net/url" "os" "strconv" "strings" ) const ( BASE_URL = "https://cloud-api.yandex.net" OAUTH_URL = "https://oauth.yandex.ru" DEFAULT_FOLDER = "disk:/templategen" DEFAULT_TEMPLATE_FOLDER = DEFAULT_FOLDER + "/templates" DEFAULT_SAVE_FOLDER = DEFAULT_FOLDER + "/saved" ) type Client struct { App *ClientApp HTTPClient *http.Client Token *oauth2.Token } type ClientApp struct { Config *oauth2.Config ServiceUrl string } func NewClientApp(clientID, clientSecret, redirectUri, serviceUrl string) *ClientApp { return &ClientApp{ Config: &oauth2.Config{ ClientID: clientID, ClientSecret: clientSecret, Endpoint: oauth2.Endpoint{ AuthURL: "https://oauth.yandex.ru/authorize", TokenURL: "https://oauth.yandex.ru/token", }, RedirectURL: redirectUri, Scopes: nil, }, ServiceUrl: serviceUrl, } } func (ca *ClientApp) GenerateOAuthUrl(userId, redirectUrl string) (string, error) { state, err := tools.EncryptTokenRC4(tools.StateToken{ UserID: userId, Service: "yandex", RedirectUrl: redirectUrl, }) if err != nil { return "", err } return ca.Config.AuthCodeURL( state, oauth2.AccessTypeOffline, oauth2.SetAuthURLParam("display", "popup"), oauth2.SetAuthURLParam("force_confirm", "true"), ), nil } func (ca *ClientApp) NewClient(ctx context.Context, token *oauth2.Token, code string) (*Client, error) { var err error if code != "" { token, err = ca.Config.Exchange(ctx, code) } // Этот костыль нужен, т.к. Яндекс принимает токены только типа OAuth, хоть и отправляет типа bearer token.TokenType = "OAuth" return &Client{ App: ca, HTTPClient: ca.Config.Client(ctx, token), Token: token, }, err } func (ca *ClientApp) RefreshToken(ctx context.Context, oldToken *oauth2.Token) (*oauth2.Token, error) { token, err := ca.Config.TokenSource(ctx, oldToken).Token() if err != nil { return nil, err } // Этот костыль нужен, т.к. Яндекс принимает токены только типа OAuth, хоть и отправляет типа bearer token.TokenType = "OAuth" return token, nil } func (c *Client) GetDisk() (*Disk, error) { req, err := http.NewRequest("GET", BASE_URL+"/v1/disk", nil) if err != nil { return nil, err } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err } err = checkError(resp) if err != nil { return nil, err } r := Disk{} err = json.NewDecoder(resp.Body).Decode(&r) if err != nil { return nil, err } return &r, nil } func (c *Client) GetUser() (*User, error) { disk, err := c.GetDisk() if err != nil { return nil, err } return &disk.User, nil } func (c *Client) GetResources(path string, limit, offset int) (*Resource, error) { if path == "" { path = "disk:/" } data := url.Values{} data.Set("path", path) if limit > 0 { data.Set("limit", strconv.Itoa(limit)) } if offset > 0 { data.Set("offset", strconv.Itoa(offset)) } data.Encode() req, err := http.NewRequest("GET", BASE_URL+"/v1/disk/resources?"+data.Encode(), nil) if err != nil { return nil, err } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err } if resp.StatusCode == 404 { return nil, nil } err = checkError(resp) if err != nil { return nil, err } r := Resource{} err = json.NewDecoder(resp.Body).Decode(&r) return &r, err } func (c *Client) DownloadResource(path, downloadPath string) error { res, err := c.GetResources(path, 0, 0) if err != nil { return err } resp, err := http.Get(res.File) if err != nil { return err } defer resp.Body.Close() // Create the file out, err := os.Create(downloadPath) if err != nil { return err } defer out.Close() // Write the body to file _, err = io.Copy(out, resp.Body) return err } // PutResources - создание папки func (c *Client) PutResources(path string) (*RespPutResources, error) { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("PUT", BASE_URL+"/v1/disk/resources?"+data.Encode(), nil) if err != nil { return nil, err } resp, err := c.HTTPClient.Do(req) if err != nil { return nil, err } if resp.StatusCode == 409 { return nil, nil } err = checkError(resp) if err != nil { return nil, err } var r RespPutResources err = json.NewDecoder(resp.Body).Decode(&r) return &r, err } func (c *Client) DeleteResources(path string) error { data := url.Values{} data.Set("path", path) req, err := http.NewRequest("DELETE", BASE_URL+"/v1/disk/resources?"+data.Encode(), nil) if err != nil { return err } resp, err := c.HTTPClient.Do(req) if err != nil { return err } err = checkError(resp) return err } func (c *Client) UploadResources(path, downloadPath string) error { downloadPath = strings.TrimLeft(downloadPath, "..") downloadPath = strings.TrimLeft(downloadPath, ".") data := url.Values{} data.Set("path", path) data.Set("url", c.App.ServiceUrl+downloadPath) req, err := http.NewRequest("POST", BASE_URL+"/v1/disk/resources/upload?"+data.Encode(), nil) if err != nil { return err } resp, err := c.HTTPClient.Do(req) if err != nil { return err } r := map[string]interface{}{} err = json.NewDecoder(resp.Body).Decode(&r) fmt.Printf("%+v", r) return err } func checkError(resp *http.Response) error { switch resp.StatusCode { case 200, 201, 202, 203, 204, 205, 206, 207, 208, 226: return nil } r := Error{} err := json.NewDecoder(resp.Body).Decode(&r) if err != nil { return err } return errors.New(fmt.Sprintf("api/yaDisk (%v) err: %v | %v (%v)", resp.StatusCode, r.Message, r.Description, r.Error)) }