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