github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/cmd/mattermost/commands/sampledata.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package commands
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"math/rand"
    12  	"os"
    13  	"path"
    14  	"sort"
    15  	"strings"
    16  	"time"
    17  
    18  	"github.com/icrowley/fake"
    19  	"github.com/spf13/cobra"
    20  
    21  	"github.com/mattermost/mattermost-server/v5/app"
    22  	"github.com/mattermost/mattermost-server/v5/audit"
    23  	"github.com/mattermost/mattermost-server/v5/model"
    24  	"github.com/mattermost/mattermost-server/v5/utils"
    25  )
    26  
    27  const (
    28  	DeactivatedUser = "deactivated"
    29  	GuestUser       = "guest"
    30  )
    31  
    32  var SampleDataCmd = &cobra.Command{
    33  	Use:   "sampledata",
    34  	Short: "Generate sample data",
    35  	RunE:  sampleDataCmdF,
    36  }
    37  
    38  func init() {
    39  	SampleDataCmd.Flags().Int64P("seed", "s", 1, "Seed used for generating the random data (Different seeds generate different data).")
    40  	SampleDataCmd.Flags().IntP("teams", "t", 2, "The number of sample teams.")
    41  	SampleDataCmd.Flags().Int("channels-per-team", 10, "The number of sample channels per team.")
    42  	SampleDataCmd.Flags().IntP("users", "u", 15, "The number of sample users.")
    43  	SampleDataCmd.Flags().IntP("guests", "g", 1, "The number of sample guests.")
    44  	SampleDataCmd.Flags().Int("deactivated-users", 0, "The number of deactivated users.")
    45  	SampleDataCmd.Flags().Int("team-memberships", 2, "The number of sample team memberships per user.")
    46  	SampleDataCmd.Flags().Int("channel-memberships", 5, "The number of sample channel memberships per user in a team.")
    47  	SampleDataCmd.Flags().Int("posts-per-channel", 100, "The number of sample post per channel.")
    48  	SampleDataCmd.Flags().Int("direct-channels", 30, "The number of sample direct message channels.")
    49  	SampleDataCmd.Flags().Int("posts-per-direct-channel", 15, "The number of sample posts per direct message channel.")
    50  	SampleDataCmd.Flags().Int("group-channels", 15, "The number of sample group message channels.")
    51  	SampleDataCmd.Flags().Int("posts-per-group-channel", 30, "The number of sample posts per group message channel.")
    52  	SampleDataCmd.Flags().IntP("workers", "w", 2, "How many workers to run during the import.")
    53  	SampleDataCmd.Flags().String("profile-images", "", "Optional. Path to folder with images to randomly pick as user profile image.")
    54  	SampleDataCmd.Flags().StringP("bulk", "b", "", "Optional. Path to write a JSONL bulk file instead of loading into the database.")
    55  	RootCmd.AddCommand(SampleDataCmd)
    56  }
    57  
    58  func randomPastTime(seconds int) int64 {
    59  	now := time.Now()
    60  	today := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.FixedZone("UTC", 0))
    61  	return (today.Unix() * 1000) - int64(rand.Intn(seconds*1000))
    62  }
    63  
    64  func sortedRandomDates(size int) []int64 {
    65  	dates := make([]int64, size)
    66  	for i := 0; i < size; i++ {
    67  		dates[i] = randomPastTime(50000)
    68  	}
    69  	sort.Slice(dates, func(a, b int) bool { return dates[a] < dates[b] })
    70  	return dates
    71  }
    72  
    73  func randomEmoji() string {
    74  	emojis := []string{"+1", "-1", "heart", "blush"}
    75  	return emojis[rand.Intn(len(emojis))]
    76  }
    77  
    78  func randomReaction(users []string, parentCreateAt int64) app.ReactionImportData {
    79  	user := users[rand.Intn(len(users))]
    80  	emoji := randomEmoji()
    81  	date := parentCreateAt + int64(rand.Intn(100000))
    82  	return app.ReactionImportData{
    83  		User:      &user,
    84  		EmojiName: &emoji,
    85  		CreateAt:  &date,
    86  	}
    87  }
    88  
    89  func randomReply(users []string, parentCreateAt int64) app.ReplyImportData {
    90  	user := users[rand.Intn(len(users))]
    91  	message := randomMessage(users)
    92  	date := parentCreateAt + int64(rand.Intn(100000))
    93  	return app.ReplyImportData{
    94  		User:     &user,
    95  		Message:  &message,
    96  		CreateAt: &date,
    97  	}
    98  }
    99  
   100  func randomMessage(users []string) string {
   101  	var message string
   102  	switch rand.Intn(30) {
   103  	case 0:
   104  		mention := users[rand.Intn(len(users))]
   105  		message = "@" + mention + " " + fake.Sentence()
   106  	case 1:
   107  		switch rand.Intn(2) {
   108  		case 0:
   109  			mattermostVideos := []string{"Q4MgnxbpZas", "BFo7E9-Kc_E", "LsMLR-BHsKg", "MRmGDhlMhNA", "mUOPxT7VgWc"}
   110  			message = "https://www.youtube.com/watch?v=" + mattermostVideos[rand.Intn(len(mattermostVideos))]
   111  		case 1:
   112  			mattermostTweets := []string{"943119062334353408", "949370809528832005", "948539688171819009", "939122439115681792", "938061722027425797"}
   113  			message = "https://twitter.com/mattermosthq/status/" + mattermostTweets[rand.Intn(len(mattermostTweets))]
   114  		}
   115  	case 2:
   116  		message = ""
   117  		if rand.Intn(2) == 0 {
   118  			message += fake.Sentence()
   119  		}
   120  		for i := 0; i < rand.Intn(4)+1; i++ {
   121  			message += "\n  * " + fake.Word()
   122  		}
   123  	default:
   124  		if rand.Intn(2) == 0 {
   125  			message = fake.Sentence()
   126  		} else {
   127  			message = fake.Paragraph()
   128  		}
   129  		if rand.Intn(3) == 0 {
   130  			message += "\n" + fake.Sentence()
   131  		}
   132  		if rand.Intn(3) == 0 {
   133  			message += "\n" + fake.Sentence()
   134  		}
   135  		if rand.Intn(3) == 0 {
   136  			message += "\n" + fake.Sentence()
   137  		}
   138  	}
   139  	return message
   140  }
   141  
   142  func sampleDataCmdF(command *cobra.Command, args []string) error {
   143  	a, err := InitDBCommandContextCobra(command)
   144  	if err != nil {
   145  		return err
   146  	}
   147  	defer a.Srv().Shutdown()
   148  
   149  	seed, err := command.Flags().GetInt64("seed")
   150  	if err != nil {
   151  		return errors.New("Invalid seed parameter")
   152  	}
   153  	bulk, err := command.Flags().GetString("bulk")
   154  	if err != nil {
   155  		return errors.New("Invalid bulk parameter")
   156  	}
   157  	teams, err := command.Flags().GetInt("teams")
   158  	if err != nil || teams < 0 {
   159  		return errors.New("Invalid teams parameter")
   160  	}
   161  	channelsPerTeam, err := command.Flags().GetInt("channels-per-team")
   162  	if err != nil || channelsPerTeam < 0 {
   163  		return errors.New("Invalid channels-per-team parameter")
   164  	}
   165  	users, err := command.Flags().GetInt("users")
   166  	if err != nil || users < 0 {
   167  		return errors.New("Invalid users parameter")
   168  	}
   169  	deactivatedUsers, err := command.Flags().GetInt("deactivated-users")
   170  	if err != nil || deactivatedUsers < 0 {
   171  		return errors.New("Invalid deactivated-users parameter")
   172  	}
   173  	guests, err := command.Flags().GetInt("guests")
   174  	if err != nil || guests < 0 {
   175  		return errors.New("Invalid guests parameter")
   176  	}
   177  	teamMemberships, err := command.Flags().GetInt("team-memberships")
   178  	if err != nil || teamMemberships < 0 {
   179  		return errors.New("Invalid team-memberships parameter")
   180  	}
   181  	channelMemberships, err := command.Flags().GetInt("channel-memberships")
   182  	if err != nil || channelMemberships < 0 {
   183  		return errors.New("Invalid channel-memberships parameter")
   184  	}
   185  	postsPerChannel, err := command.Flags().GetInt("posts-per-channel")
   186  	if err != nil || postsPerChannel < 0 {
   187  		return errors.New("Invalid posts-per-channel parameter")
   188  	}
   189  	directChannels, err := command.Flags().GetInt("direct-channels")
   190  	if err != nil || directChannels < 0 {
   191  		return errors.New("Invalid direct-channels parameter")
   192  	}
   193  	postsPerDirectChannel, err := command.Flags().GetInt("posts-per-direct-channel")
   194  	if err != nil || postsPerDirectChannel < 0 {
   195  		return errors.New("Invalid posts-per-direct-channel parameter")
   196  	}
   197  	groupChannels, err := command.Flags().GetInt("group-channels")
   198  	if err != nil || groupChannels < 0 {
   199  		return errors.New("Invalid group-channels parameter")
   200  	}
   201  	postsPerGroupChannel, err := command.Flags().GetInt("posts-per-group-channel")
   202  	if err != nil || postsPerGroupChannel < 0 {
   203  		return errors.New("Invalid posts-per-group-channel parameter")
   204  	}
   205  	workers, err := command.Flags().GetInt("workers")
   206  	if err != nil {
   207  		return errors.New("Invalid workers parameter")
   208  	}
   209  	profileImagesPath, err := command.Flags().GetString("profile-images")
   210  	if err != nil {
   211  		return errors.New("Invalid profile-images parameter")
   212  	}
   213  	profileImages := []string{}
   214  	if profileImagesPath != "" {
   215  		var profileImagesStat os.FileInfo
   216  		profileImagesStat, err = os.Stat(profileImagesPath)
   217  		if os.IsNotExist(err) {
   218  			return errors.New("Profile images folder doesn't exists.")
   219  		}
   220  		if !profileImagesStat.IsDir() {
   221  			return errors.New("profile-images parameters must be a folder path.")
   222  		}
   223  		var profileImagesFiles []os.FileInfo
   224  		profileImagesFiles, err = ioutil.ReadDir(profileImagesPath)
   225  		if err != nil {
   226  			return errors.New("Invalid profile-images parameter")
   227  		}
   228  		for _, profileImage := range profileImagesFiles {
   229  			profileImages = append(profileImages, path.Join(profileImagesPath, profileImage.Name()))
   230  		}
   231  		sort.Strings(profileImages)
   232  	}
   233  
   234  	if workers < 1 {
   235  		return errors.New("You must have at least one worker.")
   236  	}
   237  	if teamMemberships > teams {
   238  		return errors.New("You can't have more team memberships than teams.")
   239  	}
   240  	if channelMemberships > channelsPerTeam {
   241  		return errors.New("You can't have more channel memberships than channels per team.")
   242  	}
   243  
   244  	if users < 6 && groupChannels > 0 {
   245  		return errors.New("You can't have group channels generation with less than 6 users. Use --group-channels 0 or increase the number of users.")
   246  	}
   247  
   248  	var bulkFile *os.File
   249  	switch bulk {
   250  	case "":
   251  		bulkFile, err = ioutil.TempFile("", ".mattermost-sample-data-")
   252  		defer os.Remove(bulkFile.Name())
   253  		if err != nil {
   254  			return errors.New("Unable to open temporary file.")
   255  		}
   256  	case "-":
   257  		bulkFile = os.Stdout
   258  	default:
   259  		bulkFile, err = os.OpenFile(bulk, os.O_RDWR|os.O_CREATE, 0755)
   260  		if err != nil {
   261  			return errors.New("Unable to write into the \"" + bulk + "\" file.")
   262  		}
   263  	}
   264  
   265  	encoder := json.NewEncoder(bulkFile)
   266  	version := 1
   267  	encoder.Encode(app.LineImportData{Type: "version", Version: &version})
   268  
   269  	fake.Seed(seed)
   270  	rand.Seed(seed)
   271  
   272  	teamsAndChannels := make(map[string][]string)
   273  	for i := 0; i < teams; i++ {
   274  		teamLine := createTeam(i)
   275  		teamsAndChannels[*teamLine.Team.Name] = []string{}
   276  		encoder.Encode(teamLine)
   277  	}
   278  
   279  	teamsList := []string{}
   280  	for teamName := range teamsAndChannels {
   281  		teamsList = append(teamsList, teamName)
   282  	}
   283  	sort.Strings(teamsList)
   284  
   285  	for _, teamName := range teamsList {
   286  		for i := 0; i < channelsPerTeam; i++ {
   287  			channelLine := createChannel(i, teamName)
   288  			teamsAndChannels[teamName] = append(teamsAndChannels[teamName], *channelLine.Channel.Name)
   289  			encoder.Encode(channelLine)
   290  		}
   291  	}
   292  
   293  	allUsers := []string{}
   294  	for i := 0; i < users; i++ {
   295  		userLine := createUser(i, teamMemberships, channelMemberships, teamsAndChannels, profileImages, "")
   296  		encoder.Encode(userLine)
   297  		allUsers = append(allUsers, *userLine.User.Username)
   298  	}
   299  	for i := 0; i < guests; i++ {
   300  		userLine := createUser(i, teamMemberships, channelMemberships, teamsAndChannels, profileImages, GuestUser)
   301  		encoder.Encode(userLine)
   302  		allUsers = append(allUsers, *userLine.User.Username)
   303  	}
   304  	for i := 0; i < deactivatedUsers; i++ {
   305  		userLine := createUser(i, teamMemberships, channelMemberships, teamsAndChannels, profileImages, DeactivatedUser)
   306  		encoder.Encode(userLine)
   307  		allUsers = append(allUsers, *userLine.User.Username)
   308  	}
   309  
   310  	for team, channels := range teamsAndChannels {
   311  		for _, channel := range channels {
   312  			dates := sortedRandomDates(postsPerChannel)
   313  
   314  			for i := 0; i < postsPerChannel; i++ {
   315  				postLine := createPost(team, channel, allUsers, dates[i])
   316  				encoder.Encode(postLine)
   317  			}
   318  		}
   319  	}
   320  
   321  	for i := 0; i < directChannels; i++ {
   322  		user1 := allUsers[rand.Intn(len(allUsers))]
   323  		user2 := allUsers[rand.Intn(len(allUsers))]
   324  		channelLine := createDirectChannel([]string{user1, user2})
   325  		encoder.Encode(channelLine)
   326  	}
   327  
   328  	for i := 0; i < directChannels; i++ {
   329  		user1 := allUsers[rand.Intn(len(allUsers))]
   330  		user2 := allUsers[rand.Intn(len(allUsers))]
   331  
   332  		dates := sortedRandomDates(postsPerDirectChannel)
   333  		for j := 0; j < postsPerDirectChannel; j++ {
   334  			postLine := createDirectPost([]string{user1, user2}, dates[j])
   335  			encoder.Encode(postLine)
   336  		}
   337  	}
   338  
   339  	for i := 0; i < groupChannels; i++ {
   340  		users := []string{}
   341  		totalUsers := 3 + rand.Intn(3)
   342  		for len(users) < totalUsers {
   343  			user := allUsers[rand.Intn(len(allUsers))]
   344  			if !utils.StringInSlice(user, users) {
   345  				users = append(users, user)
   346  			}
   347  		}
   348  		channelLine := createDirectChannel(users)
   349  		encoder.Encode(channelLine)
   350  	}
   351  
   352  	for i := 0; i < groupChannels; i++ {
   353  		users := []string{}
   354  		totalUsers := 3 + rand.Intn(3)
   355  		for len(users) < totalUsers {
   356  			user := allUsers[rand.Intn(len(allUsers))]
   357  			if !utils.StringInSlice(user, users) {
   358  				users = append(users, user)
   359  			}
   360  		}
   361  
   362  		dates := sortedRandomDates(postsPerGroupChannel)
   363  		for j := 0; j < postsPerGroupChannel; j++ {
   364  			postLine := createDirectPost(users, dates[j])
   365  			encoder.Encode(postLine)
   366  		}
   367  	}
   368  
   369  	if bulk == "" {
   370  		_, err := bulkFile.Seek(0, 0)
   371  		if err != nil {
   372  			return errors.New("Unable to read correctly the temporary file.")
   373  		}
   374  
   375  		var importErr *model.AppError
   376  		importErr, lineNumber := a.BulkImport(bulkFile, false, workers)
   377  		if importErr != nil {
   378  			return fmt.Errorf("%s: %s, %s (line: %d)", importErr.Where, importErr.Message, importErr.DetailedError, lineNumber)
   379  		}
   380  		auditRec := a.MakeAuditRecord("sampleData", audit.Success)
   381  		auditRec.AddMeta("file", bulkFile.Name())
   382  		a.LogAuditRec(auditRec, nil)
   383  	} else if bulk != "-" {
   384  		err := bulkFile.Close()
   385  		if err != nil {
   386  			return errors.New("Unable to close correctly the output file")
   387  		}
   388  	}
   389  
   390  	return nil
   391  }
   392  
   393  func createUser(idx int, teamMemberships int, channelMemberships int, teamsAndChannels map[string][]string, profileImages []string, userType string) app.LineImportData {
   394  	firstName := fake.FirstName()
   395  	lastName := fake.LastName()
   396  	position := fake.JobTitle()
   397  
   398  	username := fmt.Sprintf("%s.%s", strings.ToLower(firstName), strings.ToLower(lastName))
   399  	roles := "system_user"
   400  
   401  	var password string
   402  	var email string
   403  
   404  	switch userType {
   405  	case GuestUser:
   406  		password = fmt.Sprintf("SampleGu@st-%d", idx)
   407  		email = fmt.Sprintf("guest-%d@sample.mattermost.com", idx)
   408  		roles = "system_guest"
   409  		if idx == 0 {
   410  			username = "guest"
   411  			password = "SampleGu@st1"
   412  			email = "guest@sample.mattermost.com"
   413  		}
   414  	case DeactivatedUser:
   415  		password = fmt.Sprintf("SampleDe@ctivated-%d", idx)
   416  		email = fmt.Sprintf("deactivated-%d@sample.mattermost.com", idx)
   417  	default:
   418  		password = fmt.Sprintf("SampleUs@r-%d", idx)
   419  		email = fmt.Sprintf("user-%d@sample.mattermost.com", idx)
   420  		if idx == 0 {
   421  			username = "sysadmin"
   422  			password = "Sys@dmin-sample1"
   423  			email = "sysadmin@sample.mattermost.com"
   424  		} else if idx == 1 {
   425  			username = "user-1"
   426  		}
   427  
   428  		if idx%5 == 0 {
   429  			roles = "system_admin system_user"
   430  		}
   431  	}
   432  
   433  	// The 75% of the users have custom profile image
   434  	var profileImage *string = nil
   435  	if rand.Intn(4) != 0 {
   436  		profileImageSelector := rand.Int()
   437  		if len(profileImages) > 0 {
   438  			profileImage = &profileImages[profileImageSelector%len(profileImages)]
   439  		}
   440  	}
   441  
   442  	useMilitaryTime := "false"
   443  	if idx != 0 && rand.Intn(2) == 0 {
   444  		useMilitaryTime = "true"
   445  	}
   446  
   447  	collapsePreviews := "false"
   448  	if idx != 0 && rand.Intn(2) == 0 {
   449  		collapsePreviews = "true"
   450  	}
   451  
   452  	messageDisplay := "clean"
   453  	if idx != 0 && rand.Intn(2) == 0 {
   454  		messageDisplay = "compact"
   455  	}
   456  
   457  	channelDisplayMode := "full"
   458  	if idx != 0 && rand.Intn(2) == 0 {
   459  		channelDisplayMode = "centered"
   460  	}
   461  
   462  	// Some users has nickname
   463  	nickname := ""
   464  	if rand.Intn(5) == 0 {
   465  		nickname = fake.Company()
   466  	}
   467  
   468  	// sysadmin, user-1 and user-2 users skip tutorial steps
   469  	// Other half of users also skip tutorial steps
   470  	tutorialStep := "999"
   471  	if idx > 2 {
   472  		switch rand.Intn(6) {
   473  		case 1:
   474  			tutorialStep = "1"
   475  		case 2:
   476  			tutorialStep = "2"
   477  		case 3:
   478  			tutorialStep = "3"
   479  		}
   480  	}
   481  
   482  	teams := []app.UserTeamImportData{}
   483  	possibleTeams := []string{}
   484  	for teamName := range teamsAndChannels {
   485  		possibleTeams = append(possibleTeams, teamName)
   486  	}
   487  	sort.Strings(possibleTeams)
   488  	for x := 0; x < teamMemberships; x++ {
   489  		if len(possibleTeams) == 0 {
   490  			break
   491  		}
   492  		position := rand.Intn(len(possibleTeams))
   493  		team := possibleTeams[position]
   494  		possibleTeams = append(possibleTeams[:position], possibleTeams[position+1:]...)
   495  		if teamChannels, err := teamsAndChannels[team]; err {
   496  			teams = append(teams, createTeamMembership(channelMemberships, teamChannels, &team, userType == GuestUser))
   497  		}
   498  	}
   499  
   500  	var deleteAt int64
   501  	if userType == DeactivatedUser {
   502  		deleteAt = model.GetMillis()
   503  	}
   504  
   505  	user := app.UserImportData{
   506  		ProfileImage:       profileImage,
   507  		Username:           &username,
   508  		Email:              &email,
   509  		Password:           &password,
   510  		Nickname:           &nickname,
   511  		FirstName:          &firstName,
   512  		LastName:           &lastName,
   513  		Position:           &position,
   514  		Roles:              &roles,
   515  		Teams:              &teams,
   516  		UseMilitaryTime:    &useMilitaryTime,
   517  		CollapsePreviews:   &collapsePreviews,
   518  		MessageDisplay:     &messageDisplay,
   519  		ChannelDisplayMode: &channelDisplayMode,
   520  		TutorialStep:       &tutorialStep,
   521  		DeleteAt:           &deleteAt,
   522  	}
   523  	return app.LineImportData{
   524  		Type: "user",
   525  		User: &user,
   526  	}
   527  }
   528  
   529  func createTeamMembership(numOfchannels int, teamChannels []string, teamName *string, guest bool) app.UserTeamImportData {
   530  	roles := "team_user"
   531  	if guest {
   532  		roles = "team_guest"
   533  	} else if rand.Intn(5) == 0 {
   534  		roles = "team_user team_admin"
   535  	}
   536  	channels := []app.UserChannelImportData{}
   537  	teamChannelsCopy := append([]string(nil), teamChannels...)
   538  	for x := 0; x < numOfchannels; x++ {
   539  		if len(teamChannelsCopy) == 0 {
   540  			break
   541  		}
   542  		position := rand.Intn(len(teamChannelsCopy))
   543  		channelName := teamChannelsCopy[position]
   544  		teamChannelsCopy = append(teamChannelsCopy[:position], teamChannelsCopy[position+1:]...)
   545  		channels = append(channels, createChannelMembership(channelName, guest))
   546  	}
   547  
   548  	return app.UserTeamImportData{
   549  		Name:     teamName,
   550  		Roles:    &roles,
   551  		Channels: &channels,
   552  	}
   553  }
   554  
   555  func createChannelMembership(channelName string, guest bool) app.UserChannelImportData {
   556  	roles := "channel_user"
   557  	if guest {
   558  		roles = "channel_guest"
   559  	} else if rand.Intn(5) == 0 {
   560  		roles = "channel_user channel_admin"
   561  	}
   562  	favorite := rand.Intn(5) == 0
   563  
   564  	return app.UserChannelImportData{
   565  		Name:     &channelName,
   566  		Roles:    &roles,
   567  		Favorite: &favorite,
   568  	}
   569  }
   570  
   571  func getSampleTeamName(idx int) string {
   572  	for {
   573  		name := fmt.Sprintf("%s-%d", fake.Word(), idx)
   574  		if !model.IsReservedTeamName(name) {
   575  			return name
   576  		}
   577  	}
   578  }
   579  
   580  func createTeam(idx int) app.LineImportData {
   581  	displayName := fake.Word()
   582  	name := getSampleTeamName(idx)
   583  	allowOpenInvite := rand.Intn(2) == 0
   584  
   585  	description := fake.Paragraph()
   586  	if len(description) > 255 {
   587  		description = description[0:255]
   588  	}
   589  
   590  	teamType := "O"
   591  	if rand.Intn(2) == 0 {
   592  		teamType = "I"
   593  	}
   594  
   595  	team := app.TeamImportData{
   596  		DisplayName:     &displayName,
   597  		Name:            &name,
   598  		AllowOpenInvite: &allowOpenInvite,
   599  		Description:     &description,
   600  		Type:            &teamType,
   601  	}
   602  	return app.LineImportData{
   603  		Type: "team",
   604  		Team: &team,
   605  	}
   606  }
   607  
   608  func createChannel(idx int, teamName string) app.LineImportData {
   609  	displayName := fake.Word()
   610  	name := fmt.Sprintf("%s-%d", fake.Word(), idx)
   611  	header := fake.Paragraph()
   612  	purpose := fake.Paragraph()
   613  
   614  	if len(purpose) > 250 {
   615  		purpose = purpose[0:250]
   616  	}
   617  
   618  	channelType := "P"
   619  	if rand.Intn(2) == 0 {
   620  		channelType = "O"
   621  	}
   622  
   623  	channel := app.ChannelImportData{
   624  		Team:        &teamName,
   625  		Name:        &name,
   626  		DisplayName: &displayName,
   627  		Type:        &channelType,
   628  		Header:      &header,
   629  		Purpose:     &purpose,
   630  	}
   631  	return app.LineImportData{
   632  		Type:    "channel",
   633  		Channel: &channel,
   634  	}
   635  }
   636  
   637  func createPost(team string, channel string, allUsers []string, createAt int64) app.LineImportData {
   638  	message := randomMessage(allUsers)
   639  	create_at := createAt
   640  	user := allUsers[rand.Intn(len(allUsers))]
   641  
   642  	// Some messages are flagged by an user
   643  	flagged_by := []string{}
   644  	if rand.Intn(10) == 0 {
   645  		flagged_by = append(flagged_by, allUsers[rand.Intn(len(allUsers))])
   646  	}
   647  
   648  	reactions := []app.ReactionImportData{}
   649  	if rand.Intn(10) == 0 {
   650  		for {
   651  			reactions = append(reactions, randomReaction(allUsers, create_at))
   652  			if rand.Intn(3) == 0 {
   653  				break
   654  			}
   655  		}
   656  	}
   657  
   658  	replies := []app.ReplyImportData{}
   659  	if rand.Intn(10) == 0 {
   660  		for {
   661  			replies = append(replies, randomReply(allUsers, create_at))
   662  			if rand.Intn(4) == 0 {
   663  				break
   664  			}
   665  		}
   666  	}
   667  
   668  	post := app.PostImportData{
   669  		Team:      &team,
   670  		Channel:   &channel,
   671  		User:      &user,
   672  		Message:   &message,
   673  		CreateAt:  &create_at,
   674  		FlaggedBy: &flagged_by,
   675  		Reactions: &reactions,
   676  		Replies:   &replies,
   677  	}
   678  	return app.LineImportData{
   679  		Type: "post",
   680  		Post: &post,
   681  	}
   682  }
   683  
   684  func createDirectChannel(members []string) app.LineImportData {
   685  	header := fake.Sentence()
   686  
   687  	channel := app.DirectChannelImportData{
   688  		Members: &members,
   689  		Header:  &header,
   690  	}
   691  	return app.LineImportData{
   692  		Type:          "direct_channel",
   693  		DirectChannel: &channel,
   694  	}
   695  }
   696  
   697  func createDirectPost(members []string, createAt int64) app.LineImportData {
   698  	message := randomMessage(members)
   699  	create_at := createAt
   700  	user := members[rand.Intn(len(members))]
   701  
   702  	// Some messages are flagged by an user
   703  	flagged_by := []string{}
   704  	if rand.Intn(10) == 0 {
   705  		flagged_by = append(flagged_by, members[rand.Intn(len(members))])
   706  	}
   707  
   708  	reactions := []app.ReactionImportData{}
   709  	if rand.Intn(10) == 0 {
   710  		for {
   711  			reactions = append(reactions, randomReaction(members, create_at))
   712  			if rand.Intn(3) == 0 {
   713  				break
   714  			}
   715  		}
   716  	}
   717  
   718  	replies := []app.ReplyImportData{}
   719  	if rand.Intn(10) == 0 {
   720  		for {
   721  			replies = append(replies, randomReply(members, create_at))
   722  			if rand.Intn(4) == 0 {
   723  				break
   724  			}
   725  		}
   726  	}
   727  
   728  	post := app.DirectPostImportData{
   729  		ChannelMembers: &members,
   730  		User:           &user,
   731  		Message:        &message,
   732  		CreateAt:       &create_at,
   733  		FlaggedBy:      &flagged_by,
   734  		Reactions:      &reactions,
   735  		Replies:        &replies,
   736  	}
   737  	return app.LineImportData{
   738  		Type:       "direct_post",
   739  		DirectPost: &post,
   740  	}
   741  }