github.com/demisto/mattermost-server@v4.9.0-rc3+incompatible/cmd/commands/user.go (about)

     1  // Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package commands
     5  
     6  import (
     7  	"encoding/json"
     8  	"errors"
     9  	"fmt"
    10  	"io/ioutil"
    11  
    12  	l4g "github.com/alecthomas/log4go"
    13  	"github.com/mattermost/mattermost-server/app"
    14  	"github.com/mattermost/mattermost-server/cmd"
    15  	"github.com/mattermost/mattermost-server/model"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  var UserCmd = &cobra.Command{
    20  	Use:   "user",
    21  	Short: "Management of users",
    22  }
    23  
    24  var UserActivateCmd = &cobra.Command{
    25  	Use:   "activate [emails, usernames, userIds]",
    26  	Short: "Activate users",
    27  	Long:  "Activate users that have been deactivated.",
    28  	Example: `  user activate user@example.com
    29    user activate username`,
    30  	RunE: userActivateCmdF,
    31  }
    32  
    33  var UserDeactivateCmd = &cobra.Command{
    34  	Use:   "deactivate [emails, usernames, userIds]",
    35  	Short: "Deactivate users",
    36  	Long:  "Deactivate users. Deactivated users are immediately logged out of all sessions and are unable to log back in.",
    37  	Example: `  user deactivate user@example.com
    38    user deactivate username`,
    39  	RunE: userDeactivateCmdF,
    40  }
    41  
    42  var UserCreateCmd = &cobra.Command{
    43  	Use:     "create",
    44  	Short:   "Create a user",
    45  	Long:    "Create a user",
    46  	Example: `  user create --email user@example.com --username userexample --password Password1`,
    47  	RunE:    userCreateCmdF,
    48  }
    49  
    50  var UserInviteCmd = &cobra.Command{
    51  	Use:   "invite [email] [teams]",
    52  	Short: "Send user an email invite to a team.",
    53  	Long: `Send user an email invite to a team.
    54  You can invite a user to multiple teams by listing them.
    55  You can specify teams by name or ID.`,
    56  	Example: `  user invite user@example.com myteam
    57    user invite user@example.com myteam1 myteam2`,
    58  	RunE: userInviteCmdF,
    59  }
    60  
    61  var ResetUserPasswordCmd = &cobra.Command{
    62  	Use:     "password [user] [password]",
    63  	Short:   "Set a user's password",
    64  	Long:    "Set a user's password",
    65  	Example: "  user password user@example.com Password1",
    66  	RunE:    resetUserPasswordCmdF,
    67  }
    68  
    69  var updateUserEmailCmd = &cobra.Command{
    70  	Use:   "email [user] [new email]",
    71  	Short: "Change email of the user",
    72  	Long:  "Change email of the user.",
    73  	Example: `  user email test user@example.com
    74    user activate username`,
    75  	RunE: updateUserEmailCmdF,
    76  }
    77  
    78  var ResetUserMfaCmd = &cobra.Command{
    79  	Use:   "resetmfa [users]",
    80  	Short: "Turn off MFA",
    81  	Long: `Turn off multi-factor authentication for a user.
    82  If MFA enforcement is enabled, the user will be forced to re-enable MFA as soon as they login.`,
    83  	Example: "  user resetmfa user@example.com",
    84  	RunE:    resetUserMfaCmdF,
    85  }
    86  
    87  var DeleteUserCmd = &cobra.Command{
    88  	Use:     "delete [users]",
    89  	Short:   "Delete users and all posts",
    90  	Long:    "Permanently delete user and all related information including posts.",
    91  	Example: "  user delete user@example.com",
    92  	RunE:    deleteUserCmdF,
    93  }
    94  
    95  var DeleteAllUsersCmd = &cobra.Command{
    96  	Use:     "deleteall",
    97  	Short:   "Delete all users and all posts",
    98  	Long:    "Permanently delete all users and all related information including posts.",
    99  	Example: "  user deleteall",
   100  	RunE:    deleteAllUsersCommandF,
   101  }
   102  
   103  var MigrateAuthCmd = &cobra.Command{
   104  	Use:     "migrate_auth [from_auth] [to_auth] [migration-options]",
   105  	Short:   "Mass migrate user accounts authentication type",
   106  	Long:    `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap.`,
   107  	Example: "  user migrate_auth email saml users.json",
   108  	Args: func(cmd *cobra.Command, args []string) error {
   109  		if len(args) < 2 {
   110  			return errors.New("Auth migration requires at least 2 arguments.")
   111  		}
   112  
   113  		toAuth := args[1]
   114  
   115  		if toAuth != "ldap" && toAuth != "saml" {
   116  			return errors.New("Invalid to_auth parameter, must be saml or ldap.")
   117  		}
   118  
   119  		if toAuth == "ldap" && len(args) != 3 {
   120  			return errors.New("Ldap migration requires 3 arguments.")
   121  		}
   122  
   123  		autoFlag, _ := cmd.Flags().GetBool("auto")
   124  
   125  		if toAuth == "saml" && autoFlag {
   126  			if len(args) != 2 {
   127  				return errors.New("Saml migration requires two arguments when using the --auto flag. See help text for details.")
   128  			}
   129  		}
   130  
   131  		if toAuth == "saml" && !autoFlag {
   132  			if len(args) != 3 {
   133  				return errors.New("Saml migration requires three arguments when not using the --auto flag. See help text for details.")
   134  			}
   135  		}
   136  		return nil
   137  	},
   138  	RunE: migrateAuthCmdF,
   139  }
   140  
   141  var VerifyUserCmd = &cobra.Command{
   142  	Use:     "verify [users]",
   143  	Short:   "Verify email of users",
   144  	Long:    "Verify the emails of some users.",
   145  	Example: "  user verify user1",
   146  	RunE:    verifyUserCmdF,
   147  }
   148  
   149  var SearchUserCmd = &cobra.Command{
   150  	Use:     "search [users]",
   151  	Short:   "Search for users",
   152  	Long:    "Search for users based on username, email, or user ID.",
   153  	Example: "  user search user1@mail.com user2@mail.com",
   154  	RunE:    searchUserCmdF,
   155  }
   156  
   157  func init() {
   158  	UserCreateCmd.Flags().String("username", "", "Required. Username for the new user account.")
   159  	UserCreateCmd.Flags().String("email", "", "Required. The email address for the new user account.")
   160  	UserCreateCmd.Flags().String("password", "", "Required. The password for the new user account.")
   161  	UserCreateCmd.Flags().String("nickname", "", "Optional. The nickname for the new user account.")
   162  	UserCreateCmd.Flags().String("firstname", "", "Optional. The first name for the new user account.")
   163  	UserCreateCmd.Flags().String("lastname", "", "Optional. The last name for the new user account.")
   164  	UserCreateCmd.Flags().String("locale", "", "Optional. The locale (ex: en, fr) for the new user account.")
   165  	UserCreateCmd.Flags().Bool("system_admin", false, "Optional. If supplied, the new user will be a system administrator. Defaults to false.")
   166  
   167  	DeleteUserCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
   168  
   169  	DeleteAllUsersCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
   170  
   171  	MigrateAuthCmd.Flags().Bool("force", false, "Force the migration to occur even if there are duplicates on the LDAP server. Duplicates will not be migrated. (ldap only)")
   172  	MigrateAuthCmd.Flags().Bool("auto", false, "Automatically migrate all users. Assumes the usernames and emails are identical between Mattermost and SAML services. (saml only)")
   173  	MigrateAuthCmd.Flags().Bool("dryRun", false, "Run a simulation of the migration process without changing the database.")
   174  	MigrateAuthCmd.SetUsageTemplate(`Usage:
   175    platform user migrate_auth [from_auth] [to_auth] [migration-options] [flags]
   176  
   177  Examples:
   178  {{.Example}}
   179  
   180  Arguments:
   181    from_auth:
   182      The authentication service to migrate users accounts from.
   183      Supported options: email, gitlab, ldap, saml.
   184  
   185    to_auth:
   186      The authentication service to migrate users to.
   187      Supported options: ldap, saml.
   188  
   189    migration-options:
   190      Migration specific options, full command help for more information.
   191  
   192  Flags:
   193  {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
   194  
   195  Global Flags:
   196  {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}
   197  `)
   198  	MigrateAuthCmd.SetHelpTemplate(`Usage:
   199    platform user migrate_auth [from_auth] [to_auth] [migration-options] [flags]
   200  
   201  Examples:
   202  {{.Example}}
   203  
   204  Arguments:
   205    from_auth:
   206      The authentication service to migrate users accounts from.
   207      Supported options: email, gitlab, ldap, saml.
   208  
   209    to_auth:
   210      The authentication service to migrate users to.
   211      Supported options: ldap, saml.
   212  
   213    migration-options (ldap):
   214      match_field:
   215        The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email.
   216        Supported options: email, username.
   217  
   218    migration-options (saml):
   219      users_file:
   220        The path of a json file with the usernames and emails of all users to migrate to SAML. The username and email must be the same that the SAML service provider store. And the email must match with the email in mattermost database.
   221  
   222        Example json content:
   223          {
   224            "usr1@email.com": "usr.one",
   225            "usr2@email.com": "usr.two"
   226          }
   227  
   228  Flags:
   229  {{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}
   230  
   231  Global Flags:
   232  {{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}
   233  `)
   234  
   235  	UserCmd.AddCommand(
   236  		UserActivateCmd,
   237  		UserDeactivateCmd,
   238  		UserCreateCmd,
   239  		UserInviteCmd,
   240  		ResetUserPasswordCmd,
   241  		updateUserEmailCmd,
   242  		ResetUserMfaCmd,
   243  		DeleteUserCmd,
   244  		DeleteAllUsersCmd,
   245  		MigrateAuthCmd,
   246  		VerifyUserCmd,
   247  		SearchUserCmd,
   248  	)
   249  	cmd.RootCmd.AddCommand(UserCmd)
   250  }
   251  
   252  func userActivateCmdF(command *cobra.Command, args []string) error {
   253  	a, err := cmd.InitDBCommandContextCobra(command)
   254  	if err != nil {
   255  		return err
   256  	}
   257  
   258  	if len(args) < 1 {
   259  		return errors.New("Expected at least one argument. See help text for details.")
   260  	}
   261  
   262  	changeUsersActiveStatus(a, args, true)
   263  	return nil
   264  }
   265  
   266  func changeUsersActiveStatus(a *app.App, userArgs []string, active bool) {
   267  	users := getUsersFromUserArgs(a, userArgs)
   268  	for i, user := range users {
   269  		err := changeUserActiveStatus(a, user, userArgs[i], active)
   270  
   271  		if err != nil {
   272  			cmd.CommandPrintErrorln(err.Error())
   273  		}
   274  	}
   275  }
   276  
   277  func changeUserActiveStatus(a *app.App, user *model.User, userArg string, activate bool) error {
   278  	if user == nil {
   279  		return fmt.Errorf("Can't find user '%v'", userArg)
   280  	}
   281  	if user.IsSSOUser() {
   282  		fmt.Println("You must also deactivate this user in the SSO provider or they will be reactivated on next login or sync.")
   283  	}
   284  	if _, err := a.UpdateActive(user, activate); err != nil {
   285  		return fmt.Errorf("Unable to change activation status of user: %v", userArg)
   286  	}
   287  
   288  	return nil
   289  }
   290  
   291  func userDeactivateCmdF(command *cobra.Command, args []string) error {
   292  	a, err := cmd.InitDBCommandContextCobra(command)
   293  	if err != nil {
   294  		return err
   295  	}
   296  
   297  	if len(args) < 1 {
   298  		return errors.New("Expected at least one argument. See help text for details.")
   299  	}
   300  
   301  	changeUsersActiveStatus(a, args, false)
   302  	return nil
   303  }
   304  
   305  func userCreateCmdF(command *cobra.Command, args []string) error {
   306  	a, err := cmd.InitDBCommandContextCobra(command)
   307  	if err != nil {
   308  		return err
   309  	}
   310  
   311  	username, erru := command.Flags().GetString("username")
   312  	if erru != nil || username == "" {
   313  		return errors.New("Username is required")
   314  	}
   315  	email, erre := command.Flags().GetString("email")
   316  	if erre != nil || email == "" {
   317  		return errors.New("Email is required")
   318  	}
   319  	password, errp := command.Flags().GetString("password")
   320  	if errp != nil || password == "" {
   321  		return errors.New("Password is required")
   322  	}
   323  	nickname, _ := command.Flags().GetString("nickname")
   324  	firstname, _ := command.Flags().GetString("firstname")
   325  	lastname, _ := command.Flags().GetString("lastname")
   326  	locale, _ := command.Flags().GetString("locale")
   327  	systemAdmin, _ := command.Flags().GetBool("system_admin")
   328  
   329  	user := &model.User{
   330  		Username:  username,
   331  		Email:     email,
   332  		Password:  password,
   333  		Nickname:  nickname,
   334  		FirstName: firstname,
   335  		LastName:  lastname,
   336  		Locale:    locale,
   337  	}
   338  
   339  	if ruser, err := a.CreateUser(user); err != nil {
   340  		return errors.New("Unable to create user. Error: " + err.Error())
   341  	} else if systemAdmin {
   342  		a.UpdateUserRoles(ruser.Id, "system_user system_admin", false)
   343  	}
   344  
   345  	cmd.CommandPrettyPrintln("Created User")
   346  
   347  	return nil
   348  }
   349  
   350  func userInviteCmdF(command *cobra.Command, args []string) error {
   351  	a, err := cmd.InitDBCommandContextCobra(command)
   352  	if err != nil {
   353  		return err
   354  	}
   355  
   356  	if len(args) < 2 {
   357  		return errors.New("Expected at least two arguments. See help text for details.")
   358  	}
   359  
   360  	email := args[0]
   361  	if !model.IsValidEmail(email) {
   362  		return errors.New("Invalid email")
   363  	}
   364  
   365  	teams := getTeamsFromTeamArgs(a, args[1:])
   366  	for i, team := range teams {
   367  		err := inviteUser(a, email, team, args[i+1])
   368  
   369  		if err != nil {
   370  			cmd.CommandPrintErrorln(err.Error())
   371  		}
   372  	}
   373  
   374  	return nil
   375  }
   376  
   377  func inviteUser(a *app.App, email string, team *model.Team, teamArg string) error {
   378  	invites := []string{email}
   379  	if team == nil {
   380  		return fmt.Errorf("Can't find team '%v'", teamArg)
   381  	}
   382  
   383  	a.SendInviteEmails(team, "Administrator", invites, *a.Config().ServiceSettings.SiteURL)
   384  	cmd.CommandPrettyPrintln("Invites may or may not have been sent.")
   385  
   386  	return nil
   387  }
   388  
   389  func resetUserPasswordCmdF(command *cobra.Command, args []string) error {
   390  	a, err := cmd.InitDBCommandContextCobra(command)
   391  	if err != nil {
   392  		return err
   393  	}
   394  
   395  	if len(args) != 2 {
   396  		return errors.New("Expected two arguments. See help text for details.")
   397  	}
   398  
   399  	user := getUserFromUserArg(a, args[0])
   400  	if user == nil {
   401  		return errors.New("Unable to find user '" + args[0] + "'")
   402  	}
   403  	password := args[1]
   404  
   405  	if result := <-a.Srv.Store.User().UpdatePassword(user.Id, model.HashPassword(password)); result.Err != nil {
   406  		return result.Err
   407  	}
   408  
   409  	return nil
   410  }
   411  
   412  func updateUserEmailCmdF(command *cobra.Command, args []string) error {
   413  	a, err := cmd.InitDBCommandContextCobra(command)
   414  	if err != nil {
   415  		return err
   416  	}
   417  
   418  	newEmail := args[1]
   419  
   420  	if !model.IsValidEmail(newEmail) {
   421  		return errors.New("Invalid email: '" + newEmail + "'")
   422  	}
   423  
   424  	if len(args) != 2 {
   425  		return errors.New("Expected two arguments. See help text for details.")
   426  	}
   427  
   428  	user := getUserFromUserArg(a, args[0])
   429  	if user == nil {
   430  		return errors.New("Unable to find user '" + args[0] + "'")
   431  	}
   432  
   433  	user.Email = newEmail
   434  	_, errUpdate := a.UpdateUser(user, true)
   435  	if err != nil {
   436  		return errUpdate
   437  	}
   438  
   439  	return nil
   440  }
   441  
   442  func resetUserMfaCmdF(command *cobra.Command, args []string) error {
   443  	a, err := cmd.InitDBCommandContextCobra(command)
   444  	if err != nil {
   445  		return err
   446  	}
   447  
   448  	if len(args) < 1 {
   449  		return errors.New("Expected at least one argument. See help text for details.")
   450  	}
   451  
   452  	users := getUsersFromUserArgs(a, args)
   453  
   454  	for i, user := range users {
   455  		if user == nil {
   456  			return errors.New("Unable to find user '" + args[i] + "'")
   457  		}
   458  
   459  		if err := a.DeactivateMfa(user.Id); err != nil {
   460  			return err
   461  		}
   462  	}
   463  
   464  	return nil
   465  }
   466  
   467  func deleteUserCmdF(command *cobra.Command, args []string) error {
   468  	a, err := cmd.InitDBCommandContextCobra(command)
   469  	if err != nil {
   470  		return err
   471  	}
   472  
   473  	if len(args) < 1 {
   474  		return errors.New("Expected at least one argument. See help text for details.")
   475  	}
   476  
   477  	confirmFlag, _ := command.Flags().GetBool("confirm")
   478  	if !confirmFlag {
   479  		var confirm string
   480  		cmd.CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
   481  		fmt.Scanln(&confirm)
   482  
   483  		if confirm != "YES" {
   484  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   485  		}
   486  		cmd.CommandPrettyPrintln("Are you sure you want to permanently delete the specified users? (YES/NO): ")
   487  		fmt.Scanln(&confirm)
   488  		if confirm != "YES" {
   489  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   490  		}
   491  	}
   492  
   493  	users := getUsersFromUserArgs(a, args)
   494  
   495  	for i, user := range users {
   496  		if user == nil {
   497  			return errors.New("Unable to find user '" + args[i] + "'")
   498  		}
   499  
   500  		if err := a.PermanentDeleteUser(user); err != nil {
   501  			return err
   502  		}
   503  	}
   504  
   505  	return nil
   506  }
   507  
   508  func deleteAllUsersCommandF(command *cobra.Command, args []string) error {
   509  	a, err := cmd.InitDBCommandContextCobra(command)
   510  	if err != nil {
   511  		return err
   512  	}
   513  
   514  	if len(args) > 0 {
   515  		return errors.New("Expected zero arguments.")
   516  	}
   517  
   518  	confirmFlag, _ := command.Flags().GetBool("confirm")
   519  	if !confirmFlag {
   520  		var confirm string
   521  		cmd.CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
   522  		fmt.Scanln(&confirm)
   523  
   524  		if confirm != "YES" {
   525  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   526  		}
   527  		cmd.CommandPrettyPrintln("Are you sure you want to permanently delete all user accounts? (YES/NO): ")
   528  		fmt.Scanln(&confirm)
   529  		if confirm != "YES" {
   530  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   531  		}
   532  	}
   533  
   534  	if err := a.PermanentDeleteAllUsers(); err != nil {
   535  		return err
   536  	}
   537  
   538  	cmd.CommandPrettyPrintln("All user accounts successfully deleted.")
   539  	return nil
   540  }
   541  
   542  func migrateAuthCmdF(command *cobra.Command, args []string) error {
   543  	if args[1] == "saml" {
   544  		return migrateAuthToSamlCmdF(command, args)
   545  	}
   546  	return migrateAuthToLdapCmdF(command, args)
   547  }
   548  
   549  func migrateAuthToLdapCmdF(command *cobra.Command, args []string) error {
   550  	a, err := cmd.InitDBCommandContextCobra(command)
   551  	if err != nil {
   552  		return err
   553  	}
   554  
   555  	fromAuth := args[0]
   556  	matchField := args[2]
   557  
   558  	if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "saml") {
   559  		return errors.New("Invalid from_auth argument")
   560  	}
   561  
   562  	// Email auth in Mattermost system is represented by ""
   563  	if fromAuth == "email" {
   564  		fromAuth = ""
   565  	}
   566  
   567  	if len(matchField) == 0 || (matchField != "email" && matchField != "username") {
   568  		return errors.New("Invalid match_field argument")
   569  	}
   570  
   571  	forceFlag, _ := command.Flags().GetBool("force")
   572  	dryRunFlag, _ := command.Flags().GetBool("dryRun")
   573  
   574  	if migrate := a.AccountMigration; migrate != nil {
   575  		if err := migrate.MigrateToLdap(fromAuth, matchField, forceFlag, dryRunFlag); err != nil {
   576  			return errors.New("Error while migrating users: " + err.Error())
   577  		}
   578  
   579  		cmd.CommandPrettyPrintln("Successfully migrated accounts.")
   580  	}
   581  
   582  	return nil
   583  }
   584  
   585  func migrateAuthToSamlCmdF(command *cobra.Command, args []string) error {
   586  	a, err := cmd.InitDBCommandContextCobra(command)
   587  	if err != nil {
   588  		return err
   589  	}
   590  
   591  	dryRunFlag, _ := command.Flags().GetBool("dryRun")
   592  	autoFlag, _ := command.Flags().GetBool("auto")
   593  
   594  	matchesFile := ""
   595  	matches := map[string]string{}
   596  	if !autoFlag {
   597  		matchesFile = args[2]
   598  
   599  		file, e := ioutil.ReadFile(matchesFile)
   600  		if e != nil {
   601  			return errors.New("Invalid users file.")
   602  		}
   603  		if json.Unmarshal(file, &matches) != nil {
   604  			return errors.New("Invalid users file.")
   605  		}
   606  	}
   607  
   608  	fromAuth := args[0]
   609  
   610  	if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "ldap") {
   611  		return errors.New("Invalid from_auth argument")
   612  	}
   613  
   614  	if autoFlag && !dryRunFlag {
   615  		var confirm string
   616  		cmd.CommandPrettyPrintln("You are about to perform an automatic \"" + fromAuth + " to saml\" migration. This must only be done if your current Mattermost users with " + fromAuth + " auth have the same username and email in your SAML service. Otherwise, provide the usernames and emails from your SAML Service using the \"users file\" without the \"--auto\" option.\n\nDo you want to proceed with automatic migration anyway? (YES/NO):")
   617  		fmt.Scanln(&confirm)
   618  
   619  		if confirm != "YES" {
   620  			return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
   621  		}
   622  	}
   623  
   624  	// Email auth in Mattermost system is represented by ""
   625  	if fromAuth == "email" {
   626  		fromAuth = ""
   627  	}
   628  
   629  	if migrate := a.AccountMigration; migrate != nil {
   630  		if err := migrate.MigrateToSaml(fromAuth, matches, autoFlag, dryRunFlag); err != nil {
   631  			return errors.New("Error while migrating users: " + err.Error())
   632  		}
   633  		l4g.Close()
   634  		cmd.CommandPrettyPrintln("Successfully migrated accounts.")
   635  	}
   636  
   637  	return nil
   638  }
   639  
   640  func verifyUserCmdF(command *cobra.Command, args []string) error {
   641  	a, err := cmd.InitDBCommandContextCobra(command)
   642  	if err != nil {
   643  		return err
   644  	}
   645  
   646  	if len(args) < 1 {
   647  		return errors.New("Expected at least one argument. See help text for details.")
   648  	}
   649  
   650  	users := getUsersFromUserArgs(a, args)
   651  
   652  	for i, user := range users {
   653  		if user == nil {
   654  			cmd.CommandPrintErrorln("Unable to find user '" + args[i] + "'")
   655  			continue
   656  		}
   657  		if cresult := <-a.Srv.Store.User().VerifyEmail(user.Id); cresult.Err != nil {
   658  			cmd.CommandPrintErrorln("Unable to verify '" + args[i] + "' email. Error: " + cresult.Err.Error())
   659  		}
   660  	}
   661  
   662  	return nil
   663  }
   664  
   665  func searchUserCmdF(command *cobra.Command, args []string) error {
   666  	a, err := cmd.InitDBCommandContextCobra(command)
   667  	if err != nil {
   668  		return err
   669  	}
   670  
   671  	if len(args) < 1 {
   672  		return errors.New("Expected at least one argument. See help text for details.")
   673  	}
   674  
   675  	users := getUsersFromUserArgs(a, args)
   676  
   677  	for i, user := range users {
   678  		if i > 0 {
   679  			cmd.CommandPrettyPrintln("------------------------------")
   680  		}
   681  		if user == nil {
   682  			cmd.CommandPrintErrorln("Unable to find user '" + args[i] + "'")
   683  			continue
   684  		}
   685  
   686  		cmd.CommandPrettyPrintln("id: " + user.Id)
   687  		cmd.CommandPrettyPrintln("username: " + user.Username)
   688  		cmd.CommandPrettyPrintln("nickname: " + user.Nickname)
   689  		cmd.CommandPrettyPrintln("position: " + user.Position)
   690  		cmd.CommandPrettyPrintln("first_name: " + user.FirstName)
   691  		cmd.CommandPrettyPrintln("last_name: " + user.LastName)
   692  		cmd.CommandPrettyPrintln("email: " + user.Email)
   693  		cmd.CommandPrettyPrintln("auth_service: " + user.AuthService)
   694  	}
   695  
   696  	return nil
   697  }