github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/app/import_functions.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package app 5 6 import ( 7 "bytes" 8 "crypto/sha1" 9 "errors" 10 "fmt" 11 "io" 12 "net/http" 13 "os" 14 "path" 15 "strings" 16 17 "github.com/mattermost/mattermost-server/v5/mlog" 18 "github.com/mattermost/mattermost-server/v5/model" 19 "github.com/mattermost/mattermost-server/v5/store" 20 "github.com/mattermost/mattermost-server/v5/utils" 21 ) 22 23 // 24 // -- Bulk Import Functions -- 25 // These functions import data directly into the database. Security and permission checks are bypassed but validity is 26 // still enforced. 27 // 28 29 func (a *App) importScheme(data *SchemeImportData, dryRun bool) *model.AppError { 30 if err := validateSchemeImportData(data); err != nil { 31 return err 32 } 33 34 // If this is a Dry Run, do not continue any further. 35 if dryRun { 36 return nil 37 } 38 39 scheme, err := a.GetSchemeByName(*data.Name) 40 if err != nil { 41 scheme = new(model.Scheme) 42 } else if scheme.Scope != *data.Scope { 43 return model.NewAppError("BulkImport", "app.import.import_scheme.scope_change.error", map[string]interface{}{"SchemeName": scheme.Name}, "", http.StatusBadRequest) 44 } 45 46 scheme.Name = *data.Name 47 scheme.DisplayName = *data.DisplayName 48 scheme.Scope = *data.Scope 49 50 if data.Description != nil { 51 scheme.Description = *data.Description 52 } 53 54 if len(scheme.Id) == 0 { 55 scheme, err = a.CreateScheme(scheme) 56 } else { 57 scheme, err = a.UpdateScheme(scheme) 58 } 59 60 if err != nil { 61 return err 62 } 63 64 if scheme.Scope == model.SCHEME_SCOPE_TEAM { 65 data.DefaultTeamAdminRole.Name = &scheme.DefaultTeamAdminRole 66 if err := a.importRole(data.DefaultTeamAdminRole, dryRun, true); err != nil { 67 return err 68 } 69 70 data.DefaultTeamUserRole.Name = &scheme.DefaultTeamUserRole 71 if err := a.importRole(data.DefaultTeamUserRole, dryRun, true); err != nil { 72 return err 73 } 74 75 if data.DefaultTeamGuestRole == nil { 76 data.DefaultTeamGuestRole = &RoleImportData{ 77 DisplayName: model.NewString("Team Guest Role for Scheme"), 78 } 79 } 80 data.DefaultTeamGuestRole.Name = &scheme.DefaultTeamGuestRole 81 if err := a.importRole(data.DefaultTeamGuestRole, dryRun, true); err != nil { 82 return err 83 } 84 } 85 86 if scheme.Scope == model.SCHEME_SCOPE_TEAM || scheme.Scope == model.SCHEME_SCOPE_CHANNEL { 87 data.DefaultChannelAdminRole.Name = &scheme.DefaultChannelAdminRole 88 if err := a.importRole(data.DefaultChannelAdminRole, dryRun, true); err != nil { 89 return err 90 } 91 92 data.DefaultChannelUserRole.Name = &scheme.DefaultChannelUserRole 93 if err := a.importRole(data.DefaultChannelUserRole, dryRun, true); err != nil { 94 return err 95 } 96 97 if data.DefaultChannelGuestRole == nil { 98 data.DefaultChannelGuestRole = &RoleImportData{ 99 DisplayName: model.NewString("Channel Guest Role for Scheme"), 100 } 101 } 102 data.DefaultChannelGuestRole.Name = &scheme.DefaultChannelGuestRole 103 if err := a.importRole(data.DefaultChannelGuestRole, dryRun, true); err != nil { 104 return err 105 } 106 } 107 108 return nil 109 } 110 111 func (a *App) importRole(data *RoleImportData, dryRun bool, isSchemeRole bool) *model.AppError { 112 if !isSchemeRole { 113 if err := validateRoleImportData(data); err != nil { 114 return err 115 } 116 } 117 118 // If this is a Dry Run, do not continue any further. 119 if dryRun { 120 return nil 121 } 122 123 role, err := a.GetRoleByName(*data.Name) 124 if err != nil { 125 role = new(model.Role) 126 } 127 128 role.Name = *data.Name 129 130 if data.DisplayName != nil { 131 role.DisplayName = *data.DisplayName 132 } 133 134 if data.Description != nil { 135 role.Description = *data.Description 136 } 137 138 if data.Permissions != nil { 139 role.Permissions = *data.Permissions 140 } 141 142 if isSchemeRole { 143 role.SchemeManaged = true 144 } else { 145 role.SchemeManaged = false 146 } 147 148 if len(role.Id) == 0 { 149 _, err = a.CreateRole(role) 150 } else { 151 _, err = a.UpdateRole(role) 152 } 153 154 return err 155 } 156 157 func (a *App) importTeam(data *TeamImportData, dryRun bool) *model.AppError { 158 if err := validateTeamImportData(data); err != nil { 159 return err 160 } 161 162 // If this is a Dry Run, do not continue any further. 163 if dryRun { 164 return nil 165 } 166 167 var team *model.Team 168 team, err := a.Srv().Store.Team().GetByName(*data.Name) 169 170 if err != nil { 171 team = &model.Team{} 172 } 173 174 team.Name = *data.Name 175 team.DisplayName = *data.DisplayName 176 team.Type = *data.Type 177 178 if data.Description != nil { 179 team.Description = *data.Description 180 } 181 182 if data.AllowOpenInvite != nil { 183 team.AllowOpenInvite = *data.AllowOpenInvite 184 } 185 186 if data.Scheme != nil { 187 scheme, err := a.GetSchemeByName(*data.Scheme) 188 if err != nil { 189 return err 190 } 191 192 if scheme.DeleteAt != 0 { 193 return model.NewAppError("BulkImport", "app.import.import_team.scheme_deleted.error", nil, "", http.StatusBadRequest) 194 } 195 196 if scheme.Scope != model.SCHEME_SCOPE_TEAM { 197 return model.NewAppError("BulkImport", "app.import.import_team.scheme_wrong_scope.error", nil, "", http.StatusBadRequest) 198 } 199 200 team.SchemeId = &scheme.Id 201 } 202 203 if team.Id == "" { 204 if _, err := a.CreateTeam(team); err != nil { 205 return err 206 } 207 } else { 208 if _, err := a.updateTeamUnsanitized(team); err != nil { 209 return err 210 } 211 } 212 213 return nil 214 } 215 216 func (a *App) importChannel(data *ChannelImportData, dryRun bool) *model.AppError { 217 if err := validateChannelImportData(data); err != nil { 218 return err 219 } 220 221 // If this is a Dry Run, do not continue any further. 222 if dryRun { 223 return nil 224 } 225 226 team, err := a.Srv().Store.Team().GetByName(*data.Team) 227 if err != nil { 228 return model.NewAppError("BulkImport", "app.import.import_channel.team_not_found.error", map[string]interface{}{"TeamName": *data.Team}, err.Error(), http.StatusBadRequest) 229 } 230 231 var channel *model.Channel 232 if result, err := a.Srv().Store.Channel().GetByNameIncludeDeleted(team.Id, *data.Name, true); err == nil { 233 channel = result 234 } else { 235 channel = &model.Channel{} 236 } 237 238 channel.TeamId = team.Id 239 channel.Name = *data.Name 240 channel.DisplayName = *data.DisplayName 241 channel.Type = *data.Type 242 243 if data.Header != nil { 244 channel.Header = *data.Header 245 } 246 247 if data.Purpose != nil { 248 channel.Purpose = *data.Purpose 249 } 250 251 if data.Scheme != nil { 252 scheme, err := a.GetSchemeByName(*data.Scheme) 253 if err != nil { 254 return err 255 } 256 257 if scheme.DeleteAt != 0 { 258 return model.NewAppError("BulkImport", "app.import.import_channel.scheme_deleted.error", nil, "", http.StatusBadRequest) 259 } 260 261 if scheme.Scope != model.SCHEME_SCOPE_CHANNEL { 262 return model.NewAppError("BulkImport", "app.import.import_channel.scheme_wrong_scope.error", nil, "", http.StatusBadRequest) 263 } 264 265 channel.SchemeId = &scheme.Id 266 } 267 268 if channel.Id == "" { 269 if _, err := a.CreateChannel(channel, false); err != nil { 270 return err 271 } 272 } else { 273 if _, err := a.UpdateChannel(channel); err != nil { 274 return err 275 } 276 } 277 278 return nil 279 } 280 281 func (a *App) importUser(data *UserImportData, dryRun bool) *model.AppError { 282 if err := validateUserImportData(data); err != nil { 283 return err 284 } 285 286 // If this is a Dry Run, do not continue any further. 287 if dryRun { 288 return nil 289 } 290 291 // We want to avoid database writes if nothing has changed. 292 hasUserChanged := false 293 hasNotifyPropsChanged := false 294 hasUserRolesChanged := false 295 hasUserAuthDataChanged := false 296 hasUserEmailVerifiedChanged := false 297 298 var user *model.User 299 var err *model.AppError 300 user, err = a.Srv().Store.User().GetByUsername(*data.Username) 301 if err != nil { 302 user = &model.User{} 303 user.MakeNonNil() 304 user.SetDefaultNotifications() 305 hasUserChanged = true 306 } 307 308 user.Username = *data.Username 309 310 if user.Email != *data.Email { 311 hasUserChanged = true 312 hasUserEmailVerifiedChanged = true // Changing the email resets email verified to false by default. 313 user.Email = *data.Email 314 user.Email = strings.ToLower(user.Email) 315 } 316 317 var password string 318 var authService string 319 var authData *string 320 321 if data.AuthService != nil { 322 if user.AuthService != *data.AuthService { 323 hasUserAuthDataChanged = true 324 } 325 authService = *data.AuthService 326 } 327 328 // AuthData and Password are mutually exclusive. 329 if data.AuthData != nil { 330 if user.AuthData == nil || *user.AuthData != *data.AuthData { 331 hasUserAuthDataChanged = true 332 } 333 authData = data.AuthData 334 password = "" 335 } else if data.Password != nil { 336 password = *data.Password 337 authData = nil 338 } else { 339 // If no AuthData or Password is specified, we must generate a password. 340 password = model.GeneratePassword(*a.Config().PasswordSettings.MinimumLength) 341 authData = nil 342 } 343 344 user.Password = password 345 user.AuthService = authService 346 user.AuthData = authData 347 348 // Automatically assume all emails are verified. 349 emailVerified := true 350 if user.EmailVerified != emailVerified { 351 user.EmailVerified = emailVerified 352 hasUserEmailVerifiedChanged = true 353 } 354 355 if data.Nickname != nil { 356 if user.Nickname != *data.Nickname { 357 user.Nickname = *data.Nickname 358 hasUserChanged = true 359 } 360 } 361 362 if data.FirstName != nil { 363 if user.FirstName != *data.FirstName { 364 user.FirstName = *data.FirstName 365 hasUserChanged = true 366 } 367 } 368 369 if data.LastName != nil { 370 if user.LastName != *data.LastName { 371 user.LastName = *data.LastName 372 hasUserChanged = true 373 } 374 } 375 376 if data.Position != nil { 377 if user.Position != *data.Position { 378 user.Position = *data.Position 379 hasUserChanged = true 380 } 381 } 382 383 if data.Locale != nil { 384 if user.Locale != *data.Locale { 385 user.Locale = *data.Locale 386 hasUserChanged = true 387 } 388 } else { 389 if user.Locale != *a.Config().LocalizationSettings.DefaultClientLocale { 390 user.Locale = *a.Config().LocalizationSettings.DefaultClientLocale 391 hasUserChanged = true 392 } 393 } 394 395 if data.DeleteAt != nil { 396 if user.DeleteAt != *data.DeleteAt { 397 user.DeleteAt = *data.DeleteAt 398 hasUserChanged = true 399 } 400 } 401 402 var roles string 403 if data.Roles != nil { 404 if user.Roles != *data.Roles { 405 roles = *data.Roles 406 hasUserRolesChanged = true 407 } 408 } else if len(user.Roles) == 0 { 409 // Set SYSTEM_USER roles on newly created users by default. 410 if user.Roles != model.SYSTEM_USER_ROLE_ID { 411 roles = model.SYSTEM_USER_ROLE_ID 412 hasUserRolesChanged = true 413 } 414 } 415 user.Roles = roles 416 417 if data.NotifyProps != nil { 418 if data.NotifyProps.Desktop != nil { 419 if value, ok := user.NotifyProps[model.DESKTOP_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Desktop { 420 user.AddNotifyProp(model.DESKTOP_NOTIFY_PROP, *data.NotifyProps.Desktop) 421 hasNotifyPropsChanged = true 422 } 423 } 424 425 if data.NotifyProps.DesktopSound != nil { 426 if value, ok := user.NotifyProps[model.DESKTOP_SOUND_NOTIFY_PROP]; !ok || value != *data.NotifyProps.DesktopSound { 427 user.AddNotifyProp(model.DESKTOP_SOUND_NOTIFY_PROP, *data.NotifyProps.DesktopSound) 428 hasNotifyPropsChanged = true 429 } 430 } 431 432 if data.NotifyProps.Email != nil { 433 if value, ok := user.NotifyProps[model.EMAIL_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Email { 434 user.AddNotifyProp(model.EMAIL_NOTIFY_PROP, *data.NotifyProps.Email) 435 hasNotifyPropsChanged = true 436 } 437 } 438 439 if data.NotifyProps.Mobile != nil { 440 if value, ok := user.NotifyProps[model.PUSH_NOTIFY_PROP]; !ok || value != *data.NotifyProps.Mobile { 441 user.AddNotifyProp(model.PUSH_NOTIFY_PROP, *data.NotifyProps.Mobile) 442 hasNotifyPropsChanged = true 443 } 444 } 445 446 if data.NotifyProps.MobilePushStatus != nil { 447 if value, ok := user.NotifyProps[model.PUSH_STATUS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.MobilePushStatus { 448 user.AddNotifyProp(model.PUSH_STATUS_NOTIFY_PROP, *data.NotifyProps.MobilePushStatus) 449 hasNotifyPropsChanged = true 450 } 451 } 452 453 if data.NotifyProps.ChannelTrigger != nil { 454 if value, ok := user.NotifyProps[model.CHANNEL_MENTIONS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.ChannelTrigger { 455 user.AddNotifyProp(model.CHANNEL_MENTIONS_NOTIFY_PROP, *data.NotifyProps.ChannelTrigger) 456 hasNotifyPropsChanged = true 457 } 458 } 459 460 if data.NotifyProps.CommentsTrigger != nil { 461 if value, ok := user.NotifyProps[model.COMMENTS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.CommentsTrigger { 462 user.AddNotifyProp(model.COMMENTS_NOTIFY_PROP, *data.NotifyProps.CommentsTrigger) 463 hasNotifyPropsChanged = true 464 } 465 } 466 467 if data.NotifyProps.MentionKeys != nil { 468 if value, ok := user.NotifyProps[model.MENTION_KEYS_NOTIFY_PROP]; !ok || value != *data.NotifyProps.MentionKeys { 469 user.AddNotifyProp(model.MENTION_KEYS_NOTIFY_PROP, *data.NotifyProps.MentionKeys) 470 hasNotifyPropsChanged = true 471 } 472 } else { 473 user.UpdateMentionKeysFromUsername("") 474 } 475 } 476 477 var savedUser *model.User 478 if user.Id == "" { 479 if savedUser, err = a.createUser(user); err != nil { 480 return err 481 } 482 } else { 483 if hasUserChanged { 484 if savedUser, err = a.UpdateUser(user, false); err != nil { 485 return err 486 } 487 } 488 if hasUserRolesChanged { 489 if savedUser, err = a.UpdateUserRoles(user.Id, roles, false); err != nil { 490 return err 491 } 492 } 493 if hasNotifyPropsChanged { 494 if savedUser, err = a.UpdateUserNotifyProps(user.Id, user.NotifyProps); err != nil { 495 return err 496 } 497 } 498 if len(password) > 0 { 499 if err = a.UpdatePassword(user, password); err != nil { 500 return err 501 } 502 } else { 503 if hasUserAuthDataChanged { 504 if _, err = a.Srv().Store.User().UpdateAuthData(user.Id, authService, authData, user.Email, false); err != nil { 505 return err 506 } 507 } 508 } 509 if emailVerified { 510 if hasUserEmailVerifiedChanged { 511 if err := a.VerifyUserEmail(user.Id, user.Email); err != nil { 512 return err 513 } 514 } 515 } 516 } 517 518 if savedUser == nil { 519 savedUser = user 520 } 521 522 if data.ProfileImage != nil { 523 file, err := os.Open(*data.ProfileImage) 524 if err != nil { 525 mlog.Error("Unable to open the profile image.", mlog.Any("err", err)) 526 } 527 if err := a.SetProfileImageFromMultiPartFile(savedUser.Id, file); err != nil { 528 mlog.Error("Unable to set the profile image from a file.", mlog.Any("err", err)) 529 } 530 } 531 532 // Preferences. 533 var preferences model.Preferences 534 535 if data.Theme != nil { 536 preferences = append(preferences, model.Preference{ 537 UserId: savedUser.Id, 538 Category: model.PREFERENCE_CATEGORY_THEME, 539 Name: "", 540 Value: *data.Theme, 541 }) 542 } 543 544 if data.UseMilitaryTime != nil { 545 preferences = append(preferences, model.Preference{ 546 UserId: savedUser.Id, 547 Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, 548 Name: model.PREFERENCE_NAME_USE_MILITARY_TIME, 549 Value: *data.UseMilitaryTime, 550 }) 551 } 552 553 if data.CollapsePreviews != nil { 554 preferences = append(preferences, model.Preference{ 555 UserId: savedUser.Id, 556 Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, 557 Name: model.PREFERENCE_NAME_COLLAPSE_SETTING, 558 Value: *data.CollapsePreviews, 559 }) 560 } 561 562 if data.MessageDisplay != nil { 563 preferences = append(preferences, model.Preference{ 564 UserId: savedUser.Id, 565 Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, 566 Name: model.PREFERENCE_NAME_MESSAGE_DISPLAY, 567 Value: *data.MessageDisplay, 568 }) 569 } 570 571 if data.ChannelDisplayMode != nil { 572 preferences = append(preferences, model.Preference{ 573 UserId: savedUser.Id, 574 Category: model.PREFERENCE_CATEGORY_DISPLAY_SETTINGS, 575 Name: "channel_display_mode", 576 Value: *data.ChannelDisplayMode, 577 }) 578 } 579 580 if data.TutorialStep != nil { 581 preferences = append(preferences, model.Preference{ 582 UserId: savedUser.Id, 583 Category: model.PREFERENCE_CATEGORY_TUTORIAL_STEPS, 584 Name: savedUser.Id, 585 Value: *data.TutorialStep, 586 }) 587 } 588 589 if data.UseMarkdownPreview != nil { 590 preferences = append(preferences, model.Preference{ 591 UserId: savedUser.Id, 592 Category: model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, 593 Name: "feature_enabled_markdown_preview", 594 Value: *data.UseMarkdownPreview, 595 }) 596 } 597 598 if data.UseFormatting != nil { 599 preferences = append(preferences, model.Preference{ 600 UserId: savedUser.Id, 601 Category: model.PREFERENCE_CATEGORY_ADVANCED_SETTINGS, 602 Name: "formatting", 603 Value: *data.UseFormatting, 604 }) 605 } 606 607 if data.ShowUnreadSection != nil { 608 preferences = append(preferences, model.Preference{ 609 UserId: savedUser.Id, 610 Category: model.PREFERENCE_CATEGORY_SIDEBAR_SETTINGS, 611 Name: "show_unread_section", 612 Value: *data.ShowUnreadSection, 613 }) 614 } 615 616 if data.EmailInterval != nil || savedUser.NotifyProps[model.EMAIL_NOTIFY_PROP] == "false" { 617 var intervalSeconds string 618 if value := savedUser.NotifyProps[model.EMAIL_NOTIFY_PROP]; value == "false" { 619 intervalSeconds = "0" 620 } else { 621 switch *data.EmailInterval { 622 case model.PREFERENCE_EMAIL_INTERVAL_IMMEDIATELY: 623 intervalSeconds = model.PREFERENCE_EMAIL_INTERVAL_NO_BATCHING_SECONDS 624 case model.PREFERENCE_EMAIL_INTERVAL_FIFTEEN: 625 intervalSeconds = model.PREFERENCE_EMAIL_INTERVAL_FIFTEEN_AS_SECONDS 626 case model.PREFERENCE_EMAIL_INTERVAL_HOUR: 627 intervalSeconds = model.PREFERENCE_EMAIL_INTERVAL_HOUR_AS_SECONDS 628 } 629 } 630 if intervalSeconds != "" { 631 preferences = append(preferences, model.Preference{ 632 UserId: savedUser.Id, 633 Category: model.PREFERENCE_CATEGORY_NOTIFICATIONS, 634 Name: model.PREFERENCE_NAME_EMAIL_INTERVAL, 635 Value: intervalSeconds, 636 }) 637 } 638 } 639 640 if len(preferences) > 0 { 641 if err := a.Srv().Store.Preference().Save(&preferences); err != nil { 642 return model.NewAppError("BulkImport", "app.import.import_user.save_preferences.error", nil, err.Error(), http.StatusInternalServerError) 643 } 644 } 645 646 return a.importUserTeams(savedUser, data.Teams) 647 } 648 649 func (a *App) importUserTeams(user *model.User, data *[]UserTeamImportData) *model.AppError { 650 if data == nil { 651 return nil 652 } 653 654 teamNames := []string{} 655 for _, tdata := range *data { 656 teamNames = append(teamNames, *tdata.Name) 657 } 658 allTeams, err := a.getTeamsByNames(teamNames) 659 if err != nil { 660 return err 661 } 662 663 teamThemePreferencesByID := map[string]model.Preferences{} 664 channels := map[string][]UserChannelImportData{} 665 teamsByID := map[string]*model.Team{} 666 teamMemberByTeamID := map[string]*model.TeamMember{} 667 newTeamMembers := []*model.TeamMember{} 668 oldTeamMembers := []*model.TeamMember{} 669 rolesByTeamId := map[string]string{} 670 isGuestByTeamId := map[string]bool{} 671 isUserByTeamId := map[string]bool{} 672 isAdminByTeamId := map[string]bool{} 673 existingMemberships, err := a.Srv().Store.Team().GetTeamsForUser(user.Id) 674 if err != nil { 675 return err 676 } 677 existingMembershipsByTeamId := map[string]*model.TeamMember{} 678 for _, teamMembership := range existingMemberships { 679 existingMembershipsByTeamId[teamMembership.TeamId] = teamMembership 680 } 681 for _, tdata := range *data { 682 team := allTeams[*tdata.Name] 683 684 // Team-specific theme Preferences. 685 if tdata.Theme != nil { 686 teamThemePreferencesByID[team.Id] = append(teamThemePreferencesByID[team.Id], model.Preference{ 687 UserId: user.Id, 688 Category: model.PREFERENCE_CATEGORY_THEME, 689 Name: team.Id, 690 Value: *tdata.Theme, 691 }) 692 } 693 694 isGuestByTeamId[team.Id] = false 695 isUserByTeamId[team.Id] = true 696 isAdminByTeamId[team.Id] = false 697 698 if tdata.Roles == nil { 699 isUserByTeamId[team.Id] = true 700 } else { 701 rawRoles := *tdata.Roles 702 explicitRoles := []string{} 703 for _, role := range strings.Fields(rawRoles) { 704 if role == model.TEAM_GUEST_ROLE_ID { 705 isGuestByTeamId[team.Id] = true 706 isUserByTeamId[team.Id] = false 707 } else if role == model.TEAM_USER_ROLE_ID { 708 isUserByTeamId[team.Id] = true 709 } else if role == model.TEAM_ADMIN_ROLE_ID { 710 isAdminByTeamId[team.Id] = true 711 } else { 712 explicitRoles = append(explicitRoles, role) 713 } 714 } 715 rolesByTeamId[team.Id] = strings.Join(explicitRoles, " ") 716 } 717 718 member := &model.TeamMember{ 719 TeamId: team.Id, 720 UserId: user.Id, 721 SchemeGuest: user.IsGuest(), 722 SchemeUser: !user.IsGuest(), 723 SchemeAdmin: team.Email == user.Email && !user.IsGuest(), 724 } 725 if !user.IsGuest() { 726 var userShouldBeAdmin bool 727 userShouldBeAdmin, err = a.UserIsInAdminRoleGroup(user.Id, team.Id, model.GroupSyncableTypeTeam) 728 if err != nil { 729 return err 730 } 731 member.SchemeAdmin = userShouldBeAdmin 732 } 733 734 if tdata.Channels != nil { 735 channels[team.Id] = append(channels[team.Id], *tdata.Channels...) 736 } 737 if !user.IsGuest() { 738 channels[team.Id] = append(channels[team.Id], UserChannelImportData{Name: model.NewString(model.DEFAULT_CHANNEL)}) 739 } 740 741 teamsByID[team.Id] = team 742 teamMemberByTeamID[team.Id] = member 743 if _, ok := existingMembershipsByTeamId[team.Id]; !ok { 744 newTeamMembers = append(newTeamMembers, member) 745 } else { 746 oldTeamMembers = append(oldTeamMembers, member) 747 } 748 } 749 750 oldMembers, err := a.Srv().Store.Team().UpdateMultipleMembers(oldTeamMembers) 751 if err != nil { 752 return err 753 } 754 755 newMembers := []*model.TeamMember{} 756 if len(newTeamMembers) > 0 { 757 newMembers, err = a.Srv().Store.Team().SaveMultipleMembers(newTeamMembers, *a.Config().TeamSettings.MaxUsersPerTeam) 758 if err != nil { 759 return err 760 } 761 } 762 763 for _, member := range append(newMembers, oldMembers...) { 764 if member.ExplicitRoles != rolesByTeamId[member.TeamId] { 765 if _, err = a.UpdateTeamMemberRoles(member.TeamId, user.Id, rolesByTeamId[member.TeamId]); err != nil { 766 return err 767 } 768 } 769 770 a.UpdateTeamMemberSchemeRoles(member.TeamId, user.Id, isGuestByTeamId[member.TeamId], isUserByTeamId[member.TeamId], isAdminByTeamId[member.TeamId]) 771 } 772 773 for _, team := range allTeams { 774 if len(teamThemePreferencesByID[team.Id]) > 0 { 775 pref := teamThemePreferencesByID[team.Id] 776 if err := a.Srv().Store.Preference().Save(&pref); err != nil { 777 return model.NewAppError("BulkImport", "app.import.import_user_teams.save_preferences.error", nil, err.Error(), http.StatusInternalServerError) 778 } 779 } 780 channelsToImport := channels[team.Id] 781 if err := a.importUserChannels(user, team, teamMemberByTeamID[team.Id], &channelsToImport); err != nil { 782 return err 783 } 784 } 785 786 return nil 787 } 788 789 func (a *App) importUserChannels(user *model.User, team *model.Team, teamMember *model.TeamMember, data *[]UserChannelImportData) *model.AppError { 790 if data == nil { 791 return nil 792 } 793 794 channelNames := []string{} 795 for _, tdata := range *data { 796 channelNames = append(channelNames, *tdata.Name) 797 } 798 allChannels, err := a.getChannelsByNames(channelNames, team.Id) 799 if err != nil { 800 return err 801 } 802 803 channelsByID := map[string]*model.Channel{} 804 channelMemberByChannelID := map[string]*model.ChannelMember{} 805 newChannelMembers := []*model.ChannelMember{} 806 oldChannelMembers := []*model.ChannelMember{} 807 rolesByChannelId := map[string]string{} 808 channelPreferencesByID := map[string]model.Preferences{} 809 isGuestByChannelId := map[string]bool{} 810 isUserByChannelId := map[string]bool{} 811 isAdminByChannelId := map[string]bool{} 812 existingMemberships, err := a.Srv().Store.Channel().GetMembersForUser(team.Id, user.Id) 813 if err != nil { 814 return err 815 } 816 existingMembershipsByChannelId := map[string]model.ChannelMember{} 817 for _, channelMembership := range *existingMemberships { 818 existingMembershipsByChannelId[channelMembership.ChannelId] = channelMembership 819 } 820 for _, cdata := range *data { 821 channel, ok := allChannels[*cdata.Name] 822 if !ok { 823 return model.NewAppError("BulkImport", "app.import.import_user_channels.channel_not_found.error", nil, "", http.StatusInternalServerError) 824 } 825 if _, ok = channelsByID[channel.Id]; ok && *cdata.Name == model.DEFAULT_CHANNEL { 826 // town-square membership was in the import and added by the importer (skip the added by the importer) 827 continue 828 } 829 830 isGuestByChannelId[channel.Id] = false 831 isUserByChannelId[channel.Id] = true 832 isAdminByChannelId[channel.Id] = false 833 834 if cdata.Roles == nil { 835 isUserByChannelId[channel.Id] = true 836 } else { 837 rawRoles := *cdata.Roles 838 explicitRoles := []string{} 839 for _, role := range strings.Fields(rawRoles) { 840 if role == model.CHANNEL_GUEST_ROLE_ID { 841 isGuestByChannelId[channel.Id] = true 842 isUserByChannelId[channel.Id] = false 843 } else if role == model.CHANNEL_USER_ROLE_ID { 844 isUserByChannelId[channel.Id] = true 845 } else if role == model.CHANNEL_ADMIN_ROLE_ID { 846 isAdminByChannelId[channel.Id] = true 847 } else { 848 explicitRoles = append(explicitRoles, role) 849 } 850 } 851 rolesByChannelId[channel.Id] = strings.Join(explicitRoles, " ") 852 } 853 854 if cdata.Favorite != nil && *cdata.Favorite { 855 channelPreferencesByID[channel.Id] = append(channelPreferencesByID[channel.Id], model.Preference{ 856 UserId: user.Id, 857 Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL, 858 Name: channel.Id, 859 Value: "true", 860 }) 861 } 862 863 member := &model.ChannelMember{ 864 ChannelId: channel.Id, 865 UserId: user.Id, 866 NotifyProps: model.GetDefaultChannelNotifyProps(), 867 SchemeGuest: user.IsGuest(), 868 SchemeUser: !user.IsGuest(), 869 SchemeAdmin: false, 870 } 871 if !user.IsGuest() { 872 var userShouldBeAdmin bool 873 userShouldBeAdmin, err = a.UserIsInAdminRoleGroup(user.Id, team.Id, model.GroupSyncableTypeTeam) 874 if err != nil { 875 return err 876 } 877 member.SchemeAdmin = userShouldBeAdmin 878 } 879 880 if cdata.NotifyProps != nil { 881 if cdata.NotifyProps.Desktop != nil { 882 member.NotifyProps[model.DESKTOP_NOTIFY_PROP] = *cdata.NotifyProps.Desktop 883 } 884 885 if cdata.NotifyProps.Mobile != nil { 886 member.NotifyProps[model.PUSH_NOTIFY_PROP] = *cdata.NotifyProps.Mobile 887 } 888 889 if cdata.NotifyProps.MarkUnread != nil { 890 member.NotifyProps[model.MARK_UNREAD_NOTIFY_PROP] = *cdata.NotifyProps.MarkUnread 891 } 892 } 893 894 channelsByID[channel.Id] = channel 895 channelMemberByChannelID[channel.Id] = member 896 if _, ok := existingMembershipsByChannelId[channel.Id]; !ok { 897 newChannelMembers = append(newChannelMembers, member) 898 } else { 899 oldChannelMembers = append(oldChannelMembers, member) 900 } 901 } 902 903 oldMembers, err := a.Srv().Store.Channel().UpdateMultipleMembers(oldChannelMembers) 904 if err != nil { 905 return err 906 } 907 908 newMembers := []*model.ChannelMember{} 909 if len(newChannelMembers) > 0 { 910 newMembers, err = a.Srv().Store.Channel().SaveMultipleMembers(newChannelMembers) 911 if err != nil { 912 return err 913 } 914 } 915 916 for _, member := range append(newMembers, oldMembers...) { 917 if member.ExplicitRoles != rolesByChannelId[member.ChannelId] { 918 if _, err = a.UpdateChannelMemberRoles(member.ChannelId, user.Id, rolesByChannelId[member.ChannelId]); err != nil { 919 return err 920 } 921 } 922 923 a.UpdateChannelMemberSchemeRoles(member.ChannelId, user.Id, isGuestByChannelId[member.ChannelId], isUserByChannelId[member.ChannelId], isAdminByChannelId[member.ChannelId]) 924 } 925 926 for _, channel := range allChannels { 927 if len(channelPreferencesByID[channel.Id]) > 0 { 928 pref := channelPreferencesByID[channel.Id] 929 if err := a.Srv().Store.Preference().Save(&pref); err != nil { 930 return model.NewAppError("BulkImport", "app.import.import_user_channels.save_preferences.error", nil, err.Error(), http.StatusInternalServerError) 931 } 932 } 933 } 934 935 return nil 936 } 937 938 func (a *App) importReaction(data *ReactionImportData, post *model.Post, dryRun bool) *model.AppError { 939 var err *model.AppError 940 if err = validateReactionImportData(data, post.CreateAt); err != nil { 941 return err 942 } 943 944 var user *model.User 945 user, err = a.Srv().Store.User().GetByUsername(*data.User) 946 if err != nil { 947 return model.NewAppError("BulkImport", "app.import.import_post.user_not_found.error", map[string]interface{}{"Username": data.User}, err.Error(), http.StatusBadRequest) 948 } 949 950 reaction := &model.Reaction{ 951 UserId: user.Id, 952 PostId: post.Id, 953 EmojiName: *data.EmojiName, 954 CreateAt: *data.CreateAt, 955 } 956 if _, nErr := a.Srv().Store.Reaction().Save(reaction); nErr != nil { 957 var appErr *model.AppError 958 switch { 959 case errors.As(nErr, &appErr): 960 return appErr 961 default: 962 return model.NewAppError("importReaction", "app.reaction.save.save.app_error", nil, nErr.Error(), http.StatusInternalServerError) 963 } 964 } 965 966 return nil 967 } 968 969 func (a *App) importReplies(data []ReplyImportData, post *model.Post, teamId string, dryRun bool) *model.AppError { 970 var err *model.AppError 971 usernames := []string{} 972 for _, replyData := range data { 973 replyData := replyData 974 if err = validateReplyImportData(&replyData, post.CreateAt, a.MaxPostSize()); err != nil { 975 return err 976 } 977 usernames = append(usernames, *replyData.User) 978 } 979 980 users, err := a.getUsersByUsernames(usernames) 981 if err != nil { 982 return err 983 } 984 985 postsWithData := []postAndData{} 986 postsForCreateList := []*model.Post{} 987 postsForOverwriteList := []*model.Post{} 988 989 for _, replyData := range data { 990 replyData := replyData 991 user := users[*replyData.User] 992 993 // Check if this post already exists. 994 replies, err := a.Srv().Store.Post().GetPostsCreatedAt(post.ChannelId, *replyData.CreateAt) 995 if err != nil { 996 return err 997 } 998 999 var reply *model.Post 1000 for _, r := range replies { 1001 if r.Message == *replyData.Message && r.RootId == post.Id { 1002 reply = r 1003 break 1004 } 1005 } 1006 1007 if reply == nil { 1008 reply = &model.Post{} 1009 } 1010 reply.UserId = user.Id 1011 reply.ChannelId = post.ChannelId 1012 reply.ParentId = post.Id 1013 reply.RootId = post.Id 1014 reply.Message = *replyData.Message 1015 reply.CreateAt = *replyData.CreateAt 1016 1017 fileIds, err := a.uploadAttachments(replyData.Attachments, reply, teamId, dryRun) 1018 if err != nil { 1019 return err 1020 } 1021 for _, fileID := range reply.FileIds { 1022 if _, ok := fileIds[fileID]; !ok { 1023 a.Srv().Store.FileInfo().PermanentDelete(fileID) 1024 } 1025 } 1026 reply.FileIds = make([]string, 0) 1027 for fileID := range fileIds { 1028 reply.FileIds = append(reply.FileIds, fileID) 1029 } 1030 1031 if len(reply.Id) == 0 { 1032 postsForCreateList = append(postsForCreateList, reply) 1033 } else { 1034 postsForOverwriteList = append(postsForOverwriteList, reply) 1035 } 1036 postsWithData = append(postsWithData, postAndData{post: reply, replyData: &replyData}) 1037 } 1038 1039 if len(postsForCreateList) > 0 { 1040 if _, _, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil { 1041 return err 1042 } 1043 } 1044 1045 if _, _, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil { 1046 return err 1047 } 1048 1049 for _, postWithData := range postsWithData { 1050 a.updateFileInfoWithPostId(postWithData.post) 1051 } 1052 1053 return nil 1054 } 1055 1056 func (a *App) importAttachment(data *AttachmentImportData, post *model.Post, teamId string, dryRun bool) (*model.FileInfo, *model.AppError) { 1057 file, err := os.Open(*data.Path) 1058 if file == nil || err != nil { 1059 return nil, model.NewAppError("BulkImport", "app.import.attachment.bad_file.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest) 1060 } 1061 1062 timestamp := utils.TimeFromMillis(post.CreateAt) 1063 buf := bytes.NewBuffer(nil) 1064 _, _ = io.Copy(buf, file) 1065 // Go over existing files in the post and see if there already exists a file with the same name, size and hash. If so - skip it 1066 if post.Id != "" { 1067 oldFiles, err := a.GetFileInfosForPost(post.Id, true) 1068 if err != nil { 1069 return nil, model.NewAppError("BulkImport", "app.import.attachment.file_upload.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest) 1070 } 1071 for _, oldFile := range oldFiles { 1072 if oldFile.Name != path.Base(file.Name()) || oldFile.Size != int64(buf.Len()) { 1073 continue 1074 } 1075 // check md5 1076 newHash := sha1.Sum(buf.Bytes()) 1077 oldFileData, err := a.GetFile(oldFile.Id) 1078 if err != nil { 1079 return nil, model.NewAppError("BulkImport", "app.import.attachment.file_upload.error", map[string]interface{}{"FilePath": *data.Path}, "", http.StatusBadRequest) 1080 } 1081 oldHash := sha1.Sum(oldFileData) 1082 1083 if bytes.Equal(oldHash[:], newHash[:]) { 1084 mlog.Info("Skipping uploading of file because name already exists", mlog.Any("file_name", file.Name())) 1085 return oldFile, nil 1086 } 1087 } 1088 } 1089 fileInfo, appErr := a.DoUploadFile(timestamp, teamId, post.ChannelId, post.UserId, file.Name(), buf.Bytes()) 1090 if appErr != nil { 1091 mlog.Error("Failed to upload file:", mlog.Err(appErr)) 1092 return nil, appErr 1093 } 1094 1095 a.HandleImages([]string{fileInfo.PreviewPath}, []string{fileInfo.ThumbnailPath}, [][]byte{buf.Bytes()}) 1096 1097 mlog.Info("Uploading file with name", mlog.String("file_name", file.Name())) 1098 return fileInfo, nil 1099 } 1100 1101 type postAndData struct { 1102 post *model.Post 1103 postData *PostImportData 1104 directPostData *DirectPostImportData 1105 replyData *ReplyImportData 1106 team *model.Team 1107 lineNumber int 1108 } 1109 1110 func (a *App) getUsersByUsernames(usernames []string) (map[string]*model.User, *model.AppError) { 1111 uniqueUsernames := utils.RemoveDuplicatesFromStringArray(usernames) 1112 allUsers, err := a.Srv().Store.User().GetProfilesByUsernames(uniqueUsernames, nil) 1113 if err != nil { 1114 return nil, model.NewAppError("BulkImport", "app.import.get_users_by_username.some_users_not_found.error", nil, err.Error(), http.StatusBadRequest) 1115 } 1116 1117 if len(allUsers) != len(uniqueUsernames) { 1118 return nil, model.NewAppError("BulkImport", "app.import.get_users_by_username.some_users_not_found.error", nil, "", http.StatusBadRequest) 1119 } 1120 1121 users := make(map[string]*model.User) 1122 for _, user := range allUsers { 1123 users[user.Username] = user 1124 } 1125 return users, nil 1126 } 1127 1128 func (a *App) getTeamsByNames(names []string) (map[string]*model.Team, *model.AppError) { 1129 allTeams, err := a.Srv().Store.Team().GetByNames(names) 1130 if err != nil { 1131 return nil, model.NewAppError("BulkImport", "app.import.get_teams_by_names.some_teams_not_found.error", nil, err.Error(), http.StatusBadRequest) 1132 } 1133 1134 teams := make(map[string]*model.Team) 1135 for _, team := range allTeams { 1136 teams[team.Name] = team 1137 } 1138 return teams, nil 1139 } 1140 1141 func (a *App) getChannelsByNames(names []string, teamId string) (map[string]*model.Channel, *model.AppError) { 1142 allChannels, err := a.Srv().Store.Channel().GetByNames(teamId, names, true) 1143 if err != nil { 1144 return nil, model.NewAppError("BulkImport", "app.import.get_teams_by_names.some_teams_not_found.error", nil, err.Error(), http.StatusBadRequest) 1145 } 1146 1147 channels := make(map[string]*model.Channel) 1148 for _, channel := range allChannels { 1149 channels[channel.Name] = channel 1150 } 1151 return channels, nil 1152 } 1153 1154 func (a *App) getChannelsForPosts(teams map[string]*model.Team, data []*PostImportData) (map[string]*model.Channel, *model.AppError) { 1155 channels := make(map[string]*model.Channel) 1156 for _, postData := range data { 1157 team := teams[*postData.Team] 1158 if channel, ok := channels[*postData.Channel]; !ok || channel == nil { 1159 var err error 1160 channel, err = a.Srv().Store.Channel().GetByName(team.Id, *postData.Channel, true) 1161 if err != nil { 1162 return nil, model.NewAppError("BulkImport", "app.import.import_post.channel_not_found.error", map[string]interface{}{"ChannelName": *postData.Channel}, err.Error(), http.StatusBadRequest) 1163 } 1164 channels[*postData.Channel] = channel 1165 } 1166 } 1167 return channels, nil 1168 } 1169 1170 // getPostStrID returns a string ID composed of several post fields to 1171 // uniquely identify a post before it's imported, so it has no ID yet 1172 func getPostStrID(post *model.Post) string { 1173 return fmt.Sprintf("%d%s%s", post.CreateAt, post.ChannelId, post.Message) 1174 } 1175 1176 // importMultiplePostLines will return an error and the line that 1177 // caused it whenever possible 1178 func (a *App) importMultiplePostLines(lines []LineImportWorkerData, dryRun bool) (int, *model.AppError) { 1179 if len(lines) == 0 { 1180 return 0, nil 1181 } 1182 1183 for _, line := range lines { 1184 if err := validatePostImportData(line.Post, a.MaxPostSize()); err != nil { 1185 return line.LineNumber, err 1186 } 1187 } 1188 1189 // If this is a Dry Run, do not continue any further. 1190 if dryRun { 1191 return 0, nil 1192 } 1193 1194 usernames := []string{} 1195 teamNames := make([]string, len(lines)) 1196 postsData := make([]*PostImportData, len(lines)) 1197 for i, line := range lines { 1198 usernames = append(usernames, *line.Post.User) 1199 if line.Post.FlaggedBy != nil { 1200 usernames = append(usernames, *line.Post.FlaggedBy...) 1201 } 1202 teamNames[i] = *line.Post.Team 1203 postsData[i] = line.Post 1204 } 1205 1206 users, err := a.getUsersByUsernames(usernames) 1207 if err != nil { 1208 return 0, err 1209 } 1210 1211 teams, err := a.getTeamsByNames(teamNames) 1212 if err != nil { 1213 return 0, err 1214 } 1215 1216 channels, err := a.getChannelsForPosts(teams, postsData) 1217 if err != nil { 1218 return 0, err 1219 } 1220 postsWithData := []postAndData{} 1221 postsForCreateList := []*model.Post{} 1222 postsForCreateMap := map[string]int{} 1223 postsForOverwriteList := []*model.Post{} 1224 postsForOverwriteMap := map[string]int{} 1225 1226 for _, line := range lines { 1227 team := teams[*line.Post.Team] 1228 channel := channels[*line.Post.Channel] 1229 user := users[*line.Post.User] 1230 1231 // Check if this post already exists. 1232 posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *line.Post.CreateAt) 1233 if err != nil { 1234 return line.LineNumber, err 1235 } 1236 1237 var post *model.Post 1238 for _, p := range posts { 1239 if p.Message == *line.Post.Message { 1240 post = p 1241 break 1242 } 1243 } 1244 1245 if post == nil { 1246 post = &model.Post{} 1247 } 1248 1249 post.ChannelId = channel.Id 1250 post.Message = *line.Post.Message 1251 post.UserId = user.Id 1252 post.CreateAt = *line.Post.CreateAt 1253 post.Hashtags, _ = model.ParseHashtags(post.Message) 1254 1255 if line.Post.Props != nil { 1256 post.Props = *line.Post.Props 1257 } 1258 1259 fileIds, err := a.uploadAttachments(line.Post.Attachments, post, team.Id, dryRun) 1260 if err != nil { 1261 return line.LineNumber, err 1262 } 1263 for _, fileID := range post.FileIds { 1264 if _, ok := fileIds[fileID]; !ok { 1265 a.Srv().Store.FileInfo().PermanentDelete(fileID) 1266 } 1267 } 1268 post.FileIds = make([]string, 0) 1269 for fileID := range fileIds { 1270 post.FileIds = append(post.FileIds, fileID) 1271 } 1272 1273 if len(post.Id) == 0 { 1274 postsForCreateList = append(postsForCreateList, post) 1275 postsForCreateMap[getPostStrID(post)] = line.LineNumber 1276 } else { 1277 postsForOverwriteList = append(postsForOverwriteList, post) 1278 postsForOverwriteMap[getPostStrID(post)] = line.LineNumber 1279 } 1280 postsWithData = append(postsWithData, postAndData{post: post, postData: line.Post, team: team, lineNumber: line.LineNumber}) 1281 } 1282 1283 if len(postsForCreateList) > 0 { 1284 if _, idx, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil { 1285 if idx != -1 && idx < len(postsForCreateList) { 1286 post := postsForCreateList[idx] 1287 if lineNumber, ok := postsForCreateMap[getPostStrID(post)]; ok { 1288 return lineNumber, err 1289 } 1290 } 1291 return 0, err 1292 } 1293 } 1294 1295 if _, idx, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil { 1296 if idx != -1 && idx < len(postsForOverwriteList) { 1297 post := postsForOverwriteList[idx] 1298 if lineNumber, ok := postsForOverwriteMap[getPostStrID(post)]; ok { 1299 return lineNumber, err 1300 } 1301 } 1302 return 0, err 1303 } 1304 1305 for _, postWithData := range postsWithData { 1306 postWithData := postWithData 1307 if postWithData.postData.FlaggedBy != nil { 1308 var preferences model.Preferences 1309 1310 for _, username := range *postWithData.postData.FlaggedBy { 1311 user := users[username] 1312 1313 preferences = append(preferences, model.Preference{ 1314 UserId: user.Id, 1315 Category: model.PREFERENCE_CATEGORY_FLAGGED_POST, 1316 Name: postWithData.post.Id, 1317 Value: "true", 1318 }) 1319 } 1320 1321 if len(preferences) > 0 { 1322 if err := a.Srv().Store.Preference().Save(&preferences); err != nil { 1323 return postWithData.lineNumber, model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError) 1324 } 1325 } 1326 } 1327 1328 if postWithData.postData.Reactions != nil { 1329 for _, reaction := range *postWithData.postData.Reactions { 1330 reaction := reaction 1331 if err := a.importReaction(&reaction, postWithData.post, dryRun); err != nil { 1332 return postWithData.lineNumber, err 1333 } 1334 } 1335 } 1336 1337 if postWithData.postData.Replies != nil && len(*postWithData.postData.Replies) > 0 { 1338 err := a.importReplies(*postWithData.postData.Replies, postWithData.post, postWithData.team.Id, dryRun) 1339 if err != nil { 1340 return postWithData.lineNumber, err 1341 } 1342 } 1343 a.updateFileInfoWithPostId(postWithData.post) 1344 } 1345 return 0, nil 1346 } 1347 1348 // uploadAttachments imports new attachments and returns current attachments of the post as a map 1349 func (a *App) uploadAttachments(attachments *[]AttachmentImportData, post *model.Post, teamId string, dryRun bool) (map[string]bool, *model.AppError) { 1350 if attachments == nil { 1351 return nil, nil 1352 } 1353 fileIds := make(map[string]bool) 1354 for _, attachment := range *attachments { 1355 attachment := attachment 1356 fileInfo, err := a.importAttachment(&attachment, post, teamId, dryRun) 1357 if err != nil { 1358 return nil, err 1359 } 1360 fileIds[fileInfo.Id] = true 1361 } 1362 return fileIds, nil 1363 } 1364 1365 func (a *App) updateFileInfoWithPostId(post *model.Post) { 1366 for _, fileId := range post.FileIds { 1367 if err := a.Srv().Store.FileInfo().AttachToPost(fileId, post.Id, post.UserId); err != nil { 1368 mlog.Error("Error attaching files to post.", mlog.String("post_id", post.Id), mlog.Any("post_file_ids", post.FileIds), mlog.Err(err)) 1369 } 1370 } 1371 } 1372 func (a *App) importDirectChannel(data *DirectChannelImportData, dryRun bool) *model.AppError { 1373 var err *model.AppError 1374 if err = validateDirectChannelImportData(data); err != nil { 1375 return err 1376 } 1377 1378 // If this is a Dry Run, do not continue any further. 1379 if dryRun { 1380 return nil 1381 } 1382 1383 var userIds []string 1384 userMap, err := a.getUsersByUsernames(*data.Members) 1385 if err != nil { 1386 return err 1387 } 1388 for _, user := range *data.Members { 1389 userIds = append(userIds, userMap[user].Id) 1390 } 1391 1392 var channel *model.Channel 1393 1394 if len(userIds) == 2 { 1395 ch, err := a.createDirectChannel(userIds[0], userIds[1]) 1396 if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { 1397 return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest) 1398 } 1399 channel = ch 1400 } else { 1401 ch, err := a.createGroupChannel(userIds, userIds[0]) 1402 if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { 1403 return model.NewAppError("BulkImport", "app.import.import_direct_channel.create_group_channel.error", nil, err.Error(), http.StatusBadRequest) 1404 } 1405 channel = ch 1406 } 1407 1408 var preferences model.Preferences 1409 1410 for _, userId := range userIds { 1411 preferences = append(preferences, model.Preference{ 1412 UserId: userId, 1413 Category: model.PREFERENCE_CATEGORY_DIRECT_CHANNEL_SHOW, 1414 Name: channel.Id, 1415 Value: "true", 1416 }) 1417 } 1418 1419 if data.FavoritedBy != nil { 1420 for _, favoriter := range *data.FavoritedBy { 1421 preferences = append(preferences, model.Preference{ 1422 UserId: userMap[favoriter].Id, 1423 Category: model.PREFERENCE_CATEGORY_FAVORITE_CHANNEL, 1424 Name: channel.Id, 1425 Value: "true", 1426 }) 1427 } 1428 } 1429 1430 if err := a.Srv().Store.Preference().Save(&preferences); err != nil { 1431 var appErr *model.AppError 1432 switch { 1433 case errors.As(err, &appErr): 1434 appErr.StatusCode = http.StatusBadRequest 1435 return appErr 1436 default: 1437 return model.NewAppError("importDirectChannel", "app.preference.save.updating.app_error", nil, err.Error(), http.StatusBadRequest) 1438 } 1439 } 1440 1441 if data.Header != nil { 1442 channel.Header = *data.Header 1443 if _, appErr := a.Srv().Store.Channel().Update(channel); appErr != nil { 1444 return model.NewAppError("BulkImport", "app.import.import_direct_channel.update_header_failed.error", nil, appErr.Error(), http.StatusBadRequest) 1445 } 1446 } 1447 1448 return nil 1449 } 1450 1451 // importMultipleDirectPostLines will return an error and the line 1452 // that caused it whenever possible 1453 func (a *App) importMultipleDirectPostLines(lines []LineImportWorkerData, dryRun bool) (int, *model.AppError) { 1454 if len(lines) == 0 { 1455 return 0, nil 1456 } 1457 1458 for _, line := range lines { 1459 if err := validateDirectPostImportData(line.DirectPost, a.MaxPostSize()); err != nil { 1460 return line.LineNumber, err 1461 } 1462 } 1463 1464 // If this is a Dry Run, do not continue any further. 1465 if dryRun { 1466 return 0, nil 1467 } 1468 1469 usernames := []string{} 1470 for _, line := range lines { 1471 usernames = append(usernames, *line.DirectPost.User) 1472 if line.DirectPost.FlaggedBy != nil { 1473 usernames = append(usernames, *line.DirectPost.FlaggedBy...) 1474 } 1475 usernames = append(usernames, *line.DirectPost.ChannelMembers...) 1476 } 1477 1478 users, err := a.getUsersByUsernames(usernames) 1479 if err != nil { 1480 return 0, err 1481 } 1482 1483 postsWithData := []postAndData{} 1484 postsForCreateList := []*model.Post{} 1485 postsForCreateMap := map[string]int{} 1486 postsForOverwriteList := []*model.Post{} 1487 postsForOverwriteMap := map[string]int{} 1488 1489 for _, line := range lines { 1490 var userIds []string 1491 var err *model.AppError 1492 for _, username := range *line.DirectPost.ChannelMembers { 1493 user := users[username] 1494 userIds = append(userIds, user.Id) 1495 } 1496 1497 var channel *model.Channel 1498 var ch *model.Channel 1499 if len(userIds) == 2 { 1500 ch, err = a.GetOrCreateDirectChannel(userIds[0], userIds[1]) 1501 if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { 1502 return line.LineNumber, model.NewAppError("BulkImport", "app.import.import_direct_post.create_direct_channel.error", nil, err.Error(), http.StatusBadRequest) 1503 } 1504 channel = ch 1505 } else { 1506 ch, err = a.createGroupChannel(userIds, userIds[0]) 1507 if err != nil && err.Id != store.CHANNEL_EXISTS_ERROR { 1508 return line.LineNumber, model.NewAppError("BulkImport", "app.import.import_direct_post.create_group_channel.error", nil, err.Error(), http.StatusBadRequest) 1509 } 1510 channel = ch 1511 } 1512 1513 user := users[*line.DirectPost.User] 1514 1515 // Check if this post already exists. 1516 posts, err := a.Srv().Store.Post().GetPostsCreatedAt(channel.Id, *line.DirectPost.CreateAt) 1517 if err != nil { 1518 return line.LineNumber, err 1519 } 1520 1521 var post *model.Post 1522 for _, p := range posts { 1523 if p.Message == *line.DirectPost.Message { 1524 post = p 1525 break 1526 } 1527 } 1528 1529 if post == nil { 1530 post = &model.Post{} 1531 } 1532 1533 post.ChannelId = channel.Id 1534 post.Message = *line.DirectPost.Message 1535 post.UserId = user.Id 1536 post.CreateAt = *line.DirectPost.CreateAt 1537 post.Hashtags, _ = model.ParseHashtags(post.Message) 1538 1539 if line.DirectPost.Props != nil { 1540 post.Props = *line.DirectPost.Props 1541 } 1542 1543 fileIds, err := a.uploadAttachments(line.DirectPost.Attachments, post, "noteam", dryRun) 1544 if err != nil { 1545 return line.LineNumber, err 1546 } 1547 for _, fileID := range post.FileIds { 1548 if _, ok := fileIds[fileID]; !ok { 1549 a.Srv().Store.FileInfo().PermanentDelete(fileID) 1550 } 1551 } 1552 post.FileIds = make([]string, 0) 1553 for fileID := range fileIds { 1554 post.FileIds = append(post.FileIds, fileID) 1555 } 1556 1557 if len(post.Id) == 0 { 1558 postsForCreateList = append(postsForCreateList, post) 1559 postsForCreateMap[getPostStrID(post)] = line.LineNumber 1560 } else { 1561 postsForOverwriteList = append(postsForOverwriteList, post) 1562 postsForOverwriteMap[getPostStrID(post)] = line.LineNumber 1563 } 1564 postsWithData = append(postsWithData, postAndData{post: post, directPostData: line.DirectPost, lineNumber: line.LineNumber}) 1565 } 1566 1567 if len(postsForCreateList) > 0 { 1568 if _, idx, err := a.Srv().Store.Post().SaveMultiple(postsForCreateList); err != nil { 1569 if idx != -1 && idx < len(postsForCreateList) { 1570 post := postsForCreateList[idx] 1571 if lineNumber, ok := postsForCreateMap[getPostStrID(post)]; ok { 1572 return lineNumber, err 1573 } 1574 } 1575 return 0, err 1576 } 1577 } 1578 if _, idx, err := a.Srv().Store.Post().OverwriteMultiple(postsForOverwriteList); err != nil { 1579 if idx != -1 && idx < len(postsForOverwriteList) { 1580 post := postsForOverwriteList[idx] 1581 if lineNumber, ok := postsForOverwriteMap[getPostStrID(post)]; ok { 1582 return lineNumber, err 1583 } 1584 } 1585 return 0, err 1586 } 1587 1588 for _, postWithData := range postsWithData { 1589 if postWithData.directPostData.FlaggedBy != nil { 1590 var preferences model.Preferences 1591 1592 for _, username := range *postWithData.directPostData.FlaggedBy { 1593 user := users[username] 1594 1595 preferences = append(preferences, model.Preference{ 1596 UserId: user.Id, 1597 Category: model.PREFERENCE_CATEGORY_FLAGGED_POST, 1598 Name: postWithData.post.Id, 1599 Value: "true", 1600 }) 1601 } 1602 1603 if len(preferences) > 0 { 1604 if err := a.Srv().Store.Preference().Save(&preferences); err != nil { 1605 return postWithData.lineNumber, model.NewAppError("BulkImport", "app.import.import_post.save_preferences.error", nil, err.Error(), http.StatusInternalServerError) 1606 } 1607 } 1608 } 1609 1610 if postWithData.directPostData.Reactions != nil { 1611 for _, reaction := range *postWithData.directPostData.Reactions { 1612 reaction := reaction 1613 if err := a.importReaction(&reaction, postWithData.post, dryRun); err != nil { 1614 return postWithData.lineNumber, err 1615 } 1616 } 1617 } 1618 1619 if postWithData.directPostData.Replies != nil { 1620 if err := a.importReplies(*postWithData.directPostData.Replies, postWithData.post, "noteam", dryRun); err != nil { 1621 return postWithData.lineNumber, err 1622 } 1623 } 1624 1625 a.updateFileInfoWithPostId(postWithData.post) 1626 } 1627 return 0, nil 1628 } 1629 1630 func (a *App) importEmoji(data *EmojiImportData, dryRun bool) *model.AppError { 1631 if err := validateEmojiImportData(data); err != nil { 1632 return err 1633 } 1634 1635 // If this is a Dry Run, do not continue any further. 1636 if dryRun { 1637 return nil 1638 } 1639 1640 var emoji *model.Emoji 1641 1642 emoji, err := a.Srv().Store.Emoji().GetByName(*data.Name, true) 1643 if err != nil { 1644 var nfErr *store.ErrNotFound 1645 if !errors.As(err, &nfErr) { 1646 return model.NewAppError("importEmoji", "app.emoji.get_by_name.app_error", nil, err.Error(), http.StatusInternalServerError) 1647 } 1648 } 1649 1650 alreadyExists := emoji != nil 1651 1652 if !alreadyExists { 1653 emoji = &model.Emoji{ 1654 Name: *data.Name, 1655 } 1656 emoji.PreSave() 1657 } 1658 1659 file, err := os.Open(*data.Image) 1660 if err != nil { 1661 return model.NewAppError("BulkImport", "app.import.emoji.bad_file.error", map[string]interface{}{"EmojiName": *data.Name}, "", http.StatusBadRequest) 1662 } 1663 1664 if _, err := a.WriteFile(file, getEmojiImagePath(emoji.Id)); err != nil { 1665 return err 1666 } 1667 1668 if !alreadyExists { 1669 if _, err := a.Srv().Store.Emoji().Save(emoji); err != nil { 1670 return model.NewAppError("importEmoji", "api.emoji.create.internal_error", nil, err.Error(), http.StatusBadRequest) 1671 } 1672 } 1673 1674 return nil 1675 }