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