hugo-micropub/storage.go

134 lines
3.6 KiB
Go

package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"io/ioutil"
"net/http"
"net/url"
"strings"
)
type Storage interface {
CreateFile(path string, file string, message string) (err error)
UpdateFile(path string, file string, message string) (err error)
ReadFile(path string) (content string, sha string, exists bool, err error)
}
// Gitea
type Gitea struct {
endpoint string
token string
}
type giteaCommitRequest struct {
Content string `json:"content"`
Message string `json:"message"`
SHA string `json:"sha,omitempty"`
}
type giteaReadResponse struct {
Type string `json:"type"`
Content string `json:"content"`
SHA string `json:"sha"`
}
type giteaErrorResponse struct {
Message string `json:"message"`
}
func (gitea *Gitea) CreateFile(path string, file string, message string) (err error) {
request := &giteaCommitRequest{
Content: base64.StdEncoding.EncodeToString([]byte(file)),
Message: message,
}
bytesRepresentation, err := json.Marshal(request)
if err != nil {
return errors.New("failed to marshal json before committing")
}
resp, err := http.Post(gitea.endpoint+url.QueryEscape(path)+"?access_token="+gitea.token, "application/json", bytes.NewBuffer(bytesRepresentation))
if err != nil || resp.StatusCode != 201 {
return errors.New("failed to create file in repo")
}
return nil
}
func (gitea *Gitea) UpdateFile(path string, file string, message string) (err error) {
_, sha, exists, err := gitea.ReadFile(path)
if err != nil {
return err
}
if !exists {
// File doesn't exist, create it
return gitea.CreateFile(path, file, message)
}
request := &giteaCommitRequest{
Content: base64.StdEncoding.EncodeToString([]byte(file)),
Message: message,
SHA: sha,
}
bytesRepresentation, err := json.Marshal(request)
if err != nil {
return errors.New("failed to marshal json before committing")
}
req, err := http.NewRequest(http.MethodPut, gitea.endpoint+url.QueryEscape(path)+"?access_token="+gitea.token, bytes.NewBuffer(bytesRepresentation))
if err != nil {
return errors.New("error making update request")
}
req.Header.Set("Content-type", "application/json")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil || resp.StatusCode != 200 {
return errors.New("failed to update file in repo")
}
return nil
}
func (gitea *Gitea) ReadFile(path string) (content string, sha string, exists bool, err error) {
exists = false
resp, err := http.Get(gitea.endpoint + url.QueryEscape(path) + "?access_token=" + gitea.token)
if err != nil || resp.StatusCode != 200 {
if resp != nil {
defer resp.Body.Close()
body, readErr := ioutil.ReadAll(resp.Body)
if readErr != nil {
err = errors.New("failed reading Gitea error response")
return
}
errorResponse := &giteaErrorResponse{}
marshalErr := json.Unmarshal(body, &errorResponse)
if marshalErr != nil {
err = errors.New("failed parsing Gitea error response")
return
}
exists = !strings.Contains(errorResponse.Message, "does not exist")
if !exists {
return
}
}
err = errors.New("failed to read file in repo")
return
}
exists = true
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
err = errors.New("failed reading file in repo")
return
}
readResponse := &giteaReadResponse{}
err = json.Unmarshal(body, &readResponse)
if err != nil {
err = errors.New("failed parsing Gitea response")
return
}
decodedContentBytes, err := base64.StdEncoding.DecodeString(readResponse.Content)
if err != nil {
err = errors.New("failed decoding file content")
}
content = string(decodedContentBytes)
sha = readResponse.SHA
return
}