feat: implement files endpoint
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
package onspring
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"mime"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const (
|
||||
filesPath = "/files"
|
||||
)
|
||||
|
||||
// FilesEndpoint provides access to files in an Onspring instance.
|
||||
type FilesEndpoint struct {
|
||||
client *Client
|
||||
}
|
||||
|
||||
// FileInfo represents the metadata of a file in Onspring.
|
||||
type FileInfo struct {
|
||||
Type string `json:"type"`
|
||||
ContentType string `json:"contentType"`
|
||||
Name string `json:"name"`
|
||||
CreatedDate string `json:"createdDate"`
|
||||
ModifiedDate string `json:"modifiedDate"`
|
||||
Owner string `json:"owner"`
|
||||
Notes string `json:"notes"`
|
||||
FileHref string `json:"fileHref"`
|
||||
}
|
||||
|
||||
// FileContent represents the content of a downloaded file.
|
||||
type FileContent struct {
|
||||
FileName string
|
||||
ContentType string
|
||||
Data []byte
|
||||
}
|
||||
|
||||
// SaveFileRequest represents a request to upload a file.
|
||||
type SaveFileRequest struct {
|
||||
RecordId int
|
||||
FieldId int
|
||||
Notes string
|
||||
ModifiedDate string
|
||||
FileName string
|
||||
FileContents io.Reader
|
||||
}
|
||||
|
||||
// SaveFileResponse represents the response for saving a file.
|
||||
type SaveFileResponse struct {
|
||||
Id int `json:"id"`
|
||||
}
|
||||
|
||||
func fileBasePath(recordId, fieldId, fileId int) string {
|
||||
return fmt.Sprintf("%s/recordId/%d/fieldId/%d/fileId/%d", filesPath, recordId, fieldId, fileId)
|
||||
}
|
||||
|
||||
// GetInfo retrieves a file's metadata from the Onspring API.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context for the request
|
||||
// - recordId: The id of the record
|
||||
// - fieldId: The id of the field
|
||||
// - fileId: The id of the file
|
||||
//
|
||||
// Returns:
|
||||
// - FileInfo: The file's metadata
|
||||
// - error: An error if the request fails
|
||||
func (f *FilesEndpoint) GetInfo(ctx context.Context, recordId, fieldId, fileId int) (FileInfo, error) {
|
||||
path := fileBasePath(recordId, fieldId, fileId)
|
||||
req, requestCreationErr := f.client.newRequest(ctx, http.MethodGet, path, nil, nil)
|
||||
|
||||
var fileInfo FileInfo
|
||||
|
||||
if requestCreationErr != nil {
|
||||
return fileInfo, requestCreationErr
|
||||
}
|
||||
|
||||
responseErr := f.client.doWithJsonResponse(req, &fileInfo)
|
||||
|
||||
if responseErr != nil {
|
||||
return fileInfo, responseErr
|
||||
}
|
||||
|
||||
return fileInfo, nil
|
||||
}
|
||||
|
||||
// GetContent retrieves a file's content from the Onspring API.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context for the request
|
||||
// - recordId: The id of the record
|
||||
// - fieldId: The id of the field
|
||||
// - fileId: The id of the file
|
||||
//
|
||||
// Returns:
|
||||
// - FileContent: The file's content including name, content type, and data
|
||||
// - error: An error if the request fails
|
||||
func (f *FilesEndpoint) GetContent(ctx context.Context, recordId, fieldId, fileId int) (FileContent, error) {
|
||||
path := fmt.Sprintf("%s/file", fileBasePath(recordId, fieldId, fileId))
|
||||
req, requestCreationErr := f.client.newRequest(ctx, http.MethodGet, path, nil, nil)
|
||||
|
||||
var fileContent FileContent
|
||||
|
||||
if requestCreationErr != nil {
|
||||
return fileContent, requestCreationErr
|
||||
}
|
||||
|
||||
data, headers, responseErr := f.client.doWithBytesResponse(req)
|
||||
|
||||
if responseErr != nil {
|
||||
return fileContent, responseErr
|
||||
}
|
||||
|
||||
fileContent.Data = data
|
||||
fileContent.ContentType = headers.Get("Content-Type")
|
||||
|
||||
contentDisposition := headers.Get("Content-Disposition")
|
||||
|
||||
if contentDisposition != "" {
|
||||
_, params, err := mime.ParseMediaType(contentDisposition)
|
||||
|
||||
if err == nil {
|
||||
fileContent.FileName = params["filename"]
|
||||
}
|
||||
}
|
||||
|
||||
return fileContent, nil
|
||||
}
|
||||
|
||||
// Delete removes a file from the Onspring API.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context for the request
|
||||
// - recordId: The id of the record
|
||||
// - fieldId: The id of the field
|
||||
// - fileId: The id of the file
|
||||
//
|
||||
// Returns:
|
||||
// - error: An error if the request fails
|
||||
func (f *FilesEndpoint) Delete(ctx context.Context, recordId, fieldId, fileId int) error {
|
||||
path := fileBasePath(recordId, fieldId, fileId)
|
||||
req, requestCreationErr := f.client.newRequest(ctx, http.MethodDelete, path, nil, nil)
|
||||
|
||||
if requestCreationErr != nil {
|
||||
return requestCreationErr
|
||||
}
|
||||
|
||||
return f.client.do(req)
|
||||
}
|
||||
|
||||
// Save uploads a file to the Onspring API.
|
||||
//
|
||||
// Parameters:
|
||||
// - ctx: The context for the request
|
||||
// - saveReq: The file upload request containing record id, field id, file name, contents, and optional metadata
|
||||
//
|
||||
// Returns:
|
||||
// - SaveFileResponse: The response containing the saved file's id
|
||||
// - error: An error if the request fails
|
||||
func (f *FilesEndpoint) Save(ctx context.Context, saveReq SaveFileRequest) (SaveFileResponse, error) {
|
||||
var response SaveFileResponse
|
||||
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
|
||||
_ = writer.WriteField("RecordId", strconv.Itoa(saveReq.RecordId))
|
||||
_ = writer.WriteField("FieldId", strconv.Itoa(saveReq.FieldId))
|
||||
|
||||
if saveReq.Notes != "" {
|
||||
_ = writer.WriteField("Notes", saveReq.Notes)
|
||||
}
|
||||
|
||||
if saveReq.ModifiedDate != "" {
|
||||
_ = writer.WriteField("ModifiedDate", saveReq.ModifiedDate)
|
||||
}
|
||||
|
||||
filePart, err := writer.CreateFormFile("File", saveReq.FileName)
|
||||
|
||||
if err != nil {
|
||||
return response, fmt.Errorf("failed to create form file: %w", err)
|
||||
}
|
||||
|
||||
_, err = io.Copy(filePart, saveReq.FileContents)
|
||||
|
||||
if err != nil {
|
||||
return response, fmt.Errorf("failed to copy file contents: %w", err)
|
||||
}
|
||||
|
||||
err = writer.Close()
|
||||
|
||||
if err != nil {
|
||||
return response, fmt.Errorf("failed to close multipart writer: %w", err)
|
||||
}
|
||||
|
||||
req, requestCreationErr := f.client.newMultipartRequest(ctx, filesPath, body, writer.FormDataContentType())
|
||||
|
||||
if requestCreationErr != nil {
|
||||
return response, requestCreationErr
|
||||
}
|
||||
|
||||
responseErr := f.client.doWithJsonResponse(req, &response)
|
||||
|
||||
if responseErr != nil {
|
||||
return response, responseErr
|
||||
}
|
||||
|
||||
return response, nil
|
||||
}
|
||||
Reference in New Issue
Block a user