MM-12463 : Added capability to bulk export custom emojis (#9790)

This commit is contained in:
Wasim Thabraze 2018-11-19 20:13:31 +05:30 committed by George Goldberg
parent 2104c6878c
commit 246ff89391
4 changed files with 177 additions and 2 deletions

View file

@ -5,14 +5,17 @@ package app
import (
"encoding/json"
"errors"
"io"
"net/http"
"os"
"path/filepath"
"strings"
"github.com/mattermost/mattermost-server/model"
)
func (a *App) BulkExport(writer io.Writer) *model.AppError {
func (a *App) BulkExport(writer io.Writer, file string, pathToEmojiDir string, dirNameToExportEmoji string) *model.AppError {
if err := a.ExportVersion(writer); err != nil {
return err
}
@ -32,6 +35,9 @@ func (a *App) BulkExport(writer io.Writer) *model.AppError {
if err := a.ExportAllPosts(writer); err != nil {
return err
}
if err := a.ExportCustomEmoji(writer, file, pathToEmojiDir, dirNameToExportEmoji); err != nil {
return err
}
return nil
}
@ -338,3 +344,88 @@ func (a *App) BuildPostReactions(postId string) (*[]ReactionImportData, *model.A
return &reactionsOfPost, nil
}
func (a *App) ExportCustomEmoji(writer io.Writer, file string, pathToEmojiDir string, dirNameToExportEmoji string) *model.AppError {
pageNumber := 0
for {
customEmojiList, err := a.GetEmojiList(pageNumber, 100, model.EMOJI_SORT_BY_NAME)
if err != nil {
return err
}
if len(customEmojiList) == 0 {
break
}
pageNumber++
pathToDir := a.createDirForEmoji(file, dirNameToExportEmoji)
for _, emoji := range customEmojiList {
emojiImagePath := pathToEmojiDir + emoji.Id + "/image"
err := a.copyEmojiImages(emoji.Id, emojiImagePath, pathToDir)
if err != nil {
return model.NewAppError("BulkExport", "app.export.export_custom_emoji.copy_emoji_images.error", nil, "err="+err.Error(), http.StatusBadRequest)
}
filePath := dirNameToExportEmoji + "/" + emoji.Id + "/image"
emojiImportObject := ImportLineFromEmoji(emoji, filePath)
if err := a.ExportWriteLine(writer, emojiImportObject); err != nil {
return err
}
}
}
return nil
}
// Creates directory named 'exported_emoji' to copy the emoji files
// Directory and the file specified by admin share the same path
func (a *App) createDirForEmoji(file string, dirName string) string {
pathToFile, _ := filepath.Abs(file)
pathSlice := strings.Split(pathToFile, "/")
if len(pathSlice) > 0 {
pathSlice = pathSlice[:len(pathSlice)-1]
}
pathToDir := strings.Join(pathSlice, "/") + "/" + dirName
if _, err := os.Stat(pathToDir); os.IsNotExist(err) {
os.Mkdir(pathToDir, os.ModePerm)
}
return pathToDir
}
// Copies emoji files from 'data/emoji' dir to 'exported_emoji' dir
func (a *App) copyEmojiImages(emojiId string, emojiImagePath string, pathToDir string) error {
var err error
fromPath, err := os.Open(emojiImagePath)
if fromPath == nil || err != nil {
return errors.New("Error reading " + emojiImagePath + "file")
}
defer fromPath.Close()
emojiDir := pathToDir + "/" + emojiId
if _, err := os.Stat(emojiDir); os.IsNotExist(err) {
os.Mkdir(emojiDir, os.ModePerm)
}
if err != nil {
return errors.New("Error creating directory for the emoji " + err.Error())
}
toPath, err := os.OpenFile(emojiDir+"/image", os.O_RDWR|os.O_CREATE, 0666)
if err != nil {
return errors.New("Error creating the image file " + err.Error())
}
defer toPath.Close()
_, err = io.Copy(toPath, fromPath)
if err != nil {
return errors.New("Error copying emojis " + err.Error())
}
return nil
}

View file

@ -139,3 +139,13 @@ func ImportReactionFromPost(reaction *model.Reaction) *ReactionImportData {
CreateAt: &reaction.CreateAt,
}
}
func ImportLineFromEmoji(emoji *model.Emoji, filePath string) *LineImportData {
return &LineImportData{
Type: "emoji",
Emoji: &EmojiImportData{
Name: &emoji.Name,
Image: &filePath,
},
}
}

View file

@ -1,6 +1,7 @@
package app
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
@ -103,3 +104,69 @@ func TestExportUserChannels(t *testing.T) {
}
}
}
func TestDirCreationForEmoji(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
pathToDir := th.App.createDirForEmoji("test.json", "exported_emoji_test")
defer os.Remove(pathToDir)
if _, err := os.Stat(pathToDir); os.IsNotExist(err) {
t.Fatal("Directory exported_emoji_test should exist")
}
}
func TestCopyEmojiImages(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
emoji := &model.Emoji{
Id: th.BasicUser.Id,
}
// Creating a dir named `exported_emoji_test` in the root of the repo
pathToDir := "../exported_emoji_test"
os.Mkdir(pathToDir, 0777)
defer os.RemoveAll(pathToDir)
filePath := "../data/emoji/" + emoji.Id
emojiImagePath := filePath + "/image"
var _, err = os.Stat(filePath)
if os.IsNotExist(err) {
os.MkdirAll(filePath, 0777)
}
// Creating a file with the name `image` to copy it to `exported_emoji_test`
os.OpenFile(filePath+"/image", os.O_RDONLY|os.O_CREATE, 0777)
defer os.RemoveAll(filePath)
copyError := th.App.copyEmojiImages(emoji.Id, emojiImagePath, pathToDir)
if copyError != nil {
t.Fatal(copyError)
}
if _, err := os.Stat(pathToDir + "/" + emoji.Id + "/image"); os.IsNotExist(err) {
t.Fatal("File should exist ", err)
}
}
func TestExportCustomEmoji(t *testing.T) {
th := Setup().InitBasic()
defer th.TearDown()
filePath := "../demo.json"
fileWriter, _ := os.Create(filePath)
defer os.Remove(filePath)
pathToEmojiDir := "../data/emoji/"
dirNameToExportEmoji := "exported_emoji_test"
err := th.App.ExportCustomEmoji(fileWriter, filePath, pathToEmojiDir, dirNameToExportEmoji)
defer os.RemoveAll("../" + dirNameToExportEmoji)
if err != nil {
t.Fatal(err)
}
}

View file

@ -180,7 +180,14 @@ func bulkExportCmdF(command *cobra.Command, args []string) error {
}
defer fileWriter.Close()
if err := a.BulkExport(fileWriter); err != nil {
// Path to directory of custom emoji
pathToEmojiDir := "data/emoji/"
// Name of the directory to export custom emoji
dirNameToExportEmoji := "exported_emoji"
// args[0] points to the filename/filepath passed with export bulk command
if err := a.BulkExport(fileWriter, args[0], pathToEmojiDir, dirNameToExportEmoji); err != nil {
CommandPrettyPrintln(err.Error())
return err
}