docxTemplater/penadisk/api.go

488 lines
9.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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))
}