[MM-56073] MMCTL delete post command (#27539)

Co-authored-by: Ben Schumacher <ben.schumacher@mattermost.com>
Этот коммит содержится в:
Ben Cooke
2024-10-08 10:45:31 -04:00
коммит произвёл GitHub
родитель a671f80d2c
Коммит b3c7ef0b97
39 изменённых файлов: 1246 добавлений и 152 удалений

Просмотреть файл

@@ -41,6 +41,22 @@ var PostListCmd = &cobra.Command{
RunE: withClient(postListCmdF),
}
var PostDeleteCmd = &cobra.Command{
Use: "delete [posts]",
Short: "Mark posts as deleted or permanently delete posts with the --permanent flag",
Long: `This command will mark the post as deleted and remove it from the user's clients, but it does not permanently delete the post from the database. Please use the --permanent flag to permanently delete a post and its attachments from your database.`,
Example: ` # Mark Post as deleted
$ mmctl post delete udjmt396tjghi8wnsk3a1qs1sw
# Permanently delete a post and it's file contents from the database and filestore
$ mmctl post delete udjmt396tjghi8wnsk3a1qs1sw --permanent
# Permanently delete multiple posts and their file contents from the database and filestore
$ mmctl post delete udjmt396tjghi8wnsk3a1qs1sw 7jgcjt7tyjyyu83qz81wo84w6o --permanent`,
Args: cobra.MinimumNArgs(1),
RunE: withClient(deletePostsCmdF),
}
const (
ISO8601Layout = "2006-01-02T15:04:05-07:00"
PostTimeFormat = "2006-01-02 15:04:05-07:00"
@@ -55,9 +71,13 @@ func init() {
PostListCmd.Flags().BoolP("follow", "f", false, "Output appended data as new messages are posted to the channel")
PostListCmd.Flags().StringP("since", "s", "", "List messages posted after a certain time (ISO 8601)")
PostDeleteCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the post and a DB backup has been performed")
PostDeleteCmd.Flags().Bool("permanent", false, "Permanently delete the post and its contents from the database")
PostCmd.AddCommand(
PostCreateCmd,
PostListCmd,
PostDeleteCmd,
)
RootCmd.AddCommand(PostCmd)
@@ -217,3 +237,42 @@ func postListCmdF(c client.Client, cmd *cobra.Command, args []string) error {
}
return multiErr.ErrorOrNil()
}
func deletePostsCmdF(c client.Client, cmd *cobra.Command, args []string) error {
permanent, err := cmd.Flags().GetBool("permanent")
if err != nil {
return err
}
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag && permanent {
if err = getConfirmation("Are you sure you want to delete the posts specified?", true); err != nil {
return err
}
}
var result *multierror.Error
var deleteFunc func(ctx context.Context, postID string) (*model.Response, error)
if permanent {
deleteFunc = c.PermanentDeletePost
} else {
deleteFunc = c.DeletePost
}
for _, postID := range args {
isValidId := model.IsValidId(postID)
if !isValidId {
printer.PrintError(fmt.Sprintf("Invalid postID: %s", postID))
result = multierror.Append(result, err)
continue
}
if _, err := deleteFunc(context.TODO(), postID); err != nil {
printer.PrintError(fmt.Sprintf("Error deleting post: %s. Error: %s", postID, err.Error()))
result = multierror.Append(result, err)
continue
}
printer.Print(fmt.Sprintf("%s successfully deleted", postID))
}
return result.ErrorOrNil()
}

Просмотреть файл

@@ -5,6 +5,7 @@ package commands
import (
"context"
"net/http"
"time"
"github.com/mattermost/mattermost/server/public/model"
@@ -257,3 +258,122 @@ func (s *MmctlUnitTestSuite) TestPostListCmdF() {
s.Len(printer.GetErrorLines(), 0)
})
}
func (s *MmctlUnitTestSuite) TestDeletePostsCmdF() {
postID1 := "ux9bxc1b8bf1zdoj1tfu14836e"
postID2 := "ux9bxc1b8bf1zdoj1tfu14836f"
s.Run("invalid post id", func() {
id := "invalid-id"
cmd := &cobra.Command{}
cmd.Flags().Bool("confirm", true, "")
cmd.Flags().Bool("permanent", false, "")
err := deletePostsCmdF(s.client, cmd, []string{id})
s.Require().Nil(err)
s.Require().Equal("Invalid postID: invalid-id", printer.GetErrorLines()[0])
})
s.Run("successfully permanently delete one post", func() {
printer.Clean()
s.client.
EXPECT().
PermanentDeletePost(context.TODO(), postID1).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("confirm", true, "")
cmd.Flags().Bool("permanent", true, "")
err := deletePostsCmdF(s.client, cmd, []string{postID1})
s.Require().Nil(err)
s.Require().Equal(postID1+" successfully deleted", printer.GetLines()[0])
})
s.Run("successfully soft delete one post", func() {
printer.Clean()
s.client.
EXPECT().
DeletePost(context.TODO(), postID1).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("confirm", true, "")
cmd.Flags().Bool("permanent", false, "")
err := deletePostsCmdF(s.client, cmd, []string{postID1})
s.Require().Nil(err)
s.Require().Equal(postID1+" successfully deleted", printer.GetLines()[0])
})
s.Run("successfully delete multiple posts", func() {
printer.Clean()
s.client.
EXPECT().
PermanentDeletePost(context.TODO(), postID1).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
s.client.
EXPECT().
PermanentDeletePost(context.TODO(), postID2).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("confirm", true, "")
cmd.Flags().Bool("permanent", true, "")
err := deletePostsCmdF(s.client, cmd, []string{postID1, postID2})
s.Require().Nil(err)
s.Require().Equal(postID1+" successfully deleted", printer.GetLines()[0])
s.Require().Equal(postID2+" successfully deleted", printer.GetLines()[1])
})
s.Run("PermanentDeletePost api request returns an error", func() {
printer.Clean()
mockError := errors.New("an error occurred on deleting a post")
s.client.
EXPECT().
PermanentDeletePost(context.TODO(), postID1).
Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("confirm", true, "")
cmd.Flags().Bool("permanent", true, "")
err := deletePostsCmdF(s.client, cmd, []string{postID1})
s.Require().ErrorContains(err, "an error occurred on deleting a post")
s.Require().Len(printer.GetErrorLines(), 1)
s.Require().Equal("Error deleting post: "+postID1+". Error: an error occurred on deleting a post",
printer.GetErrorLines()[0])
})
s.Run("Delete multiple posts but one fails with an error", func() {
printer.Clean()
mockError := errors.New("an error occurred on deleting a post")
s.client.
EXPECT().
PermanentDeletePost(context.TODO(), postID1).
Return(&model.Response{StatusCode: http.StatusOK}, nil).
Times(1)
s.client.
EXPECT().
PermanentDeletePost(context.TODO(), postID2).
Return(&model.Response{StatusCode: http.StatusBadRequest}, mockError).
Times(1)
cmd := &cobra.Command{}
cmd.Flags().Bool("confirm", true, "")
cmd.Flags().Bool("permanent", true, "")
err := deletePostsCmdF(s.client, cmd, []string{postID1, postID2})
s.Require().ErrorContains(err, "an error occurred on deleting a post")
s.Require().Len(printer.GetLines(), 1)
s.Require().Len(printer.GetErrorLines(), 1)
s.Require().Equal(postID1+" successfully deleted", printer.GetLines()[0])
s.Require().Equal("Error deleting post: "+postID2+". Error: an error occurred on deleting a post",
printer.GetErrorLines()[0])
})
}