docxTemplater/penadisk/api.go

488 lines
9.7 KiB
Go
Raw Normal View History

package penadisk
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"net/url"
"os"
"strconv"
"strings"
"github.com/minio/minio-go/v7"
)
const (
DefaultFolder = "templategen"
DefaultTemplateFolder = DefaultFolder + "/templates"
DefaultSaveFolder = DefaultFolder + "/saved"
)
var (
URL = ""
V1DiskAPI = URL + "/api/v1/"
)
func init() {
URL = os.Getenv("PENADISK_URL")
V1DiskAPI = URL + "api/v1/"
}
type Client struct {
/* ID пользователя пены */
userID string
}
func NewClient(userID string) *Client {
return &Client{userID: userID}
}
func (c *Client) GetDisk(ctx context.Context) (*BucketWithStats, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"bucket", http.NoBody)
if err != nil {
return nil, err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if err = checkError(resp); err != nil {
return nil, err
}
var r BucketWithStats
err = json.NewDecoder(resp.Body).Decode(&r)
return &r, err
}
func (c *Client) SetBucketQuota(ctx context.Context, size uint64) error {
data := url.Values{}
data.Set("size", strconv.FormatUint(size, 10))
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/quota/set?"+data.Encode(), http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) UnsetBucketQuota(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/quota/unset", http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) EnableBucketVersioning(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/versioning/enable", http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) SuspendBucketVersioning(ctx context.Context) error {
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"bucket/versioning/suspend", http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
// GetResources - получить информацию о ресурсах.
func (c *Client) GetResources(ctx context.Context, path string, recursive, withVersion bool) ([]minio.ObjectInfo, error) {
data := url.Values{}
data.Set("path", path)
if recursive {
data.Set("recursive", "true")
}
if withVersion {
data.Set("with_versions", "true")
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"resources?"+data.Encode(), http.NoBody)
if err != nil {
return nil, err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
if err = checkError(resp); err != nil {
return nil, err
}
var r []minio.ObjectInfo
err = json.NewDecoder(resp.Body).Decode(&r)
return r, err
}
// PutResources - создать папку.
func (c *Client) PutResources(ctx context.Context, path string) error {
data := url.Values{}
data.Set("path", path)
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources?"+data.Encode(), http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) UploadResources(ctx context.Context, path, filename string, overwrite bool,
file io.Reader) (fullPath string, exportURL string, err error) {
buf := new(bytes.Buffer)
bw := multipart.NewWriter(buf)
if !strings.HasSuffix(path, "/") {
path += "/"
}
err = bw.WriteField("path", path)
if err != nil {
return "", "", err
}
if overwrite {
err = bw.WriteField("overwrite", "true")
if err != nil {
return "", "", err
}
}
fw, err := bw.CreateFormFile("file", filename)
if err != nil {
return "", "", err
}
_, err = io.Copy(fw, file)
if err != nil {
return "", "", err
}
err = bw.Close()
if err != nil {
return "", "", err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, V1DiskAPI+"resources/upload", buf)
if err != nil {
return "", "", err
}
c.setHeaders(req)
req.Header.Set("Content-Type", bw.FormDataContentType())
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", "", err
}
if err = checkError(resp); err != nil {
return "", "", err
}
fullPath = path + filename
exportURL, err = c.GetPublicDownloadURL(ctx, fullPath)
return fullPath, exportURL, err
}
// GetPublicDownloadURL - получить публичную ссылку для скачивания файла. Ссылка живет 30 минут.
func (c *Client) GetPublicDownloadURL(ctx context.Context, path string) (href string, err error) {
data := url.Values{}
data.Set("path", path)
// Получаем публичную ссылку на файл живущую 30 минут
req, err := http.NewRequestWithContext(ctx, http.MethodGet, V1DiskAPI+"resources/download?"+data.Encode(), http.NoBody)
if err != nil {
return "", err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
err = checkError(resp)
if err != nil {
return "", err
}
var r RespDownloadResources
err = json.NewDecoder(resp.Body).Decode(&r)
return r.Href, err
}
func (c *Client) DownloadResource(ctx context.Context, path, downloadPath string) error {
href, err := c.GetPublicDownloadURL(ctx, path)
if err != nil {
return err
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, href, http.NoBody)
if err != nil {
return err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if err != nil {
return err
}
err = checkError(resp)
if err != nil {
return err
}
if err = checkError(resp); err != nil {
return err
}
// Create the file
out, err := os.Create(downloadPath)
if err != nil {
return err
}
defer out.Close() //nolint
// Write the body to file
_, err = io.Copy(out, resp.Body)
return err
}
func (c *Client) DownloadResourceBytes(ctx context.Context, path string) ([]byte, error) {
href, err := c.GetPublicDownloadURL(ctx, path)
if err != nil {
return nil, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, href, http.NoBody)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if err = checkError(resp); err != nil {
return nil, err
}
return io.ReadAll(resp.Body)
}
func (c *Client) CopyResources(ctx context.Context, from, path string, overwrite bool) error {
data := url.Values{}
data.Set("from", from)
data.Set("path", path)
if overwrite {
data.Set("overwrite", "true")
}
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/copy?"+data.Encode(), http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) MoveResources(ctx context.Context, from, path string, overwrite bool) error {
data := url.Values{}
data.Set("from", from)
data.Set("path", path)
if overwrite {
data.Set("overwrite", "true")
}
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/move?"+data.Encode(), http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) DeleteResources(ctx context.Context, path string, permanently bool) error {
data := url.Values{}
data.Set("path", path)
if permanently {
data.Set("permanently", "true")
}
req, err := http.NewRequestWithContext(ctx, http.MethodDelete, V1DiskAPI+"resources?"+data.Encode(), http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) PublishResources(ctx context.Context, path string) (href string, err error) {
data := url.Values{}
data.Set("path", path)
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/publish?"+data.Encode(), http.NoBody)
if err != nil {
return "", err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return "", err
}
if err = checkError(resp); err != nil {
return "", err
}
var r RespPublishResources
err = json.NewDecoder(resp.Body).Decode(&r)
return r.Href, err
}
func (c *Client) UnpublishResources(ctx context.Context, path string) error {
data := url.Values{}
data.Set("path", path)
req, err := http.NewRequestWithContext(ctx, http.MethodPut, V1DiskAPI+"resources/unpublish?"+data.Encode(), http.NoBody)
if err != nil {
return err
}
c.setHeaders(req)
resp, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
return checkError(resp)
}
func (c *Client) setHeaders(req *http.Request) {
req.Header.Set("LocalUserID", c.userID)
req.Header.Set("Content-Type", "application/json")
}
func checkError(resp *http.Response) error {
switch resp.StatusCode {
case http.StatusOK, http.StatusCreated, http.StatusAccepted, http.StatusNonAuthoritativeInfo,
http.StatusNoContent, http.StatusResetContent, http.StatusPartialContent,
http.StatusMultiStatus, http.StatusAlreadyReported, http.StatusIMUsed:
return nil
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
return fmt.Errorf("api/penaDisk: %v | %v", resp.StatusCode, string(body))
}