package gdisk import ( "bytes" "context" "fmt" "io" "log" "net/http" "os" "strings" "github.com/pkg/errors" "golang.org/x/oauth2" "golang.org/x/oauth2/google" "google.golang.org/api/drive/v3" "google.golang.org/api/option" "gitea.pena/PenaSide/docxTemplater/tools" ) const ( DefaultDir = "TemplateGenerator" TemplateDir = "templates" SaveDir = "saved" MimeTypeDocx = "application/vnd.openxmlformats-officedocument.wordprocessingml.document" MimeTypeGoogle = "application/vnd.google-apps.document" ) type Client struct { App *ClientApp HTTPClient *http.Client Service *drive.Service Token *oauth2.Token } type ClientApp struct { Config *oauth2.Config } func NewClientApp(credentials string) (*ClientApp, error) { b, err := os.ReadFile(credentials) if err != nil { return nil, errors.Wrap(err, "NewClientApp.ReadFile") } config, err := google.ConfigFromJSON(b, drive.DriveScope, drive.DriveMetadataScope, ) if err != nil { return nil, errors.Wrap(err, "NewClientApp.ConfigFromJSON") } return &ClientApp{Config: config}, nil } func (ca *ClientApp) GenerateOAuthURL(amoID, penaID, redirectURL string) (string, error) { state, err := tools.EncryptTokenAES(tools.StateToken{ AmoID: amoID, PenaID: penaID, Service: "google", RedirectURL: redirectURL, }) if err != nil { return "", errors.Wrap(err, "GenerateOAuthURL.Encrypt") } return ca.Config.AuthCodeURL(state, oauth2.AccessTypeOffline, oauth2.ApprovalForce), nil } 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, errors.Wrap(err, "RefreshToken") } return token, nil } func (ca *ClientApp) NewClient(ctx context.Context, token *oauth2.Token) (*Client, error) { client := ca.Config.Client(ctx, token) service, err := drive.NewService(ctx, option.WithHTTPClient(client)) if err != nil { return nil, errors.Wrap(err, "NewClient.NewService") } return &Client{ App: ca, HTTPClient: client, Service: service, Token: token, }, nil } func (ca *ClientApp) GetToken(ctx context.Context, authCode string) (*oauth2.Token, error) { return ca.Config.Exchange(ctx, authCode) } func (c *Client) SetToken(token oauth2.Token) { c.Token = &token } func (c *Client) GetDisk(ctx context.Context) { service, err := drive.NewService(ctx, option.WithHTTPClient(c.HTTPClient)) if err != nil { log.Println(errors.Wrap(err, "GetDisk.NewService")) return } about, err := service.About.Get().Fields("storageQuota", "user", "exportFormats", "maxImportSizes", "maxUploadSize").Do() if err != nil { log.Println(errors.Wrap(err, "GetDisk.ServiceAboutGet")) return } fmt.Printf("srv.About %+v \r\n", about.User) dl, err := service.Drives.List().Do() if err != nil { log.Println(errors.Wrap(err, "GetDisk.ServiceDriveListDo")) return } fmt.Println("DRIVES ________________________") for _, drive := range dl.Drives { fmt.Println(drive) } } // GetUserInfo - получить информацию о пользователе Google. func (c *Client) GetUserInfo(ctx context.Context) (*drive.User, error) { service, err := drive.NewService(ctx, option.WithHTTPClient(c.HTTPClient)) if err != nil { return nil, errors.Wrap(err, "GetUserInfo.NewService") } about, err := service.About.Get().Fields("user").Do() if err != nil { return nil, errors.Wrap(err, "GetUserInfo.ServiceDo") } if about == nil { return nil, errors.Wrap(errors.New("got empty about"), "GetUserInfo") } if about.User == nil { return nil, errors.Wrap(errors.New("got empty about.User"), "GetUserInfo") } return about.User, nil } // GetResourcesByName - получить информацию о ресурсе. func (c *Client) GetResourcesByName(name, parentID string) (*drive.FileList, error) { query := "name = '" + name + "' and trashed = false" if parentID != "" { query += "and '" + parentID + "' in parents" } fl, err := c.Service.Files.List(). Q(query). Do() if err != nil { if strings.Contains(err.Error(), "404") { return nil, nil } return nil, errors.Wrap(err, "GetResourcesByName.ServiceFileListDo") } return fl, nil } // GetResources - получить список файлов и папок ресурса по его id // Если id не указан, то принимается значение 'root'. func (c *Client) GetResources(id string) (*drive.FileList, error) { if id == "" { id = "root" } query := fmt.Sprintf("trashed = false and '%v' in parents", id) fl, err := c.Service.Files.List(). Q(query). Do() if err != nil { if strings.Contains(err.Error(), "404") { return nil, nil } return nil, errors.Wrap(err, "GetResources.ServiceFileListDo") } return fl, nil } // PutResources - создание папки. func (c *Client) PutResources(name, parentID string) (*drive.File, error) { queryFile := &drive.File{Name: name, MimeType: "application/vnd.google-apps.folder", IsAppAuthorized: true} if parentID != "" { queryFile.Parents = []string{parentID} } f, err := c.Service.Files.Create(queryFile).Do() if err != nil { return nil, errors.Wrap(err, "PutResources.ServiceFileListDo") } return f, nil } func (c *Client) DeleteResources(id string) error { err := c.Service.Files.Delete(id).Do() return errors.Wrap(err, "DeleteResources") } // UploadFile - отправить файл в диск. func (c *Client) UploadFile(filepath, mimetype, parentID string) (string, string, error) { file, err := os.Open(filepath) defer func() { if err = file.Close(); err != nil { log.Println("ERROR", errors.Wrap(err, "UploadFile.FileClose")) } }() if err != nil { return "", "", errors.Wrap(err, "UploadFile.OsOpen") } filename := strings.Split(file.Name(), "/") queryFile := &drive.File{ Name: filename[len(filename)-1], MimeType: mimetype, IsAppAuthorized: true, } if parentID != "" { queryFile.Parents = []string{parentID} } fileData, err := c.Service.Files.Create(queryFile).Media(file).Do() if err != nil { return "", "", errors.Wrap(err, "UploadFile.ServiceFilesCreate") } return fileData.Id, fileData.ExportLinks[mimetype], nil } func (c *Client) UploadFileBytes(file []byte, filename, mimetype, parentID string) (string, string, error) { queryFile := &drive.File{ Name: filename, MimeType: mimetype, IsAppAuthorized: true, } if parentID != "" { queryFile.Parents = []string{parentID} } fileData, err := c.Service.Files.Create(queryFile).Media(bytes.NewReader(file)).Do() if err != nil { return "", "", errors.Wrap(err, "UploadFileBytes.ServiceFilesCreateDo") } return fileData.Id, fileData.ExportLinks[mimetype], nil } func (c *Client) DownloadFile(filepath, fileID string) error { file, err := c.Service.Files.Get(fileID).Do() if err != nil { return errors.Wrap(err, "DownloadFile.ServiceFilesGetDo") } var resp *http.Response if file.MimeType == MimeTypeGoogle { resp, err = c.Service.Files.Export(fileID, MimeTypeDocx). Fields("exportFormat", "docx"). Download() err = errors.Wrap(err, "DownloadFile.Export") } else { resp, err = c.Service.Files.Get(fileID).Download() err = errors.Wrap(err, "DownloadFile.Download") } if err != nil { return err } defer func() { if err = resp.Body.Close(); err != nil { log.Println("ERROR", errors.Wrap(err, "DownloadFile.BodyClose")) } }() out, err := os.Create(filepath) defer func() { if err = out.Close(); err != nil { log.Println("ERROR", errors.Wrap(err, "DownloadFile.OutFileClose")) } }() if err != nil { return errors.Wrap(err, "DownloadFile.OsCreate") } _, err = io.Copy(out, resp.Body) if err != nil { return errors.Wrap(err, "DownloadFile.IoCopy") } return nil } func (c *Client) DownloadFileBytes(fileID string) ([]byte, error) { file, err := c.Service.Files.Get(fileID).Do() if err != nil { return nil, errors.Wrap(err, "DownloadFileBytes.ServiceFilesGetDo") } var resp *http.Response if file.MimeType == MimeTypeGoogle { resp, err = c.Service.Files.Export(fileID, MimeTypeDocx).Fields("exportFormat", "docx").Download() err = errors.Wrap(err, "DownloadFileBytes.Export") defer func() { if err = resp.Body.Close(); err != nil { log.Println("ERROR", errors.Wrap(err, "DownloadFileBytes.BodyClose")) } }() } else { resp, err = c.Service.Files.Get(fileID).Download() err = errors.Wrap(err, "DownloadFileBytes.Download") defer func() { if err = resp.Body.Close(); err != nil { log.Println("ERROR", errors.Wrap(err, "DownloadFileBytes.BodyClose")) } }() } if err != nil { return nil, err } defer func() { if err = resp.Body.Close(); err != nil { log.Println("ERROR", errors.Wrap(err, "DownloadFile.BodyClose")) } }() return io.ReadAll(resp.Body) } // MakeDefaultDirs - проверяет диск на наличие папок DefaultDir, TemplateDir и SaveDir. // Если папки не существуют, то создает их. func (c *Client) MakeDefaultDirs(defaultID, defaultName, templateID, templateName, saveID, saveName string) (*drive.File, *drive.File, *drive.File, error) { var defaultDir, templateDir, saveDir *drive.File if defaultName == "" { defaultName = DefaultDir } if templateName == "" { templateName = TemplateDir } if saveName == "" { saveName = SaveDir } var err error // Check Default directory if defaultID == "" { var fl *drive.FileList fl, err = c.GetResourcesByName(defaultName, "") if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.GetResourceByName") } if len(fl.Files) == 0 { defaultDir, err = c.PutResources(defaultName, "") if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.PutResource") } } else { defaultDir = fl.Files[0] } } else { defaultDir, err = c.Service.Files.Get(defaultID).Do() if err != nil { if strings.Contains(err.Error(), "404") { defaultDir, err = c.PutResources(defaultName, "") if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.PutResource") } } else { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.DefaultDir.ServiceFilesGetDo") } } } // Check Template Directory if templateID == "" { var fl *drive.FileList fl, err = c.GetResourcesByName(templateName, defaultDir.Id) if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.GetResourcesByName") } if len(fl.Files) == 0 { templateDir, err = c.PutResources(templateName, defaultDir.Id) if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.PutResources") } } else { templateDir = fl.Files[0] } } else { templateDir, err = c.Service.Files.Get(templateID).Do() if err != nil { if strings.Contains(err.Error(), "404") { templateDir, err = c.PutResources(templateName, defaultDir.Id) if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.PutResources") } } else { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.TemplateDir.ServiceFilesGetDo") } } } // Check Save Directory if saveID == "" { var fl *drive.FileList fl, err = c.GetResourcesByName(saveName, defaultDir.Id) if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.GetResourcesByName") } if len(fl.Files) == 0 { saveDir, err = c.PutResources(saveName, defaultDir.Id) if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.PutResources") } } else { saveDir = fl.Files[0] } } else { saveDir, err = c.Service.Files.Get(templateID).Do() if err != nil { if strings.Contains(err.Error(), "404") { saveDir, err = c.PutResources(saveName, defaultDir.Id) if err != nil { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.PutResources") } } else { return nil, nil, nil, errors.Wrap(err, "MakeDefaultDirs.SaveDir.ServiceFilesGetDo") } } } return defaultDir, templateDir, saveDir, nil }