github.com/wgh-/mattermost-server@v4.8.0-rc2+incompatible/cmd/platform/channel.go (about) 1 // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. 2 // See License.txt for license information. 3 package main 4 5 import ( 6 "errors" 7 "fmt" 8 9 "github.com/mattermost/mattermost-server/app" 10 "github.com/mattermost/mattermost-server/model" 11 "github.com/spf13/cobra" 12 ) 13 14 var channelCmd = &cobra.Command{ 15 Use: "channel", 16 Short: "Management of channels", 17 } 18 19 var channelCreateCmd = &cobra.Command{ 20 Use: "create", 21 Short: "Create a channel", 22 Long: `Create a channel.`, 23 Example: ` channel create --team myteam --name mynewchannel --display_name "My New Channel" 24 channel create --team myteam --name mynewprivatechannel --display_name "My New Private Channel" --private`, 25 RunE: createChannelCmdF, 26 } 27 28 var removeChannelUsersCmd = &cobra.Command{ 29 Use: "remove [channel] [users]", 30 Short: "Remove users from channel", 31 Long: "Remove some users from channel", 32 Example: " channel remove mychannel user@example.com username", 33 RunE: removeChannelUsersCmdF, 34 } 35 36 var addChannelUsersCmd = &cobra.Command{ 37 Use: "add [channel] [users]", 38 Short: "Add users to channel", 39 Long: "Add some users to channel", 40 Example: " channel add mychannel user@example.com username", 41 RunE: addChannelUsersCmdF, 42 } 43 44 var archiveChannelsCmd = &cobra.Command{ 45 Use: "archive [channels]", 46 Short: "Archive channels", 47 Long: `Archive some channels. 48 Archive a channel along with all related information including posts from the database. 49 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 50 Example: " channel archive myteam:mychannel", 51 RunE: archiveChannelsCmdF, 52 } 53 54 var deleteChannelsCmd = &cobra.Command{ 55 Use: "delete [channels]", 56 Short: "Delete channels", 57 Long: `Permanently delete some channels. 58 Permanently deletes a channel along with all related information including posts from the database. 59 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 60 Example: " channel delete myteam:mychannel", 61 RunE: deleteChannelsCmdF, 62 } 63 64 var listChannelsCmd = &cobra.Command{ 65 Use: "list [teams]", 66 Short: "List all channels on specified teams.", 67 Long: `List all channels on specified teams. 68 Archived channels are appended with ' (archived)'.`, 69 Example: " channel list myteam", 70 RunE: listChannelsCmdF, 71 } 72 73 var moveChannelsCmd = &cobra.Command{ 74 Use: "move [team] [channels]", 75 Short: "Moves channels to the specified team", 76 Long: `Moves the provided channels to the specified team. 77 Validates that all users in the channel belong to the target team. Incoming/Outgoing webhooks are moved along with the channel. 78 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 79 Example: " channel move newteam oldteam:mychannel", 80 RunE: moveChannelsCmdF, 81 } 82 83 var restoreChannelsCmd = &cobra.Command{ 84 Use: "restore [channels]", 85 Short: "Restore some channels", 86 Long: `Restore a previously deleted channel 87 Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 88 Example: " channel restore myteam:mychannel", 89 RunE: restoreChannelsCmdF, 90 } 91 92 var modifyChannelCmd = &cobra.Command{ 93 Use: "modify [channel]", 94 Short: "Modify a channel's public/private type", 95 Long: `Change the public/private type of a channel. 96 Channel can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`, 97 Example: " channel modify myteam:mychannel --private", 98 RunE: modifyChannelCmdF, 99 } 100 101 func init() { 102 channelCreateCmd.Flags().String("name", "", "Channel Name") 103 channelCreateCmd.Flags().String("display_name", "", "Channel Display Name") 104 channelCreateCmd.Flags().String("team", "", "Team name or ID") 105 channelCreateCmd.Flags().String("header", "", "Channel header") 106 channelCreateCmd.Flags().String("purpose", "", "Channel purpose") 107 channelCreateCmd.Flags().Bool("private", false, "Create a private channel.") 108 109 moveChannelsCmd.Flags().String("username", "", "Required. Username who is moving the channel.") 110 111 deleteChannelsCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the channels.") 112 113 modifyChannelCmd.Flags().Bool("private", false, "Convert the channel to a private channel") 114 modifyChannelCmd.Flags().Bool("public", false, "Convert the channel to a public channel") 115 modifyChannelCmd.Flags().String("username", "", "Required. Username who changes the channel privacy.") 116 117 channelCmd.AddCommand( 118 channelCreateCmd, 119 removeChannelUsersCmd, 120 addChannelUsersCmd, 121 archiveChannelsCmd, 122 deleteChannelsCmd, 123 listChannelsCmd, 124 moveChannelsCmd, 125 restoreChannelsCmd, 126 modifyChannelCmd, 127 ) 128 } 129 130 func createChannelCmdF(cmd *cobra.Command, args []string) error { 131 a, err := initDBCommandContextCobra(cmd) 132 if err != nil { 133 return err 134 } 135 136 name, errn := cmd.Flags().GetString("name") 137 if errn != nil || name == "" { 138 return errors.New("Name is required") 139 } 140 displayname, errdn := cmd.Flags().GetString("display_name") 141 if errdn != nil || displayname == "" { 142 return errors.New("Display Name is required") 143 } 144 teamArg, errteam := cmd.Flags().GetString("team") 145 if errteam != nil || teamArg == "" { 146 return errors.New("Team is required") 147 } 148 header, _ := cmd.Flags().GetString("header") 149 purpose, _ := cmd.Flags().GetString("purpose") 150 useprivate, _ := cmd.Flags().GetBool("private") 151 152 channelType := model.CHANNEL_OPEN 153 if useprivate { 154 channelType = model.CHANNEL_PRIVATE 155 } 156 157 team := getTeamFromTeamArg(a, teamArg) 158 if team == nil { 159 return errors.New("Unable to find team: " + teamArg) 160 } 161 162 channel := &model.Channel{ 163 TeamId: team.Id, 164 Name: name, 165 DisplayName: displayname, 166 Header: header, 167 Purpose: purpose, 168 Type: channelType, 169 CreatorId: "", 170 } 171 172 if _, err := a.CreateChannel(channel, false); err != nil { 173 return err 174 } 175 176 return nil 177 } 178 179 func removeChannelUsersCmdF(cmd *cobra.Command, args []string) error { 180 a, err := initDBCommandContextCobra(cmd) 181 if err != nil { 182 return err 183 } 184 185 if len(args) < 2 { 186 return errors.New("Not enough arguments.") 187 } 188 189 channel := getChannelFromChannelArg(a, args[0]) 190 if channel == nil { 191 return errors.New("Unable to find channel '" + args[0] + "'") 192 } 193 194 users := getUsersFromUserArgs(a, args[1:]) 195 for i, user := range users { 196 removeUserFromChannel(a, channel, user, args[i+1]) 197 } 198 199 return nil 200 } 201 202 func removeUserFromChannel(a *app.App, channel *model.Channel, user *model.User, userArg string) { 203 if user == nil { 204 CommandPrintErrorln("Can't find user '" + userArg + "'") 205 return 206 } 207 if err := a.RemoveUserFromChannel(user.Id, "", channel); err != nil { 208 CommandPrintErrorln("Unable to remove '" + userArg + "' from " + channel.Name + ". Error: " + err.Error()) 209 } 210 } 211 212 func addChannelUsersCmdF(cmd *cobra.Command, args []string) error { 213 a, err := initDBCommandContextCobra(cmd) 214 if err != nil { 215 return err 216 } 217 218 if len(args) < 2 { 219 return errors.New("Not enough arguments.") 220 } 221 222 channel := getChannelFromChannelArg(a, args[0]) 223 if channel == nil { 224 return errors.New("Unable to find channel '" + args[0] + "'") 225 } 226 227 users := getUsersFromUserArgs(a, args[1:]) 228 for i, user := range users { 229 addUserToChannel(a, channel, user, args[i+1]) 230 } 231 232 return nil 233 } 234 235 func addUserToChannel(a *app.App, channel *model.Channel, user *model.User, userArg string) { 236 if user == nil { 237 CommandPrintErrorln("Can't find user '" + userArg + "'") 238 return 239 } 240 if _, err := a.AddUserToChannel(user, channel); err != nil { 241 CommandPrintErrorln("Unable to add '" + userArg + "' from " + channel.Name + ". Error: " + err.Error()) 242 } 243 } 244 245 func archiveChannelsCmdF(cmd *cobra.Command, args []string) error { 246 a, err := initDBCommandContextCobra(cmd) 247 if err != nil { 248 return err 249 } 250 251 if len(args) < 1 { 252 return errors.New("Enter at least one channel to archive.") 253 } 254 255 channels := getChannelsFromChannelArgs(a, args) 256 for i, channel := range channels { 257 if channel == nil { 258 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 259 continue 260 } 261 if result := <-a.Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); result.Err != nil { 262 CommandPrintErrorln("Unable to archive channel '" + channel.Name + "' error: " + result.Err.Error()) 263 } 264 } 265 266 return nil 267 } 268 269 func deleteChannelsCmdF(cmd *cobra.Command, args []string) error { 270 a, err := initDBCommandContextCobra(cmd) 271 if err != nil { 272 return err 273 } 274 275 if len(args) < 1 { 276 return errors.New("Enter at least one channel to delete.") 277 } 278 279 confirmFlag, _ := cmd.Flags().GetBool("confirm") 280 if !confirmFlag { 281 var confirm string 282 CommandPrettyPrintln("Are you sure you want to delete the channels specified? All data will be permanently deleted? (YES/NO): ") 283 fmt.Scanln(&confirm) 284 if confirm != "YES" { 285 return errors.New("ABORTED: You did not answer YES exactly, in all capitals.") 286 } 287 } 288 289 channels := getChannelsFromChannelArgs(a, args) 290 for i, channel := range channels { 291 if channel == nil { 292 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 293 continue 294 } 295 if err := deleteChannel(a, channel); err != nil { 296 CommandPrintErrorln("Unable to delete channel '" + channel.Name + "' error: " + err.Error()) 297 } else { 298 CommandPrettyPrintln("Deleted channel '" + channel.Name + "'") 299 } 300 } 301 302 return nil 303 } 304 305 func deleteChannel(a *app.App, channel *model.Channel) *model.AppError { 306 return a.PermanentDeleteChannel(channel) 307 } 308 309 func moveChannelsCmdF(cmd *cobra.Command, args []string) error { 310 a, err := initDBCommandContextCobra(cmd) 311 if err != nil { 312 return err 313 } 314 315 if len(args) < 2 { 316 return errors.New("Enter the destination team and at least one channel to move.") 317 } 318 319 team := getTeamFromTeamArg(a, args[0]) 320 if team == nil { 321 return errors.New("Unable to find destination team '" + args[0] + "'") 322 } 323 324 username, erru := cmd.Flags().GetString("username") 325 if erru != nil || username == "" { 326 return errors.New("Username is required") 327 } 328 user := getUserFromUserArg(a, username) 329 330 channels := getChannelsFromChannelArgs(a, args[1:]) 331 for i, channel := range channels { 332 if channel == nil { 333 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 334 continue 335 } 336 originTeamID := channel.TeamId 337 if err := moveChannel(a, team, channel, user); err != nil { 338 CommandPrintErrorln("Unable to move channel '" + channel.Name + "' error: " + err.Error()) 339 } else { 340 CommandPrettyPrintln("Moved channel '" + channel.Name + "' to " + team.Name + "(" + team.Id + ") from " + originTeamID + ".") 341 } 342 } 343 344 return nil 345 } 346 347 func moveChannel(a *app.App, team *model.Team, channel *model.Channel, user *model.User) *model.AppError { 348 oldTeamId := channel.TeamId 349 350 if err := a.MoveChannel(team, channel, user); err != nil { 351 return err 352 } 353 354 if incomingWebhooks, err := a.GetIncomingWebhooksForTeamPage(oldTeamId, 0, 10000000); err != nil { 355 return err 356 } else { 357 for _, webhook := range incomingWebhooks { 358 if webhook.ChannelId == channel.Id { 359 webhook.TeamId = team.Id 360 if result := <-a.Srv.Store.Webhook().UpdateIncoming(webhook); result.Err != nil { 361 CommandPrintErrorln("Failed to move incoming webhook '" + webhook.Id + "' to new team.") 362 } 363 } 364 } 365 } 366 367 if outgoingWebhooks, err := a.GetOutgoingWebhooksForTeamPage(oldTeamId, 0, 10000000); err != nil { 368 return err 369 } else { 370 for _, webhook := range outgoingWebhooks { 371 if webhook.ChannelId == channel.Id { 372 webhook.TeamId = team.Id 373 if result := <-a.Srv.Store.Webhook().UpdateOutgoing(webhook); result.Err != nil { 374 CommandPrintErrorln("Failed to move outgoing webhook '" + webhook.Id + "' to new team.") 375 } 376 } 377 } 378 } 379 380 return nil 381 } 382 383 func listChannelsCmdF(cmd *cobra.Command, args []string) error { 384 a, err := initDBCommandContextCobra(cmd) 385 if err != nil { 386 return err 387 } 388 389 if len(args) < 1 { 390 return errors.New("Enter at least one team.") 391 } 392 393 teams := getTeamsFromTeamArgs(a, args) 394 for i, team := range teams { 395 if team == nil { 396 CommandPrintErrorln("Unable to find team '" + args[i] + "'") 397 continue 398 } 399 if result := <-a.Srv.Store.Channel().GetAll(team.Id); result.Err != nil { 400 CommandPrintErrorln("Unable to list channels for '" + args[i] + "'") 401 } else { 402 channels := result.Data.([]*model.Channel) 403 404 for _, channel := range channels { 405 if channel.DeleteAt > 0 { 406 CommandPrettyPrintln(channel.Name + " (archived)") 407 } else { 408 CommandPrettyPrintln(channel.Name) 409 } 410 } 411 } 412 } 413 414 return nil 415 } 416 417 func restoreChannelsCmdF(cmd *cobra.Command, args []string) error { 418 a, err := initDBCommandContextCobra(cmd) 419 if err != nil { 420 return err 421 } 422 423 if len(args) < 1 { 424 return errors.New("Enter at least one channel.") 425 } 426 427 channels := getChannelsFromChannelArgs(a, args) 428 for i, channel := range channels { 429 if channel == nil { 430 CommandPrintErrorln("Unable to find channel '" + args[i] + "'") 431 continue 432 } 433 if result := <-a.Srv.Store.Channel().SetDeleteAt(channel.Id, 0, model.GetMillis()); result.Err != nil { 434 CommandPrintErrorln("Unable to restore channel '" + args[i] + "'") 435 } 436 } 437 438 return nil 439 } 440 441 func modifyChannelCmdF(cmd *cobra.Command, args []string) error { 442 a, err := initDBCommandContextCobra(cmd) 443 if err != nil { 444 return err 445 } 446 447 if len(args) != 1 { 448 return errors.New("Enter at one channel to modify.") 449 } 450 451 username, erru := cmd.Flags().GetString("username") 452 if erru != nil || username == "" { 453 return errors.New("Username is required") 454 } 455 456 public, _ := cmd.Flags().GetBool("public") 457 private, _ := cmd.Flags().GetBool("private") 458 459 if public == private { 460 return errors.New("You must specify only one of --public or --private") 461 } 462 463 channel := getChannelFromChannelArg(a, args[0]) 464 if channel == nil { 465 return errors.New("Unable to find channel '" + args[0] + "'") 466 } 467 468 if !(channel.Type == model.CHANNEL_OPEN || channel.Type == model.CHANNEL_PRIVATE) { 469 return errors.New("You can only change the type of public/private channels.") 470 } 471 472 channel.Type = model.CHANNEL_OPEN 473 if private { 474 channel.Type = model.CHANNEL_PRIVATE 475 } 476 477 user := getUserFromUserArg(a, username) 478 if _, err := a.UpdateChannelPrivacy(channel, user); err != nil { 479 return errors.New("Failed to update channel ('" + args[0] + "') privacy - " + err.Error()) 480 } 481 482 return nil 483 }