Compare commits
3 commits
795e344198
...
2e455fc9f8
Author | SHA1 | Date | |
---|---|---|---|
2e455fc9f8 | |||
1debd1bbf7 | |||
41770e2b59 |
5 changed files with 235 additions and 42 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
|
||||||
|
}
|
||||||
|
|
|
@ -38,18 +38,19 @@ func (g *Client) GetStatus(statusID string) (model.Status, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateStatusForm struct {
|
type CreateStatusForm struct {
|
||||||
Content string `json:"status"`
|
Content string `json:"status"`
|
||||||
InReplyTo string `json:"in_reply_to_id"`
|
InReplyTo string `json:"in_reply_to_id"`
|
||||||
Language string `json:"language"`
|
Language string `json:"language"`
|
||||||
SpoilerText string `json:"spoiler_text"`
|
SpoilerText string `json:"spoiler_text"`
|
||||||
Boostable bool `json:"boostable"`
|
Boostable bool `json:"boostable"`
|
||||||
Federated bool `json:"federated"`
|
Federated bool `json:"federated"`
|
||||||
Likeable bool `json:"likeable"`
|
Likeable bool `json:"likeable"`
|
||||||
Replyable bool `json:"replyable"`
|
Replyable bool `json:"replyable"`
|
||||||
Sensitive bool `json:"sensitive"`
|
Sensitive bool `json:"sensitive"`
|
||||||
Poll *CreateStatusPollForm `json:"poll,omitempty"`
|
Poll *CreateStatusPollForm `json:"poll,omitempty"`
|
||||||
ContentType model.StatusContentType `json:"content_type"`
|
ContentType model.StatusContentType `json:"content_type"`
|
||||||
Visibility model.StatusVisibility `json:"visibility"`
|
Visibility model.StatusVisibility `json:"visibility"`
|
||||||
|
AttachmentIDs []string `json:"media_ids,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type CreateStatusPollForm struct {
|
type CreateStatusPollForm struct {
|
||||||
|
|
|
@ -27,7 +27,9 @@ type CreateExecutor struct {
|
||||||
sensitive *bool
|
sensitive *bool
|
||||||
content string
|
content string
|
||||||
contentType string
|
contentType string
|
||||||
|
description string
|
||||||
fromFile string
|
fromFile string
|
||||||
|
focus string
|
||||||
inReplyTo string
|
inReplyTo string
|
||||||
language string
|
language string
|
||||||
resourceType string
|
resourceType string
|
||||||
|
@ -37,6 +39,7 @@ type CreateExecutor struct {
|
||||||
visibility string
|
visibility string
|
||||||
pollExpiresIn TimeDurationFlagValue
|
pollExpiresIn TimeDurationFlagValue
|
||||||
pollOptions MultiStringFlagValue
|
pollOptions MultiStringFlagValue
|
||||||
|
attachmentIDs MultiStringFlagValue
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCreateExecutor(printer *printer.Printer, config *config.Config, name, summary string) *CreateExecutor {
|
func NewCreateExecutor(printer *printer.Printer, config *config.Config, name, summary string) *CreateExecutor {
|
||||||
|
@ -72,6 +75,7 @@ func NewCreateExecutor(printer *printer.Printer, config *config.Config, name, su
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
createExe.Var(&createExe.attachmentIDs, flagAttachmentID, "Specify the ID of the media attachment to add to the status")
|
||||||
|
|
||||||
// Flags specifically for polls
|
// Flags specifically for polls
|
||||||
createExe.BoolVar(&createExe.addPoll, flagAddPoll, false, "Add a poll to the status")
|
createExe.BoolVar(&createExe.addPoll, flagAddPoll, false, "Add a poll to the status")
|
||||||
|
@ -83,6 +87,8 @@ func NewCreateExecutor(printer *printer.Printer, config *config.Config, name, su
|
||||||
// Flags for lists
|
// Flags for lists
|
||||||
createExe.StringVar(&createExe.listTitle, flagListTitle, "", "Specify the title of the list")
|
createExe.StringVar(&createExe.listTitle, flagListTitle, "", "Specify the title of the list")
|
||||||
createExe.StringVar(&createExe.listRepliesPolicy, flagListRepliesPolicy, "list", "Specify the policy of the replies for this list (valid values are followed, list and none)")
|
createExe.StringVar(&createExe.listRepliesPolicy, flagListRepliesPolicy, "list", "Specify the policy of the replies for this list (valid values are followed, list and none)")
|
||||||
|
createExe.StringVar(&createExe.description, flagDescription, "", "The description of the media attachment that will be used as the alt-text")
|
||||||
|
createExe.StringVar(&createExe.focus, flagFocus, "", "The focus of the media file")
|
||||||
|
|
||||||
createExe.Usage = commandUsageFunc(name, summary, createExe.FlagSet)
|
createExe.Usage = commandUsageFunc(name, summary, createExe.FlagSet)
|
||||||
|
|
||||||
|
@ -100,8 +106,9 @@ 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]
|
||||||
|
@ -156,12 +163,19 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
|
||||||
return fmt.Errorf("unable to get the status contents from %q: %w", c.fromFile, err)
|
return fmt.Errorf("unable to get the status contents from %q: %w", c.fromFile, err)
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
return EmptyContentError{
|
if len(c.attachmentIDs) == 0 {
|
||||||
ResourceType: resourceStatus,
|
// TODO: revisit this error type
|
||||||
Hint: "please use --" + flagContent + " or --" + flagFromFile,
|
return EmptyContentError{
|
||||||
|
ResourceType: resourceStatus,
|
||||||
|
Hint: "please use --" + flagContent + " or --" + flagFromFile,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if len(c.attachmentIDs) > 0 && c.addPoll {
|
||||||
|
return fmt.Errorf("attaching media to a poll is not allowed")
|
||||||
|
}
|
||||||
|
|
||||||
preferences, err := gtsClient.GetUserPreferences()
|
preferences, err := gtsClient.GetUserPreferences()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Println("WARNING: Unable to get your posting preferences: %w", err)
|
fmt.Println("WARNING: Unable to get your posting preferences: %w", err)
|
||||||
|
@ -196,18 +210,23 @@ func (c *CreateExecutor) createStatus(gtsClient *client.Client) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
form := client.CreateStatusForm{
|
form := client.CreateStatusForm{
|
||||||
Content: content,
|
Content: content,
|
||||||
ContentType: parsedContentType,
|
ContentType: parsedContentType,
|
||||||
Language: language,
|
Language: language,
|
||||||
SpoilerText: c.spoilerText,
|
SpoilerText: c.spoilerText,
|
||||||
Boostable: c.boostable,
|
Boostable: c.boostable,
|
||||||
Federated: c.federated,
|
Federated: c.federated,
|
||||||
InReplyTo: c.inReplyTo,
|
InReplyTo: c.inReplyTo,
|
||||||
Likeable: c.likeable,
|
Likeable: c.likeable,
|
||||||
Replyable: c.replyable,
|
Replyable: c.replyable,
|
||||||
Sensitive: sensitive,
|
Sensitive: sensitive,
|
||||||
Visibility: parsedVisibility,
|
Visibility: parsedVisibility,
|
||||||
Poll: nil,
|
Poll: nil,
|
||||||
|
AttachmentIDs: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(c.attachmentIDs) > 0 {
|
||||||
|
form.AttachmentIDs = c.attachmentIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.addPoll {
|
if c.addPoll {
|
||||||
|
@ -235,3 +254,19 @@ 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 following media attachment:")
|
||||||
|
c.printer.PrintMediaAttachment(attachment)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,9 @@ type EditExecutor struct {
|
||||||
|
|
||||||
printer *printer.Printer
|
printer *printer.Printer
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
attachmentID string
|
||||||
|
description string
|
||||||
|
focus string
|
||||||
resourceType string
|
resourceType string
|
||||||
listID string
|
listID string
|
||||||
listTitle string
|
listTitle string
|
||||||
|
@ -29,10 +32,13 @@ func NewEditExecutor(printer *printer.Printer, config *config.Config, name, summ
|
||||||
config: config,
|
config: config,
|
||||||
}
|
}
|
||||||
|
|
||||||
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to update")
|
editExe.StringVar(&editExe.resourceType, flagType, "", "Specify the type of resource to edit")
|
||||||
editExe.StringVar(&editExe.listID, flagListID, "", "Specify the ID of the list to update")
|
editExe.StringVar(&editExe.attachmentID, flagAttachmentID, "", "Specify the ID of the media attachment to edit")
|
||||||
|
editExe.StringVar(&editExe.listID, flagListID, "", "Specify the ID of the list to edit")
|
||||||
editExe.StringVar(&editExe.listTitle, flagListTitle, "", "Specify the title of the list")
|
editExe.StringVar(&editExe.listTitle, flagListTitle, "", "Specify the title of the list")
|
||||||
editExe.StringVar(&editExe.listRepliesPolicy, flagListRepliesPolicy, "", "Specify the policy of the replies for this list (valid values are followed, list and none)")
|
editExe.StringVar(&editExe.listRepliesPolicy, flagListRepliesPolicy, "", "Specify the policy of the replies for this list (valid values are followed, list and none)")
|
||||||
|
editExe.StringVar(&editExe.description, flagDescription, "", "The description of the media attachment that will be used as the alt-text")
|
||||||
|
editExe.StringVar(&editExe.focus, flagFocus, "", "The focus of the media file")
|
||||||
|
|
||||||
editExe.Usage = commandUsageFunc(name, summary, editExe.FlagSet)
|
editExe.Usage = commandUsageFunc(name, summary, editExe.FlagSet)
|
||||||
|
|
||||||
|
@ -45,7 +51,8 @@ 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]
|
||||||
|
@ -89,8 +96,39 @@ 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 {
|
||||||
|
if e.attachmentID == "" {
|
||||||
|
return FlagNotSetError{flagText: flagAttachmentID}
|
||||||
|
}
|
||||||
|
|
||||||
|
attachment, err := gtsClient.GetMediaAttachment(e.attachmentID)
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
updatedAttachment, err := gtsClient.UpdateMediaAttachment(e.attachmentID, description, focus)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to update the media attachment: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
e.printer.PrintSuccess("Successfully edited the media attachment.")
|
||||||
|
e.printer.PrintMediaAttachment(updatedAttachment)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -16,12 +16,14 @@ const (
|
||||||
flagBrowser = "browser"
|
flagBrowser = "browser"
|
||||||
flagContentType = "content-type"
|
flagContentType = "content-type"
|
||||||
flagContent = "content"
|
flagContent = "content"
|
||||||
|
flagDescription = "description"
|
||||||
flagEnableFederation = "enable-federation"
|
flagEnableFederation = "enable-federation"
|
||||||
flagEnableLikes = "enable-likes"
|
flagEnableLikes = "enable-likes"
|
||||||
flagEnableReplies = "enable-replies"
|
flagEnableReplies = "enable-replies"
|
||||||
flagEnableReposts = "enable-reposts"
|
flagEnableReposts = "enable-reposts"
|
||||||
flagExcludeBoosts = "exclude-boosts"
|
flagExcludeBoosts = "exclude-boosts"
|
||||||
flagExcludeReplies = "exclude-replies"
|
flagExcludeReplies = "exclude-replies"
|
||||||
|
flagFocus = "focus"
|
||||||
flagFrom = "from"
|
flagFrom = "from"
|
||||||
flagFromFile = "from-file"
|
flagFromFile = "from-file"
|
||||||
flagFull = "full"
|
flagFull = "full"
|
||||||
|
|
Loading…
Reference in a new issue