github.com/mattermosttest/mattermost-server/v5@v5.0.0-20200917143240-9dfa12e121f9/cmd/mattermost/commands/channel.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 "fmt" 8 9 "github.com/mattermost/mattermost-server/v5/app" 10 "github.com/mattermost/mattermost-server/v5/audit" 11 "github.com/mattermost/mattermost-server/v5/model" 12 "github.com/pkg/errors" 13 "github.com/spf13/cobra" 14 ) 15 16 var ChannelCmd = &cobra.Command{ 17 Use: "channel", 18 Short: "Management of channels", 19 } 20 21 var ChannelCreateCmd = &cobra.Command{ 22 Use: "create", 23 Short: "Create a channel", 24 Long: `Create a channel.`, 25 Example: ` channel create --team myteam --name mynewchannel --display_name "My New Channel" 26 channel create --team myteam --name mynewprivatechannel --display_name "My New Private Channel" --private`, 27 RunE: createChannelCmdF, 28 } 29 30 var ChannelRenameCmd = &cobra.Command{ 31 Use: "rename", 32 Short: "Rename a channel", 33 Long: `Rename a channel.`, 34 Example: `" channel rename myteam:mychannel newchannelname --display_name "New Display Name"`, 35 Args: cobra.MinimumNArgs(2), 36 RunE: renameChannelCmdF, 37 } 38 39 var RemoveChannelUsersCmd = &cobra.Command{ 40 Use: "remove [channel] [users]", 41 Short: "Remove users from channel", 42 Long: "Remove some users from channel", 43 Example: ` channel remove myteam:mychannel user@example.com username 44 channel remove myteam:mychannel --all-users`, 45 RunE: removeChannelUsersCmdF, 46 } 47 48 var AddChannelUsersCmd = &cobra.Command{ 49 Use: "add [channel] [users]", 50 Short: "Add users to channel", 51 Long: "Add some users to channel", 52 Example: " channel add myteam:mychannel user@example.com username", 53 Args: cobra.MinimumNArgs(2), 54 RunE: addChannelUsersCmdF, 55 } 56 57 var ArchiveChannelsCmd = &cobra.Command{ 58 Use: "archive [channels]", 59 Short: "Archive channels", 60 Long: `Archive some channels. 61 Archive a channel along with all related information including posts from the database. 62 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 63 Example: " channel archive myteam:mychannel", 64 Args: cobra.MinimumNArgs(1), 65 RunE: archiveChannelsCmdF, 66 } 67 68 var DeleteChannelsCmd = &cobra.Command{ 69 Use: "delete [channels]", 70 Short: "Delete channels", 71 Long: `Permanently delete some channels. 72 Permanently deletes a channel along with all related information including posts from the database. 73 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 74 Example: " channel delete myteam:mychannel", 75 Args: cobra.MinimumNArgs(1), 76 RunE: deleteChannelsCmdF, 77 } 78 79 var ListChannelsCmd = &cobra.Command{ 80 Use: "list [teams]", 81 Short: "List all channels on specified teams.", 82 Long: `List all channels on specified teams. 83 Archived channels are appended with ' (archived)'. 84 Private channels are appended with ' (private)'.`, 85 Example: " channel list myteam", 86 Args: cobra.MinimumNArgs(1), 87 RunE: listChannelsCmdF, 88 } 89 90 var MoveChannelsCmd = &cobra.Command{ 91 Use: "move [team] [channels] --username [user]", 92 Short: "Moves channels to the specified team", 93 Long: `Moves the provided channels to the specified team. 94 Validates that all users in the channel belong to the target team. Incoming/Outgoing webhooks are moved along with the channel. 95 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 96 Example: " channel move newteam oldteam:mychannel --username myusername", 97 Args: cobra.MinimumNArgs(2), 98 RunE: moveChannelsCmdF, 99 } 100 101 var RestoreChannelsCmd = &cobra.Command{ 102 Use: "restore [channels]", 103 Short: "Restore some channels", 104 Long: `Restore a previously deleted channel 105 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 106 Example: " channel restore myteam:mychannel", 107 Args: cobra.MinimumNArgs(1), 108 RunE: restoreChannelsCmdF, 109 } 110 111 var ModifyChannelCmd = &cobra.Command{ 112 Use: "modify [channel] [flags] --username [user]", 113 Short: "Modify a channel's public/private type", 114 Long: `Change the public/private type of a channel. 115 Channel can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 116 Example: " channel modify myteam:mychannel --private --username myusername", 117 Args: cobra.MinimumNArgs(1), 118 RunE: modifyChannelCmdF, 119 } 120 121 var SearchChannelCmd = &cobra.Command{ 122 Use: "search [channel]\n mattermost search --team [team] [channel]", 123 Short: "Search a channel", 124 Long: `Search a channel by channel name. 125 Channel can be specified by team. ie. --team myTeam myChannel or by team ID.`, 126 Example: ` channel search myChannel 127 channel search --team myTeam myChannel`, 128 Args: cobra.ExactArgs(1), 129 RunE: searchChannelCmdF, 130 } 131 132 func init() { 133 ChannelCreateCmd.Flags().String("name", "", "Channel Name") 134 ChannelCreateCmd.Flags().String("display_name", "", "Channel Display Name") 135 ChannelCreateCmd.Flags().String("team", "", "Team name or ID") 136 ChannelCreateCmd.Flags().String("header", "", "Channel header") 137 ChannelCreateCmd.Flags().String("purpose", "", "Channel purpose") 138 ChannelCreateCmd.Flags().Bool("private", false, "Create a private channel.") 139 140 MoveChannelsCmd.Flags().String("username", "", "Required. Username who is moving the channel.") 141 142 DeleteChannelsCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the channels.") 143 144 ModifyChannelCmd.Flags().Bool("private", false, "Convert the channel to a private channel") 145 ModifyChannelCmd.Flags().Bool("public", false, "Convert the channel to a public channel") 146 ModifyChannelCmd.Flags().String("username", "", "Required. Username who changes the channel privacy.") 147 148 ChannelRenameCmd.Flags().String("display_name", "", "Channel Display Name") 149 SearchChannelCmd.Flags().String("team", "", "Team name or ID") 150 151 RemoveChannelUsersCmd.Flags().Bool("all-users", false, "Remove all users from the indicated channel.") 152 153 ChannelCmd.AddCommand( 154 ChannelCreateCmd, 155 RemoveChannelUsersCmd, 156 AddChannelUsersCmd, 157 ArchiveChannelsCmd, 158 DeleteChannelsCmd, 159 ListChannelsCmd, 160 MoveChannelsCmd, 161 RestoreChannelsCmd, 162 ModifyChannelCmd, 163 ChannelRenameCmd, 164 SearchChannelCmd, 165 ) 166 167 RootCmd.AddCommand(ChannelCmd) 168 } 169 170 func createChannelCmdF(command *cobra.Command, args []string) error { 171 a, err := InitDBCommandContextCobra(command) 172 if err != nil { 173 return err 174 } 175 defer a.Srv().Shutdown() 176 177 name, errn := command.Flags().GetString("name") 178 if errn != nil || name == "" { 179 return errors.New("Name is required") 180 } 181 displayname, errdn := command.Flags().GetString("display_name") 182 if errdn != nil || displayname == "" { 183 return errors.New("Display Name is required") 184 } 185 teamArg, errteam := command.Flags().GetString("team") 186 if errteam != nil || teamArg == "" { 187 return errors.New("Team is required") 188 } 189 header, _ := command.Flags().GetString("header") 190 purpose, _ := command.Flags().GetString("purpose") 191 useprivate, _ := command.Flags().GetBool("private") 192 193 channelType := model.CHANNEL_OPEN 194 if useprivate { 195 channelType = model.CHANNEL_PRIVATE 196 } 197 198 team := getTeamFromTeamArg(a, teamArg) 199 if team == nil { 200 return errors.New("Unable to find team: " + teamArg) 201 } 202 203 channel := &model.Channel{ 204 TeamId: team.Id, 205 Name: name, 206 DisplayName: displayname, 207 Header: header, 208 Purpose: purpose, 209 Type: channelType, 210 CreatorId: "", 211 } 212 213 createdChannel, errCreatedChannel := a.CreateChannel(channel, false) 214 if errCreatedChannel != nil { 215 return errCreatedChannel 216 } 217 218 auditRec := a.MakeAuditRecord("createChannel", audit.Success) 219 auditRec.AddMeta("channel", createdChannel) 220 auditRec.AddMeta("team", team) 221 a.LogAuditRec(auditRec, nil) 222 223 CommandPrettyPrintln("Id: " + createdChannel.Id) 224 CommandPrettyPrintln("Name: " + createdChannel.Name) 225 CommandPrettyPrintln("Display Name: " + createdChannel.DisplayName) 226 return nil 227 } 228 229 func removeChannelUsersCmdF(command *cobra.Command, args []string) error { 230 a, err := InitDBCommandContextCobra(command) 231 if err != nil { 232 return err 233 } 234 defer a.Srv().Shutdown() 235 236 allUsers, _ := command.Flags().GetBool("all-users") 237 238 if allUsers && len(args) != 1 { 239 return errors.New("individual users must not be specified in conjunction with the --all-users flag") 240 } 241 242 if !allUsers && len(args) < 2 { 243 return errors.New("you must specify some users to remove from the channel, or use the --all-users flag to remove them all") 244 } 245 246 channel := getChannelFromChannelArg(a, args[0]) 247 if channel == nil { 248 return errors.New("Unable to find channel '" + args[0] + "'") 249 } 250 251 if allUsers { 252 removeAllUsersFromChannel(a, channel) 253 } else { 254 users := getUsersFromUserArgs(a, args[1:]) 255 for i, user := range users { 256 removeUserFromChannel(a, channel, user, args[i+1]) 257 } 258 } 259 return nil 260 } 261 262 func removeUserFromChannel(a *app.App, channel *model.Channel, user *model.User, userArg string) { 263 if user == nil { 264 CommandPrintErrorln("Can't find user '" + userArg + "'") 265 return 266 } 267 if err := a.RemoveUserFromChannel(user.Id, "", channel); err != nil { 268 CommandPrintErrorln("Unable to remove '" + userArg + "' from " + channel.Name + ". Error: " + err.Error()) 269 return 270 } 271 272 auditRec := a.MakeAuditRecord("removeUserFromChannel", audit.Success) 273 auditRec.AddMeta("channel", channel) 274 auditRec.AddMeta("user", user) 275 a.LogAuditRec(auditRec, nil) 276 } 277 278 func removeAllUsersFromChannel(a *app.App, channel *model.Channel) { 279 if err := a.Srv().Store.Channel().PermanentDeleteMembersByChannel(channel.Id); err != nil { 280 CommandPrintErrorln("Unable to remove all users from " + channel.Name + ". Error: " + err.Error()) 281 return 282 } 283 284 auditRec := a.MakeAuditRecord("removeAllUsersFromChannel", audit.Success) 285 auditRec.AddMeta("channel", channel) 286 a.LogAuditRec(auditRec, nil) 287 } 288 289 func addChannelUsersCmdF(command *cobra.Command, args []string) error { 290 a, err := InitDBCommandContextCobra(command) 291 if err != nil { 292 return err 293 } 294 defer a.Srv().Shutdown() 295 296 channel := getChannelFromChannelArg(a, args[0]) 297 if channel == nil { 298 return errors.New("Unable to find channel '" + args[0] + "'") 299 } 300 301 users := getUsersFromUserArgs(a, args[1:]) 302 for i, user := range users { 303 addUserToChannel(a, channel, user, args[i+1]) 304 } 305 return nil 306 } 307 308 func addUserToChannel(a *app.App, channel *model.Channel, user *model.User, userArg string) { 309 if user == nil { 310 CommandPrintErrorln("Can't find user '" + userArg + "'") 311 return 312 } 313 if _, err := a.AddUserToChannel(user, channel); err != nil { 314 CommandPrintErrorln("Unable to add '" + userArg + "' from " + channel.Name + ". Error: " + err.Error()) 315 return 316 } 317 318 auditRec := a.MakeAuditRecord("addUserToChannel", audit.Success) 319 auditRec.AddMeta("channel", channel) 320 auditRec.AddMeta("user", user) 321 a.LogAuditRec(auditRec, nil) 322 } 323 324 func archiveChannelsCmdF(command *cobra.Command, args []string) error { 325 a, err := InitDBCommandContextCobra(command) 326 if err != nil { 327 return err 328 } 329 defer a.Srv().Shutdown() 330 331 channels := getChannelsFromChannelArgs(a, args) 332 for i, channel := range channels { 333 if channel == nil { 334 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 335 continue 336 } 337 if err := a.Srv().Store.Channel().Delete(channel.Id, model.GetMillis()); err != nil { 338 CommandPrintErrorln("Unable to archive channel '" + channel.Name + "' error: " + err.Error()) 339 continue 340 } 341 auditRec := a.MakeAuditRecord("archiveChannel", audit.Success) 342 auditRec.AddMeta("channel", channel) 343 a.LogAuditRec(auditRec, nil) 344 } 345 return nil 346 } 347 348 func deleteChannelsCmdF(command *cobra.Command, args []string) error { 349 a, err := InitDBCommandContextCobra(command) 350 if err != nil { 351 return err 352 } 353 defer a.Srv().Shutdown() 354 355 confirmFlag, _ := command.Flags().GetBool("confirm") 356 if !confirmFlag { 357 var confirm string 358 CommandPrettyPrintln("Are you sure you want to delete the channels specified? All data will be permanently deleted? (YES/NO): ") 359 fmt.Scanln(&confirm) 360 if confirm != "YES" { 361 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 362 } 363 } 364 365 channels := getChannelsFromChannelArgs(a, args) 366 for i, channel := range channels { 367 if channel == nil { 368 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 369 continue 370 } 371 if err := deleteChannel(a, channel); err != nil { 372 CommandPrintErrorln("Unable to delete channel '" + channel.Name + "' error: " + err.Error()) 373 } else { 374 CommandPrettyPrintln("Deleted channel '" + channel.Name + "'") 375 376 auditRec := a.MakeAuditRecord("deleteChannel", audit.Success) 377 auditRec.AddMeta("channel", channel) 378 a.LogAuditRec(auditRec, nil) 379 } 380 } 381 return nil 382 } 383 384 func deleteChannel(a *app.App, channel *model.Channel) *model.AppError { 385 return a.PermanentDeleteChannel(channel) 386 } 387 388 func moveChannelsCmdF(command *cobra.Command, args []string) error { 389 a, err := InitDBCommandContextCobra(command) 390 if err != nil { 391 return err 392 } 393 defer a.Srv().Shutdown() 394 395 team := getTeamFromTeamArg(a, args[0]) 396 if team == nil { 397 return errors.New("Unable to find destination team '" + args[0] + "'") 398 } 399 400 username, erru := command.Flags().GetString("username") 401 if erru != nil || username == "" { 402 return errors.New("Username is required.") 403 } 404 user := getUserFromUserArg(a, username) 405 406 channels := getChannelsFromChannelArgs(a, args[1:]) 407 for i, channel := range channels { 408 if channel == nil { 409 CommandPrintErrorln("Unable to find channel '" + args[i+1] + "'") 410 continue 411 } 412 originTeamID := channel.TeamId 413 if err := moveChannel(a, team, channel, user); err != nil { 414 CommandPrintErrorln("Unable to move channel '" + channel.Name + "' error: " + err.Error()) 415 } else { 416 CommandPrettyPrintln("Moved channel '" + channel.Name + "' to " + team.Name + "(" + team.Id + ") from " + originTeamID + ".") 417 } 418 } 419 return nil 420 } 421 422 func moveChannel(a *app.App, team *model.Team, channel *model.Channel, user *model.User) *model.AppError { 423 oldTeamId := channel.TeamId 424 425 if err := a.RemoveAllDeactivatedMembersFromChannel(channel); err != nil { 426 return err 427 } 428 429 if err := a.MoveChannel(team, channel, user); err != nil { 430 return err 431 } 432 433 auditRec := a.MakeAuditRecord("moveChannel", audit.Success) 434 auditRec.AddMeta("channel", channel) 435 auditRec.AddMeta("team", team) 436 a.LogAuditRec(auditRec, nil) 437 438 if incomingWebhooks, err := a.GetIncomingWebhooksForTeamPage(oldTeamId, 0, 10000000); err != nil { 439 return err 440 } else { 441 for _, webhook := range incomingWebhooks { 442 if webhook.ChannelId == channel.Id { 443 webhook.TeamId = team.Id 444 if _, err := a.Srv().Store.Webhook().UpdateIncoming(webhook); err != nil { 445 CommandPrintErrorln("Failed to move incoming webhook '" + webhook.Id + "' to new team.") 446 } 447 } 448 } 449 } 450 451 if outgoingWebhooks, err := a.GetOutgoingWebhooksForTeamPage(oldTeamId, 0, 10000000); err != nil { 452 return err 453 } else { 454 for _, webhook := range outgoingWebhooks { 455 if webhook.ChannelId == channel.Id { 456 webhook.TeamId = team.Id 457 if _, err := a.Srv().Store.Webhook().UpdateOutgoing(webhook); err != nil { 458 CommandPrintErrorln("Failed to move outgoing webhook '" + webhook.Id + "' to new team.") 459 } 460 } 461 } 462 } 463 464 return nil 465 } 466 467 func listChannelsCmdF(command *cobra.Command, args []string) error { 468 a, err := InitDBCommandContextCobra(command) 469 if err != nil { 470 return err 471 } 472 defer a.Srv().Shutdown() 473 474 teams := getTeamsFromTeamArgs(a, args) 475 for i, team := range teams { 476 if team == nil { 477 CommandPrintErrorln("Unable to find team '" + args[i] + "'") 478 continue 479 } 480 if channels, chanErr := a.Srv().Store.Channel().GetAll(team.Id); chanErr != nil { 481 CommandPrintErrorln("Unable to list channels for '" + args[i] + "'") 482 } else { 483 for _, channel := range channels { 484 output := channel.Name 485 if channel.DeleteAt > 0 { 486 output += " (archived)" 487 } 488 if channel.Type == model.CHANNEL_PRIVATE { 489 output += " (private)" 490 } 491 CommandPrettyPrintln(output) 492 } 493 } 494 } 495 496 return nil 497 } 498 499 func restoreChannelsCmdF(command *cobra.Command, args []string) error { 500 a, err := InitDBCommandContextCobra(command) 501 if err != nil { 502 return err 503 } 504 defer a.Srv().Shutdown() 505 506 channels := getChannelsFromChannelArgs(a, args) 507 for i, channel := range channels { 508 if channel == nil { 509 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 510 continue 511 } 512 if err := a.Srv().Store.Channel().SetDeleteAt(channel.Id, 0, model.GetMillis()); err != nil { 513 CommandPrintErrorln("Unable to restore channel '" + args[i] + "'") 514 continue 515 } 516 auditRec := a.MakeAuditRecord("restoreChannel", audit.Success) 517 auditRec.AddMeta("channel", channel) 518 a.LogAuditRec(auditRec, nil) 519 } 520 521 suffix := "" 522 if len(channels) > 1 { 523 suffix = "s" 524 } 525 CommandPrintln("Successfully restored channel" + suffix) 526 return nil 527 } 528 529 func modifyChannelCmdF(command *cobra.Command, args []string) error { 530 a, err := InitDBCommandContextCobra(command) 531 if err != nil { 532 return err 533 } 534 defer a.Srv().Shutdown() 535 536 username, erru := command.Flags().GetString("username") 537 if erru != nil || username == "" { 538 return errors.New("Username is required.") 539 } 540 541 public, _ := command.Flags().GetBool("public") 542 private, _ := command.Flags().GetBool("private") 543 544 if public == private { 545 return errors.New("You must specify only one of --public or --private") 546 } 547 548 channel := getChannelFromChannelArg(a, args[0]) 549 if channel == nil { 550 return errors.New("Unable to find channel '" + args[0] + "'") 551 } 552 553 if !(channel.Type == model.CHANNEL_OPEN || channel.Type == model.CHANNEL_PRIVATE) { 554 return errors.New("You can only change the type of public/private channels.") 555 } 556 557 channel.Type = model.CHANNEL_OPEN 558 if private { 559 channel.Type = model.CHANNEL_PRIVATE 560 } 561 562 user := getUserFromUserArg(a, username) 563 if user == nil { 564 return fmt.Errorf("Unable to find user: '%v'", username) 565 } 566 567 updatedChannel, errUpdate := a.UpdateChannelPrivacy(channel, user) 568 if errUpdate != nil { 569 return errors.Wrapf(err, "Failed to update channel ('%s') privacy", args[0]) 570 } 571 572 auditRec := a.MakeAuditRecord("modifyChannel", audit.Success) 573 auditRec.AddMeta("channel", channel) 574 auditRec.AddMeta("user", user) 575 auditRec.AddMeta("update", updatedChannel) 576 a.LogAuditRec(auditRec, nil) 577 578 return nil 579 } 580 581 func renameChannelCmdF(command *cobra.Command, args []string) error { 582 a, err := InitDBCommandContextCobra(command) 583 var newDisplayName, newChannelName string 584 if err != nil { 585 return err 586 } 587 defer a.Srv().Shutdown() 588 589 channel := getChannelFromChannelArg(a, args[0]) 590 if channel == nil { 591 return errors.New("Unable to find channel '" + args[0] + "'") 592 } 593 594 newChannelName = args[1] 595 newDisplayName, errdn := command.Flags().GetString("display_name") 596 if errdn != nil { 597 return errdn 598 } 599 600 updatedChannel, errch := a.RenameChannel(channel, newChannelName, newDisplayName) 601 if errch != nil { 602 return errors.Wrapf(errch, "Error in updating channel from %s to %s", channel.Name, newChannelName) 603 } 604 605 auditRec := a.MakeAuditRecord("renameChannel", audit.Success) 606 auditRec.AddMeta("channel", channel) 607 auditRec.AddMeta("update", updatedChannel) 608 a.LogAuditRec(auditRec, nil) 609 610 return nil 611 } 612 613 func searchChannelCmdF(command *cobra.Command, args []string) error { 614 615 a, err := InitDBCommandContextCobra(command) 616 if err != nil { 617 return errors.Wrap(err, "failed to InitDBCommandContextCobra") 618 } 619 defer a.Srv().Shutdown() 620 621 var channel *model.Channel 622 623 if teamArg, _ := command.Flags().GetString("team"); teamArg != "" { 624 team := getTeamFromTeamArg(a, teamArg) 625 if team == nil { 626 CommandPrettyPrintln(fmt.Sprintf("Team %s is not found", teamArg)) 627 return nil 628 } 629 630 var aErr *model.AppError 631 channel, aErr = a.GetChannelByName(args[0], team.Id, true) 632 if aErr != nil || channel == nil { 633 CommandPrettyPrintln(fmt.Sprintf("Channel %s is not found in team %s", args[0], teamArg)) 634 return nil 635 } 636 } else { 637 teams, aErr := a.GetAllTeams() 638 if aErr != nil { 639 return errors.Wrap(err, "failed to GetAllTeams") 640 } 641 642 for _, team := range teams { 643 channel, _ = a.GetChannelByName(args[0], team.Id, true) 644 if channel != nil && channel.Name == args[0] { 645 break 646 } 647 } 648 649 if channel == nil { 650 CommandPrettyPrintln(fmt.Sprintf("Channel %s is not found in any team", args[0])) 651 return nil 652 } 653 } 654 655 output := fmt.Sprintf(`Channel Name: %s, Display Name: %s, Channel ID: %s`, channel.Name, channel.DisplayName, channel.Id) 656 if channel.DeleteAt > 0 { 657 output += " (archived)" 658 } 659 if channel.Type == model.CHANNEL_PRIVATE { 660 output += " (private)" 661 } 662 CommandPrettyPrintln(output) 663 664 return nil 665 }