checkpoint: create and edit media attachments
This commit is contained in:
parent
eb016b96e9
commit
f3a5887cb9
5 changed files with 211 additions and 16 deletions
|
@ -1,8 +1,14 @@
|
||||||
package client
|
package client
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"mime/multipart"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
|
||||||
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
"codeflow.dananglin.me.uk/apollo/enbas/internal/model"
|
||||||
)
|
)
|
||||||
|
@ -31,12 +37,123 @@ func (g *Client) GetMediaAttachment(mediaAttachmentID string) (model.Attachment,
|
||||||
return attachment, nil
|
return attachment, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
//type CreateMediaAttachmentForm struct {
|
func (g *Client) CreateMediaAttachment(path, description, focus string) (model.Attachment, error) {
|
||||||
// Description string
|
file, err := os.Open(path)
|
||||||
// Focus string
|
if err != nil {
|
||||||
// Filepath string
|
return model.Attachment{}, fmt.Errorf("unable to open the file: %w", err)
|
||||||
//}
|
}
|
||||||
//
|
defer file.Close()
|
||||||
//func (g *Client) CreateMediaAttachment(form CreateMediaAttachmentForm) (model.Attachment, error) {
|
|
||||||
// return model.Attachment{}, nil
|
// create the request body using a writer from the multipart package
|
||||||
//}
|
requestBody := bytes.Buffer{}
|
||||||
|
requestBodyWriter := multipart.NewWriter(&requestBody)
|
||||||
|
|
||||||
|
filename := filepath.Base(path)
|
||||||
|
|
||||||
|
part, err := requestBodyWriter.CreateFormFile("file", filename)
|
||||||
|
if err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf("unable to create the new part: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.Copy(part, file); err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf("unable to copy the file contents to the form: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the description
|
||||||
|
if description != "" {
|
||||||
|
descriptionFormFieldWriter, err := requestBodyWriter.CreateFormField("description")
|
||||||
|
if err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf(
|
||||||
|
"unable to create the writer for the 'description' form field: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.WriteString(descriptionFormFieldWriter, description); err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf(
|
||||||
|
"unable to write the description to the form: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the focus values
|
||||||
|
if focus != "" {
|
||||||
|
focusFormFieldWriter, err := requestBodyWriter.CreateFormField("focus")
|
||||||
|
if err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf(
|
||||||
|
"unable to create the writer for the 'focus' form field: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := io.WriteString(focusFormFieldWriter, focus); err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf(
|
||||||
|
"unable to write the focus values to the form: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := requestBodyWriter.Close(); err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf("unable to close the writer: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
url := g.Authentication.Instance + baseMediaPath
|
||||||
|
|
||||||
|
var attachment model.Attachment
|
||||||
|
|
||||||
|
params := requestParameters{
|
||||||
|
httpMethod: http.MethodPost,
|
||||||
|
url: url,
|
||||||
|
requestBody: &requestBody,
|
||||||
|
contentType: requestBodyWriter.FormDataContentType(),
|
||||||
|
output: &attachment,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.sendRequest(params); err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf(
|
||||||
|
"received an error after sending the request to create the media attachment: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachment, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *Client) UpdateMediaAttachment(mediaAttachmentID, description, focus string) (model.Attachment, error) {
|
||||||
|
form := struct {
|
||||||
|
Description string `json:"description"`
|
||||||
|
Focus string `json:"focus"`
|
||||||
|
}{
|
||||||
|
Description: description,
|
||||||
|
Focus: focus,
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(form)
|
||||||
|
if err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf("unable to marshal the form: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
requestBody := bytes.NewBuffer(data)
|
||||||
|
url := g.Authentication.Instance + baseMediaPath + "/" + mediaAttachmentID
|
||||||
|
|
||||||
|
var updatedMediaAttachment model.Attachment
|
||||||
|
|
||||||
|
params := requestParameters{
|
||||||
|
httpMethod: http.MethodPut,
|
||||||
|
url: url,
|
||||||
|
requestBody: requestBody,
|
||||||
|
contentType: applicationJSON,
|
||||||
|
output: &updatedMediaAttachment,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := g.sendRequest(params); err != nil {
|
||||||
|
return model.Attachment{}, fmt.Errorf(
|
||||||
|
"received an error after sending the request to update the media attachment: %w",
|
||||||
|
err,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedMediaAttachment, nil
|
||||||
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ func (c *CreateExecutor) Execute() error {
|
||||||
funcMap := map[string]func(*client.Client) error{
|
funcMap := map[string]func(*client.Client) error{
|
||||||
resourceList: c.createList,
|
resourceList: c.createList,
|
||||||
resourceStatus: c.createStatus,
|
resourceStatus: c.createStatus,
|
||||||
|
resourceMediaAttachment: c.createMediaAttachment,
|
||||||
}
|
}
|
||||||
|
|
||||||
doFunc, ok := funcMap[c.resourceType]
|
doFunc, ok := funcMap[c.resourceType]
|
||||||
|
@ -153,3 +154,18 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *CreateExecutor) createMediaAttachment(gtsClient *client.Client) error {
|
||||||
|
if c.fromFile == "" {
|
||||||
|
return FlagNotSetError{flagText: flagFromFile}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := gtsClient.CreateMediaAttachment(c.fromFile, c.description, c.focus)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create the media attachment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.printer.PrintSuccess("Successfully created the media attachment with ID: " + attachment.ID)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ func (e *EditExecutor) Execute() error {
|
||||||
|
|
||||||
funcMap := map[string]func(*client.Client) error{
|
funcMap := map[string]func(*client.Client) error{
|
||||||
resourceList: e.editList,
|
resourceList: e.editList,
|
||||||
|
resourceMediaAttachment: e.editMediaAttachment,
|
||||||
}
|
}
|
||||||
|
|
||||||
doFunc, ok := funcMap[e.resourceType]
|
doFunc, ok := funcMap[e.resourceType]
|
||||||
|
@ -57,8 +58,41 @@ func (e *EditExecutor) editList(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to update the list: %w", err)
|
return fmt.Errorf("unable to update the list: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
e.printer.PrintSuccess("Successfully updated the list.")
|
e.printer.PrintSuccess("Successfully edited the list.")
|
||||||
e.printer.PrintList(updatedList)
|
e.printer.PrintList(updatedList)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *EditExecutor) editMediaAttachment(gtsClient *client.Client) error {
|
||||||
|
expectedNumMediaAttachmentIDs := 1
|
||||||
|
if !e.attachmentIDs.ExpectedLength(expectedNumMediaAttachmentIDs) {
|
||||||
|
return fmt.Errorf(
|
||||||
|
"received an unexpected number of media attachment IDs: want %d",
|
||||||
|
expectedNumMediaAttachmentIDs,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := gtsClient.GetMediaAttachment(e.attachmentIDs[0])
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to get the media attachment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
description := e.description
|
||||||
|
if description == "" {
|
||||||
|
description = attachment.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
focus := e.focus
|
||||||
|
if focus == "" {
|
||||||
|
focus = fmt.Sprintf("%f,%f", attachment.Meta.Focus.X, attachment.Meta.Focus.Y)
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err = gtsClient.UpdateMediaAttachment(e.attachmentIDs[0], description, focus); err != nil {
|
||||||
|
return fmt.Errorf("unable to update the media attachment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.printer.PrintSuccess("Successfully edited the media attachment.")
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -121,12 +121,15 @@ type CreateExecutor struct {
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
config *config.Config
|
config *config.Config
|
||||||
addPoll bool
|
addPoll bool
|
||||||
|
attachmentIDs internalFlag.StringSliceValue
|
||||||
content string
|
content string
|
||||||
contentType string
|
contentType string
|
||||||
|
description string
|
||||||
federated bool
|
federated bool
|
||||||
likeable bool
|
likeable bool
|
||||||
replyable bool
|
replyable bool
|
||||||
boostable bool
|
boostable bool
|
||||||
|
focus string
|
||||||
fromFile string
|
fromFile string
|
||||||
inReplyTo string
|
inReplyTo string
|
||||||
language string
|
language string
|
||||||
|
@ -150,6 +153,7 @@ func NewCreateExecutor(
|
||||||
FlagSet: flag.NewFlagSet("create", flag.ExitOnError),
|
FlagSet: flag.NewFlagSet("create", flag.ExitOnError),
|
||||||
printer: printer,
|
printer: printer,
|
||||||
config: config,
|
config: config,
|
||||||
|
attachmentIDs: internalFlag.NewStringSliceValue(),
|
||||||
pollExpiresIn: internalFlag.NewTimeDurationValue(),
|
pollExpiresIn: internalFlag.NewTimeDurationValue(),
|
||||||
pollOptions: internalFlag.NewStringSliceValue(),
|
pollOptions: internalFlag.NewStringSliceValue(),
|
||||||
sensitive: internalFlag.NewBoolPtrValue(),
|
sensitive: internalFlag.NewBoolPtrValue(),
|
||||||
|
@ -158,12 +162,15 @@ func NewCreateExecutor(
|
||||||
exe.Usage = usage.ExecutorUsageFunc("create", "Creates a specific resource", exe.FlagSet)
|
exe.Usage = usage.ExecutorUsageFunc("create", "Creates a specific resource", exe.FlagSet)
|
||||||
|
|
||||||
exe.BoolVar(&exe.addPoll, "add-poll", false, "Set to true to add a poll when creating a status")
|
exe.BoolVar(&exe.addPoll, "add-poll", false, "Set to true to add a poll when creating a status")
|
||||||
|
exe.Var(&exe.attachmentIDs, "attachment-id", "The ID of the media attachment")
|
||||||
exe.StringVar(&exe.content, "content", "", "The content of the created resource")
|
exe.StringVar(&exe.content, "content", "", "The content of the created resource")
|
||||||
exe.StringVar(&exe.contentType, "content-type", "plain", "The type that the contents should be parsed from (valid values are plain and markdown)")
|
exe.StringVar(&exe.contentType, "content-type", "plain", "The type that the contents should be parsed from (valid values are plain and markdown)")
|
||||||
|
exe.StringVar(&exe.description, "description", "", "The description of the media attachment that will be used as the alt-text")
|
||||||
exe.BoolVar(&exe.federated, "enable-federation", true, "Set to true to federate the status beyond the local timelines")
|
exe.BoolVar(&exe.federated, "enable-federation", true, "Set to true to federate the status beyond the local timelines")
|
||||||
exe.BoolVar(&exe.likeable, "enable-likes", true, "Set to true to allow the status to be liked (favourited)")
|
exe.BoolVar(&exe.likeable, "enable-likes", true, "Set to true to allow the status to be liked (favourited)")
|
||||||
exe.BoolVar(&exe.replyable, "enable-replies", true, "Set to true to allow viewers to reply to the status")
|
exe.BoolVar(&exe.replyable, "enable-replies", true, "Set to true to allow viewers to reply to the status")
|
||||||
exe.BoolVar(&exe.boostable, "enable-reposts", true, "Set to true to allow the status to be reposted (boosted) by others")
|
exe.BoolVar(&exe.boostable, "enable-reposts", true, "Set to true to allow the status to be reposted (boosted) by others")
|
||||||
|
exe.StringVar(&exe.focus, "focus", "", "The focus of the media file")
|
||||||
exe.StringVar(&exe.fromFile, "from-file", "", "The file path where to read the contents from")
|
exe.StringVar(&exe.fromFile, "from-file", "", "The file path where to read the contents from")
|
||||||
exe.StringVar(&exe.inReplyTo, "in-reply-to", "", "The ID of the status that you want to reply to")
|
exe.StringVar(&exe.inReplyTo, "in-reply-to", "", "The ID of the status that you want to reply to")
|
||||||
exe.StringVar(&exe.language, "language", "", "The ISO 639 language code for this status")
|
exe.StringVar(&exe.language, "language", "", "The ISO 639 language code for this status")
|
||||||
|
@ -213,6 +220,9 @@ type EditExecutor struct {
|
||||||
*flag.FlagSet
|
*flag.FlagSet
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
attachmentIDs internalFlag.StringSliceValue
|
||||||
|
description string
|
||||||
|
focus string
|
||||||
listID string
|
listID string
|
||||||
listTitle string
|
listTitle string
|
||||||
listRepliesPolicy string
|
listRepliesPolicy string
|
||||||
|
@ -227,10 +237,14 @@ func NewEditExecutor(
|
||||||
FlagSet: flag.NewFlagSet("edit", flag.ExitOnError),
|
FlagSet: flag.NewFlagSet("edit", flag.ExitOnError),
|
||||||
printer: printer,
|
printer: printer,
|
||||||
config: config,
|
config: config,
|
||||||
|
attachmentIDs: internalFlag.NewStringSliceValue(),
|
||||||
}
|
}
|
||||||
|
|
||||||
exe.Usage = usage.ExecutorUsageFunc("edit", "Edit a specific resource", exe.FlagSet)
|
exe.Usage = usage.ExecutorUsageFunc("edit", "Edit a specific resource", exe.FlagSet)
|
||||||
|
|
||||||
|
exe.Var(&exe.attachmentIDs, "attachment-id", "The ID of the media attachment")
|
||||||
|
exe.StringVar(&exe.description, "description", "", "The description of the media attachment that will be used as the alt-text")
|
||||||
|
exe.StringVar(&exe.focus, "focus", "", "The focus of the media file")
|
||||||
exe.StringVar(&exe.listID, "list-id", "", "The ID of the list in question")
|
exe.StringVar(&exe.listID, "list-id", "", "The ID of the list in question")
|
||||||
exe.StringVar(&exe.listTitle, "list-title", "", "The title of the list")
|
exe.StringVar(&exe.listTitle, "list-title", "", "The title of the list")
|
||||||
exe.StringVar(&exe.listRepliesPolicy, "list-replies-policy", "", "The replies policy of the list")
|
exe.StringVar(&exe.listRepliesPolicy, "list-replies-policy", "", "The replies policy of the list")
|
||||||
|
|
|
@ -32,6 +32,10 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The type that the contents should be parsed from (valid values are plain and markdown)"
|
"description": "The type that the contents should be parsed from (valid values are plain and markdown)"
|
||||||
},
|
},
|
||||||
|
"description": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The description of the media attachment that will be used as the alt-text"
|
||||||
|
},
|
||||||
"enable-federation": {
|
"enable-federation": {
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"description": "Set to true to federate the status beyond the local timelines"
|
"description": "Set to true to federate the status beyond the local timelines"
|
||||||
|
@ -56,6 +60,10 @@
|
||||||
"type": "bool",
|
"type": "bool",
|
||||||
"description": "Set to true to exclude statuses that are a reply to another status"
|
"description": "Set to true to exclude statuses that are a reply to another status"
|
||||||
},
|
},
|
||||||
|
"focus": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The focus of the media file"
|
||||||
|
},
|
||||||
"from": {
|
"from": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The resource type to action the target resource from (e.g. status)"
|
"description": "The resource type to action the target resource from (e.g. status)"
|
||||||
|
@ -234,12 +242,15 @@
|
||||||
"additionalFields": [],
|
"additionalFields": [],
|
||||||
"flags": [
|
"flags": [
|
||||||
{ "flag": "add-poll", "default": "false" },
|
{ "flag": "add-poll", "default": "false" },
|
||||||
|
{ "flag": "attachment-id", "fieldName": "attachmentIDs" },
|
||||||
{ "flag": "content", "default": "" },
|
{ "flag": "content", "default": "" },
|
||||||
{ "flag": "content-type", "default": "plain" },
|
{ "flag": "content-type", "default": "plain" },
|
||||||
|
{ "flag": "description", "default": "" },
|
||||||
{ "flag": "enable-federation", "fieldName": "federated", "default": "true" },
|
{ "flag": "enable-federation", "fieldName": "federated", "default": "true" },
|
||||||
{ "flag": "enable-likes", "fieldName": "likeable", "default": "true" },
|
{ "flag": "enable-likes", "fieldName": "likeable", "default": "true" },
|
||||||
{ "flag": "enable-replies", "fieldName": "replyable", "default": "true" },
|
{ "flag": "enable-replies", "fieldName": "replyable", "default": "true" },
|
||||||
{ "flag": "enable-reposts", "fieldName": "boostable", "default": "true" },
|
{ "flag": "enable-reposts", "fieldName": "boostable", "default": "true" },
|
||||||
|
{ "flag": "focus", "default": "" },
|
||||||
{ "flag": "from-file", "default": "" },
|
{ "flag": "from-file", "default": "" },
|
||||||
{ "flag": "in-reply-to", "default": "" },
|
{ "flag": "in-reply-to", "default": "" },
|
||||||
{ "flag": "language", "default": "" },
|
{ "flag": "language", "default": "" },
|
||||||
|
@ -271,6 +282,9 @@
|
||||||
"edit": {
|
"edit": {
|
||||||
"additionalFields": [],
|
"additionalFields": [],
|
||||||
"flags": [
|
"flags": [
|
||||||
|
{ "flag": "attachment-id", "fieldName": "attachmentIDs" },
|
||||||
|
{ "flag": "description", "default": "" },
|
||||||
|
{ "flag": "focus", "default": "" },
|
||||||
{ "flag": "list-id", "fieldName": "listID", "default": ""},
|
{ "flag": "list-id", "fieldName": "listID", "default": ""},
|
||||||
{ "flag": "list-title", "default": "" },
|
{ "flag": "list-title", "default": "" },
|
||||||
{ "flag": "list-replies-policy", "default": "" },
|
{ "flag": "list-replies-policy", "default": "" },
|
||||||
|
|
Loading…
Reference in a new issue