Improving command line interface (#4689)

Этот коммит содержится в:
Christopher Speller
2016-12-06 10:49:34 -05:00
коммит произвёл GitHub
родитель dcf11a14d8
Коммит 026553e4f8
130 изменённых файлов: 16375 добавлений и 669 удалений

284
cmd/platform/channel.go Обычный файл
Просмотреть файл

@@ -0,0 +1,284 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"github.com/spf13/cobra"
)
var channelCmd = &cobra.Command{
Use: "channel",
Short: "Management of channels",
}
var channelCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a channel",
Long: `Create a channel.`,
Example: ` channel create --team myteam --name mynewchannel --display_name "My New Channel"
channel create --team myteam --name mynewprivatechannel --display_name "My New Private Channel" --private`,
RunE: createChannelCmdF,
}
var removeChannelUsersCmd = &cobra.Command{
Use: "remove [channel] [users]",
Short: "Remove users from channel",
Long: "Remove some users from channel",
Example: " channel remove mychannel user@example.com username",
RunE: removeChannelUsersCmdF,
}
var addChannelUsersCmd = &cobra.Command{
Use: "add [channel] [users]",
Short: "Add users to channel",
Long: "Add some users to channel",
Example: " channel add mychannel user@example.com username",
RunE: addChannelUsersCmdF,
}
var deleteChannelsCmd = &cobra.Command{
Use: "delete [channels]",
Short: "Delete channels",
Long: `Permanently delete some channels.
Permanently deletes a channel along with all related information including posts from the database.
Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`,
Example: " channel delete myteam:mychannel",
RunE: deleteChannelsCmdF,
}
var listChannelsCmd = &cobra.Command{
Use: "list [teams]",
Short: "List all channels on specified teams.",
Long: `List all channels on specified teams.
Archived channels are appended with ' (archived)'.`,
Example: " channel list myteam",
RunE: listChannelsCmdF,
}
var restoreChannelsCmd = &cobra.Command{
Use: "restore [channels]",
Short: "Restore some channels",
Long: `Restore a previously deleted channel
Channels can be specified by [team]:[channel]. ie. myteam:mychannel or by channel ID.`,
Example: " channel restore myteam:mychannel",
RunE: restoreChannelsCmdF,
}
func init() {
channelCreateCmd.Flags().String("name", "", "Channel Name")
channelCreateCmd.Flags().String("display_name", "", "Channel Display Name")
channelCreateCmd.Flags().String("team", "", "Team name or ID")
channelCreateCmd.Flags().String("header", "", "Channel header")
channelCreateCmd.Flags().String("purpose", "", "Channel purpose")
channelCreateCmd.Flags().Bool("private", false, "Create a private channel.")
channelCmd.AddCommand(
channelCreateCmd,
removeChannelUsersCmd,
addChannelUsersCmd,
deleteChannelsCmd,
listChannelsCmd,
restoreChannelsCmd,
)
}
func createChannelCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if !utils.IsLicensed {
return errors.New(utils.T("cli.license.critical"))
}
name, errn := cmd.Flags().GetString("name")
if errn != nil || name == "" {
return errors.New("Name is required")
}
displayname, errdn := cmd.Flags().GetString("display_name")
if errdn != nil || displayname == "" {
return errors.New("Display Name is required")
}
teamArg, errteam := cmd.Flags().GetString("team")
if errteam != nil || teamArg == "" {
return errors.New("Team is required")
}
header, _ := cmd.Flags().GetString("header")
purpose, _ := cmd.Flags().GetString("purpose")
useprivate, _ := cmd.Flags().GetBool("private")
channelType := model.CHANNEL_OPEN
if useprivate {
channelType = model.CHANNEL_PRIVATE
}
team := getTeamFromTeamArg(teamArg)
channel := &model.Channel{
TeamId: team.Id,
Name: name,
DisplayName: displayname,
Header: header,
Purpose: purpose,
Type: channelType,
}
c := getMockContext()
if _, err := api.CreateChannel(c, channel, false); err != nil {
return err
}
return nil
}
func removeChannelUsersCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if !utils.IsLicensed {
return errors.New(utils.T("cli.license.critical"))
}
if len(args) < 2 {
return errors.New("Not enough arguments.")
}
channel := getChannelFromChannelArg(args[0])
if channel == nil {
return errors.New("Unable to find channel '" + args[0] + "'")
}
users := getUsersFromUserArgs(args[1:])
for i, user := range users {
removeUserFromChannel(channel, user, args[i+1])
}
return nil
}
func removeUserFromChannel(channel *model.Channel, user *model.User, userArg string) {
if user == nil {
CommandPrintErrorln("Can't find user '" + userArg + "'")
return
}
if err := api.RemoveUserFromChannel(user.Id, "", channel); err != nil {
CommandPrintErrorln("Unable to remove '" + userArg + "' from " + channel.Name + ". Error: " + err.Error())
}
}
func addChannelUsersCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if !utils.IsLicensed {
return errors.New(utils.T("cli.license.critical"))
}
if len(args) < 2 {
return errors.New("Not enough arguments.")
}
channel := getChannelFromChannelArg(args[0])
if channel == nil {
return errors.New("Unable to find channel '" + args[0] + "'")
}
users := getUsersFromUserArgs(args[1:])
for i, user := range users {
addUserToChannel(channel, user, args[i+1])
}
return nil
}
func addUserToChannel(channel *model.Channel, user *model.User, userArg string) {
if user == nil {
CommandPrintErrorln("Can't find user '" + userArg + "'")
return
}
if _, err := api.AddUserToChannel(user, channel); err != nil {
CommandPrintErrorln("Unable to add '" + userArg + "' from " + channel.Name + ". Error: " + err.Error())
}
}
func deleteChannelsCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter at least one channel to delete.")
}
channels := getChannelsFromChannelArgs(args)
for i, channel := range channels {
if channel == nil {
CommandPrintErrorln("Unable to find channel '" + args[i] + "'")
continue
}
if result := <-api.Srv.Store.Channel().Delete(channel.Id, model.GetMillis()); result.Err != nil {
CommandPrintErrorln("Unable to delete channel '" + channel.Name + "' error: " + result.Err.Error())
}
}
return nil
}
func listChannelsCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if !utils.IsLicensed {
return errors.New(utils.T("cli.license.critical"))
}
if len(args) < 1 {
return errors.New("Enter at least one team.")
}
teams := getTeamsFromTeamArgs(args)
for i, team := range teams {
if team == nil {
CommandPrintErrorln("Unable to find team '" + args[i] + "'")
continue
}
if result := <-api.Srv.Store.Channel().GetAll(team.Id); result.Err != nil {
CommandPrintErrorln("Unable to list channels for '" + args[i] + "'")
} else {
channels := result.Data.([]*model.Channel)
for _, channel := range channels {
if channel.DeleteAt > 0 {
CommandPrettyPrintln(channel.Name + " (archived)")
} else {
CommandPrettyPrintln(channel.Name)
}
}
}
}
return nil
}
func restoreChannelsCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if !utils.IsLicensed {
return errors.New(utils.T("cli.license.critical"))
}
if len(args) < 1 {
return errors.New("Enter at least one channel.")
}
channels := getChannelsFromChannelArgs(args)
for i, channel := range channels {
if channel == nil {
CommandPrintErrorln("Unable to find channel '" + args[i] + "'")
continue
}
if result := <-api.Srv.Store.Channel().SetDeleteAt(channel.Id, 0, model.GetMillis()); result.Err != nil {
CommandPrintErrorln("Unable to restore channel '" + args[i] + "'")
}
}
return nil
}

59
cmd/platform/channelargs.go Обычный файл
Просмотреть файл

@@ -0,0 +1,59 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"fmt"
"strings"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
)
const CHANNEL_ARG_SEPARATOR = ":"
func getChannelsFromChannelArgs(channelArgs []string) []*model.Channel {
channels := make([]*model.Channel, 0, len(channelArgs))
for _, channelArg := range channelArgs {
channel := getChannelFromChannelArg(channelArg)
channels = append(channels, channel)
}
return channels
}
func parseChannelArg(channelArg string) (string, string) {
result := strings.SplitN(channelArg, CHANNEL_ARG_SEPARATOR, 2)
if len(result) == 1 {
return "", channelArg
}
return result[0], result[1]
}
func getChannelFromChannelArg(channelArg string) *model.Channel {
teamArg, channelPart := parseChannelArg(channelArg)
if teamArg == "" && channelPart == "" {
return nil
}
var channel *model.Channel
if teamArg != "" {
team := getTeamFromTeamArg(teamArg)
if team == nil {
return nil
}
if result := <-api.Srv.Store.Channel().GetByNameIncludeDeleted(team.Id, channelPart); result.Err == nil {
channel = result.Data.(*model.Channel)
} else {
fmt.Println(result.Err.Error())
}
}
if channel == nil {
if result := <-api.Srv.Store.Channel().Get(channelPart); result.Err == nil {
channel = result.Data.(*model.Channel)
}
}
return channel
}

62
cmd/platform/import.go Обычный файл
Просмотреть файл

@@ -0,0 +1,62 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"os"
"github.com/mattermost/platform/api"
"github.com/spf13/cobra"
)
var importCmd = &cobra.Command{
Use: "import",
Short: "Import data.",
}
var slackImportCmd = &cobra.Command{
Use: "slack [team] [file]",
Short: "Import a team from Slack.",
Long: "Import a team from a Slack export zip file.",
Example: " import slack myteam slack_export.zip",
RunE: slackImportCmdF,
}
func init() {
importCmd.AddCommand(
slackImportCmd,
)
}
func slackImportCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) != 2 {
return errors.New("Incorrect number of arguments.")
}
team := getTeamFromTeamArg(args[0])
if team == nil {
return errors.New("Unable to find team '" + args[0] + "'")
}
fileReader, err := os.Open(args[1])
if err != nil {
return err
}
defer fileReader.Close()
fileInfo, err := fileReader.Stat()
if err != nil {
return err
}
CommandPrettyPrintln("Running Slack Import. This may take a long time for large teams or teams with many messages.")
api.SlackImport(fileReader, fileInfo.Size(), team.Id)
CommandPrettyPrintln("Finished Slack Import.")
return nil
}

41
cmd/platform/init.go Обычный файл
Просмотреть файл

@@ -0,0 +1,41 @@
package main
import (
"fmt"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/utils"
"github.com/spf13/cobra"
)
func doLoadConfig(filename string) (err string) {
defer func() {
if r := recover(); r != nil {
err = fmt.Sprintf("%v", r)
}
}()
utils.TranslationsPreInit()
utils.LoadConfig(filename)
return ""
}
func initDBCommandContextCobra(cmd *cobra.Command) error {
config, err := cmd.Flags().GetString("config")
if err != nil {
return err
}
initDBCommandContext(config)
return nil
}
func initDBCommandContext(configFileLocation string) {
if errstr := doLoadConfig(configFileLocation); errstr != "" {
return
}
utils.ConfigureCmdLineLog()
api.NewServer()
api.InitStores()
}

39
cmd/platform/ldap.go Обычный файл
Просмотреть файл

@@ -0,0 +1,39 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"github.com/mattermost/platform/einterfaces"
"github.com/spf13/cobra"
)
var ldapCmd = &cobra.Command{
Use: "ldap",
Short: "LDAP related utilities",
}
var ldapSyncCmd = &cobra.Command{
Use: "sync",
Short: "Synchronize now",
Long: "Synchronize all LDAP users now.",
Example: " ldap sync",
RunE: ldapSyncCmdF,
}
func init() {
ldapCmd.AddCommand(
ldapSyncCmd,
)
}
func ldapSyncCmdF(cmd *cobra.Command, args []string) error {
if ldapI := einterfaces.GetLdapInterface(); ldapI != nil {
if err := ldapI.Syncronize(); err != nil {
CommandPrintErrorln("ERROR: AD/LDAP Synchronization Failed")
} else {
CommandPrettyPrintln("SUCCESS: AD/LDAP Synchronization Complete")
}
}
return nil
}

50
cmd/platform/license.go Обычный файл
Просмотреть файл

@@ -0,0 +1,50 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"io/ioutil"
"github.com/mattermost/platform/api"
"github.com/spf13/cobra"
)
var licenseCmd = &cobra.Command{
Use: "license",
Short: "Licensing commands",
}
var uploadLicenseCmd = &cobra.Command{
Use: "upload [license]",
Short: "Upload a license.",
Long: "Upload a license. Replaces current license.",
Example: " license upload /path/to/license/mylicensefile.mattermost-license",
RunE: uploadLicenseCmdF,
}
func init() {
licenseCmd.AddCommand(uploadLicenseCmd)
}
func uploadLicenseCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) != 1 {
return errors.New("Enter one license file to upload")
}
var fileBytes []byte
var err error
if fileBytes, err = ioutil.ReadFile(args[0]); err != nil {
return err
}
if _, err := api.SaveLicense(fileBytes); err != nil {
return err
}
CommandPrettyPrintln("Uploaded license file")
return nil
}

84
cmd/platform/mattermost.go Обычный файл
Просмотреть файл

@@ -0,0 +1,84 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"flag"
"fmt"
"os"
"github.com/mattermost/platform/api"
"github.com/spf13/cobra"
// Plugins
_ "github.com/mattermost/platform/model/gitlab"
// Enterprise Deps
_ "github.com/dgryski/dgoogauth"
_ "github.com/go-ldap/ldap"
_ "github.com/mattermost/rsc/qr"
)
//ENTERPRISE_IMPORTS
func main() {
var rootCmd = &cobra.Command{
Use: "platform",
Short: "Open source, self-hosted Slack-alternative",
Long: `Mattermost offers workplace messaging across web, PC and phones with archiving, search and integration with your existing systems. Documentation available at https://docs.mattermost.com`,
RunE: runServerCmd,
}
rootCmd.PersistentFlags().StringP("config", "c", "config.json", "Configuration file to use.")
resetCmd.Flags().Bool("confirm", false, "Confirm you really want to delete everything and a DB backup has been performed.")
rootCmd.AddCommand(serverCmd, versionCmd, userCmd, teamCmd, licenseCmd, importCmd, resetCmd, channelCmd, rolesCmd, testCmd, ldapCmd)
flag.Usage = func() {
rootCmd.Usage()
}
parseCmds()
if flagRunCmds {
CommandPrintErrorln("---------------------------------------------------------------------------------------------")
CommandPrintErrorln("DEPRECATED! All previous commands are now deprecated. Run: platform help to see the new ones.")
CommandPrintErrorln("---------------------------------------------------------------------------------------------")
doLegacyCommands()
} else {
if err := rootCmd.Execute(); err != nil {
os.Exit(1)
}
}
}
var resetCmd = &cobra.Command{
Use: "reset",
Short: "Reset the database to initial state",
Long: "Completely erases the database causing the loss of all data. This will reset Mattermost to its initial state.",
RunE: resetCmdF,
}
func resetCmdF(cmd *cobra.Command, args []string) error {
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag {
var confirm string
CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
CommandPrettyPrintln("Are you sure you want to delete everything? All data will be permanently deleted? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
}
api.Srv.Store.DropAllTables()
CommandPrettyPrintln("Database sucessfully reset")
return nil
}

1102
cmd/platform/oldcommands.go Обычный файл

Разница между файлами не показана из-за своего большого размера Загрузить разницу

32
cmd/platform/output.go Обычный файл
Просмотреть файл

@@ -0,0 +1,32 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"fmt"
"os"
)
func CommandPrintln(a ...interface{}) (int, error) {
return fmt.Println(a...)
}
func CommandPrint(a ...interface{}) (int, error) {
return fmt.Print(a...)
}
func CommandPrintErrorln(a ...interface{}) (int, error) {
return fmt.Fprintln(os.Stderr, a...)
}
func CommandPrintError(a ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, a...)
}
func CommandPrettyPrintln(a ...interface{}) (int, error) {
return fmt.Fprintln(os.Stderr, a...)
}
func CommandPrettyPrint(a ...interface{}) (int, error) {
return fmt.Fprint(os.Stderr, a...)
}

78
cmd/platform/roles.go Обычный файл
Просмотреть файл

@@ -0,0 +1,78 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"github.com/mattermost/platform/api"
"github.com/spf13/cobra"
)
var rolesCmd = &cobra.Command{
Use: "roles",
Short: "Management of user roles",
}
var makeSystemAdminCmd = &cobra.Command{
Use: "system_admin [users]",
Short: "Set a user as system admin",
Long: "Make some users system admins",
Example: " roles system_admin user1",
RunE: makeSystemAdminCmdF,
}
var makeMemberCmd = &cobra.Command{
Use: "member [users]",
Short: "Remove system admin privileges",
Long: "Remove system admin privileges from some users.",
Example: " roles member user1",
RunE: makeMemberCmdF,
}
func init() {
rolesCmd.AddCommand(
makeSystemAdminCmd,
makeMemberCmd,
)
}
func makeSystemAdminCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter at least one user.")
}
users := getUsersFromUserArgs(args)
for i, user := range users {
if user == nil {
return errors.New("Unable to find user '" + args[i] + "'")
}
if _, err := api.UpdateUserRoles(user, "system_admin system_user"); err != nil {
return err
}
}
return nil
}
func makeMemberCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter at least one user.")
}
users := getUsersFromUserArgs(args)
for i, user := range users {
if user == nil {
return errors.New("Unable to find user '" + args[i] + "'")
}
if _, err := api.UpdateUserRoles(user, "system_user"); err != nil {
return err
}
}
return nil
}

277
cmd/platform/server.go Обычный файл
Просмотреть файл

@@ -0,0 +1,277 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"io/ioutil"
"net/http"
"net/url"
"os"
"os/signal"
"runtime"
"strconv"
"syscall"
"time"
l4g "github.com/alecthomas/log4go"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/manualtesting"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"github.com/mattermost/platform/web"
"github.com/spf13/cobra"
)
var serverCmd = &cobra.Command{
Use: "server",
Short: "Run the Mattermost server",
RunE: runServerCmd,
}
func runServerCmd(cmd *cobra.Command, args []string) error {
config, err := cmd.Flags().GetString("config")
if err != nil {
return err
}
runServer(config)
return nil
}
func runServer(configFileLocation string) {
if errstr := doLoadConfig(configFileLocation); errstr != "" {
l4g.Exit("Unable to load mattermost configuration file: ", errstr)
return
}
utils.InitTranslations(utils.Cfg.LocalizationSettings)
utils.TestConnection(utils.Cfg)
pwd, _ := os.Getwd()
l4g.Info(utils.T("mattermost.current_version"), model.CurrentVersion, model.BuildNumber, model.BuildDate, model.BuildHash, model.BuildHashEnterprise)
l4g.Info(utils.T("mattermost.entreprise_enabled"), model.BuildEnterpriseReady)
l4g.Info(utils.T("mattermost.working_dir"), pwd)
l4g.Info(utils.T("mattermost.config_file"), utils.FindConfigFile(configFileLocation))
// Enable developer settings if this is a "dev" build
if model.BuildNumber == "dev" {
*utils.Cfg.ServiceSettings.EnableDeveloper = true
}
cmdUpdateDb30()
api.NewServer()
api.InitStores()
api.InitRouter()
api.InitApi()
web.InitWeb()
if model.BuildEnterpriseReady == "true" {
api.LoadLicense()
}
if !utils.IsLicensed && len(utils.Cfg.SqlSettings.DataSourceReplicas) > 1 {
l4g.Critical(utils.T("store.sql.read_replicas_not_licensed.critical"))
return
}
resetStatuses()
api.StartServer()
// If we allow testing then listen for manual testing URL hits
if utils.Cfg.ServiceSettings.EnableTesting {
manualtesting.InitManualTesting()
}
setDiagnosticId()
go runSecurityAndDiagnosticsJob()
if complianceI := einterfaces.GetComplianceInterface(); complianceI != nil {
complianceI.StartComplianceDailyJob()
}
if einterfaces.GetClusterInterface() != nil {
einterfaces.GetClusterInterface().StartInterNodeCommunication()
}
if einterfaces.GetMetricsInterface() != nil {
einterfaces.GetMetricsInterface().StartServer()
}
// wait for kill signal before attempting to gracefully shutdown
// the running service
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
<-c
if einterfaces.GetClusterInterface() != nil {
einterfaces.GetClusterInterface().StopInterNodeCommunication()
}
if einterfaces.GetMetricsInterface() != nil {
einterfaces.GetMetricsInterface().StopServer()
}
api.StopServer()
}
func runSecurityAndDiagnosticsJob() {
doSecurityAndDiagnostics()
model.CreateRecurringTask("Security and Diagnostics", doSecurityAndDiagnostics, time.Hour*4)
}
func resetStatuses() {
if result := <-api.Srv.Store.Status().ResetAll(); result.Err != nil {
l4g.Error(utils.T("mattermost.reset_status.error"), result.Err.Error())
}
}
func setDiagnosticId() {
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
props := result.Data.(model.StringMap)
id := props[model.SYSTEM_DIAGNOSTIC_ID]
if len(id) == 0 {
id = model.NewId()
systemId := &model.System{Name: model.SYSTEM_DIAGNOSTIC_ID, Value: id}
<-api.Srv.Store.System().Save(systemId)
}
utils.CfgDiagnosticId = id
}
}
func doSecurityAndDiagnostics() {
if *utils.Cfg.ServiceSettings.EnableSecurityFixAlert {
if result := <-api.Srv.Store.System().Get(); result.Err == nil {
props := result.Data.(model.StringMap)
lastSecurityTime, _ := strconv.ParseInt(props[model.SYSTEM_LAST_SECURITY_TIME], 10, 0)
currentTime := model.GetMillis()
if (currentTime - lastSecurityTime) > 1000*60*60*24*1 {
l4g.Debug(utils.T("mattermost.security_checks.debug"))
v := url.Values{}
v.Set(utils.PROP_DIAGNOSTIC_ID, utils.CfgDiagnosticId)
v.Set(utils.PROP_DIAGNOSTIC_BUILD, model.CurrentVersion+"."+model.BuildNumber)
v.Set(utils.PROP_DIAGNOSTIC_ENTERPRISE_READY, model.BuildEnterpriseReady)
v.Set(utils.PROP_DIAGNOSTIC_DATABASE, utils.Cfg.SqlSettings.DriverName)
v.Set(utils.PROP_DIAGNOSTIC_OS, runtime.GOOS)
v.Set(utils.PROP_DIAGNOSTIC_CATEGORY, utils.VAL_DIAGNOSTIC_CATEGORY_DEFAULT)
if len(props[model.SYSTEM_RAN_UNIT_TESTS]) > 0 {
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "1")
} else {
v.Set(utils.PROP_DIAGNOSTIC_UNIT_TESTS, "0")
}
systemSecurityLastTime := &model.System{Name: model.SYSTEM_LAST_SECURITY_TIME, Value: strconv.FormatInt(currentTime, 10)}
if lastSecurityTime == 0 {
<-api.Srv.Store.System().Save(systemSecurityLastTime)
} else {
<-api.Srv.Store.System().Update(systemSecurityLastTime)
}
if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
v.Set(utils.PROP_DIAGNOSTIC_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
}
if ucr := <-api.Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil {
v.Set(utils.PROP_DIAGNOSTIC_ACTIVE_USER_COUNT, strconv.FormatInt(ucr.Data.(int64), 10))
}
if tcr := <-api.Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil {
v.Set(utils.PROP_DIAGNOSTIC_TEAM_COUNT, strconv.FormatInt(tcr.Data.(int64), 10))
}
res, err := http.Get(utils.DIAGNOSTIC_URL + "/security?" + v.Encode())
if err != nil {
l4g.Error(utils.T("mattermost.security_info.error"))
return
}
bulletins := model.SecurityBulletinsFromJson(res.Body)
ioutil.ReadAll(res.Body)
res.Body.Close()
for _, bulletin := range bulletins {
if bulletin.AppliesToVersion == model.CurrentVersion {
if props["SecurityBulletin_"+bulletin.Id] == "" {
if results := <-api.Srv.Store.User().GetSystemAdminProfiles(); results.Err != nil {
l4g.Error(utils.T("mattermost.system_admins.error"))
return
} else {
users := results.Data.(map[string]*model.User)
resBody, err := http.Get(utils.DIAGNOSTIC_URL + "/bulletins/" + bulletin.Id)
if err != nil {
l4g.Error(utils.T("mattermost.security_bulletin.error"))
return
}
body, err := ioutil.ReadAll(resBody.Body)
res.Body.Close()
if err != nil || resBody.StatusCode != 200 {
l4g.Error(utils.T("mattermost.security_bulletin_read.error"))
return
}
for _, user := range users {
l4g.Info(utils.T("mattermost.send_bulletin.info"), bulletin.Id, user.Email)
utils.SendMail(user.Email, utils.T("mattermost.bulletin.subject"), string(body))
}
}
bulletinSeen := &model.System{Name: "SecurityBulletin_" + bulletin.Id, Value: bulletin.Id}
<-api.Srv.Store.System().Save(bulletinSeen)
}
}
}
}
}
}
if *utils.Cfg.LogSettings.EnableDiagnostics {
utils.SendGeneralDiagnostics()
sendServerDiagnostics()
}
}
func sendServerDiagnostics() {
var userCount int64
var activeUserCount int64
var teamCount int64
if ucr := <-api.Srv.Store.User().GetTotalUsersCount(); ucr.Err == nil {
userCount = ucr.Data.(int64)
}
if ucr := <-api.Srv.Store.Status().GetTotalActiveUsersCount(); ucr.Err == nil {
activeUserCount = ucr.Data.(int64)
}
if tcr := <-api.Srv.Store.Team().AnalyticsTeamCount(); tcr.Err == nil {
teamCount = tcr.Data.(int64)
}
utils.SendDiagnostic(utils.TRACK_ACTIVITY, map[string]interface{}{
"registered_users": userCount,
"active_users": activeUserCount,
"teams": teamCount,
})
edition := model.BuildEnterpriseReady
version := model.CurrentVersion
database := utils.Cfg.SqlSettings.DriverName
operatingSystem := runtime.GOOS
utils.SendDiagnostic(utils.TRACK_VERSION, map[string]interface{}{
"edition": edition,
"version": version,
"database": database,
"operating_system": operatingSystem,
})
}

205
cmd/platform/team.go Обычный файл
Просмотреть файл

@@ -0,0 +1,205 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"fmt"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
"github.com/spf13/cobra"
)
var teamCmd = &cobra.Command{
Use: "team",
Short: "Management of teams",
}
var teamCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a team",
Long: `Create a team.`,
Example: ` team create --name mynewteam --display_name "My New Team"
teams create --name private --display_name "My New Private Team" --private`,
RunE: createTeamCmdF,
}
var removeUsersCmd = &cobra.Command{
Use: "remove [team] [users]",
Short: "Remove users from team",
Long: "Remove some users from team",
Example: " team remove myteam user@example.com username",
RunE: removeUsersCmdF,
}
var addUsersCmd = &cobra.Command{
Use: "add [team] [users]",
Short: "Add users to team",
Long: "Add some users to team",
Example: " team add myteam user@example.com username",
RunE: addUsersCmdF,
}
var deleteTeamsCmd = &cobra.Command{
Use: "delete [teams]",
Short: "Delete teams",
Long: `Permanently delete some teams.
Permanently deletes a team along with all related information including posts from the database.`,
Example: " team delete myteam",
RunE: deleteTeamsCmdF,
}
func init() {
teamCreateCmd.Flags().String("name", "", "Team Name")
teamCreateCmd.Flags().String("display_name", "", "Team Display Name")
teamCreateCmd.Flags().Bool("private", false, "Create a private team.")
teamCreateCmd.Flags().String("email", "", "Administrator Email (anyone with this email is automatically a team admin)")
deleteTeamsCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the team and a DB backup has been performed.")
teamCmd.AddCommand(
teamCreateCmd,
removeUsersCmd,
addUsersCmd,
deleteTeamsCmd,
)
}
func createTeamCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
name, errn := cmd.Flags().GetString("name")
if errn != nil || name == "" {
return errors.New("Name is required")
}
displayname, errdn := cmd.Flags().GetString("display_name")
if errdn != nil || displayname == "" {
return errors.New("Display Name is required")
}
email, _ := cmd.Flags().GetString("email")
useprivate, _ := cmd.Flags().GetBool("private")
teamType := model.TEAM_OPEN
if useprivate {
teamType = model.TEAM_INVITE
}
team := &model.Team{
Name: name,
DisplayName: displayname,
Email: email,
Type: teamType,
}
c := getMockContext()
api.CreateTeam(c, team)
if c.Err != nil {
return errors.New("Team creation failed: " + c.Err.Error())
}
return nil
}
func removeUsersCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 2 {
return errors.New("Not enough arguments.")
}
team := getTeamFromTeamArg(args[0])
if team == nil {
return errors.New("Unable to find team '" + args[0] + "'")
}
users := getUsersFromUserArgs(args[1:])
for i, user := range users {
removeUserFromTeam(team, user, args[i+1])
}
return nil
}
func removeUserFromTeam(team *model.Team, user *model.User, userArg string) {
if user == nil {
CommandPrintErrorln("Can't find user '" + userArg + "'")
return
}
if err := api.LeaveTeam(team, user); err != nil {
CommandPrintErrorln("Unable to remove '" + userArg + "' from " + team.Name + ". Error: " + err.Error())
}
}
func addUsersCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 2 {
return errors.New("Not enough arguments.")
}
team := getTeamFromTeamArg(args[0])
if team == nil {
return errors.New("Unable to find team '" + args[0] + "'")
}
users := getUsersFromUserArgs(args[1:])
for i, user := range users {
addUserToTeam(team, user, args[i+1])
}
return nil
}
func addUserToTeam(team *model.Team, user *model.User, userArg string) {
if user == nil {
CommandPrintErrorln("Can't find user '" + userArg + "'")
return
}
if err := api.JoinUserToTeam(team, user); err != nil {
CommandPrintErrorln("Unable to add '" + userArg + "' to " + team.Name)
}
}
func deleteTeamsCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Not enough arguments.")
}
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag {
var confirm string
CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
CommandPrettyPrintln("Are you sure you want to delete the teams specified? All data will be permanently deleted? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
}
teams := getTeamsFromTeamArgs(args)
for i, team := range teams {
if team == nil {
CommandPrintErrorln("Unable to find team '" + args[i] + "'")
continue
}
if err := deleteTeam(team); err != nil {
CommandPrintErrorln("Unable to delete team '" + team.Name + "' error: " + err.Error())
} else {
CommandPrettyPrintln("Deleted team '" + team.Name + "'")
}
}
return nil
}
func deleteTeam(team *model.Team) *model.AppError {
return api.PermanentDeleteTeam(team)
}

32
cmd/platform/teamargs.go Обычный файл
Просмотреть файл

@@ -0,0 +1,32 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
)
func getTeamsFromTeamArgs(teamArgs []string) []*model.Team {
teams := make([]*model.Team, 0, len(teamArgs))
for _, teamArg := range teamArgs {
team := getTeamFromTeamArg(teamArg)
teams = append(teams, team)
}
return teams
}
func getTeamFromTeamArg(teamArg string) *model.Team {
var team *model.Team
if result := <-api.Srv.Store.Team().GetByName(teamArg); result.Err == nil {
team = result.Data.(*model.Team)
}
if team == nil {
if result := <-api.Srv.Store.Team().Get(teamArg); result.Err == nil {
team = result.Data.(*model.Team)
}
}
return team
}

82
cmd/platform/test.go Обычный файл
Просмотреть файл

@@ -0,0 +1,82 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"bufio"
"fmt"
"os"
"os/exec"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/utils"
"github.com/spf13/cobra"
)
var testCmd = &cobra.Command{
Use: "test",
Short: "Testing Commands",
Hidden: true,
}
var runWebClientTestsCmd = &cobra.Command{
Use: "web_client_tests",
Short: "Run the web client tests",
RunE: webClientTestsCmdF,
}
func init() {
testCmd.AddCommand(
runWebClientTestsCmd,
)
}
func webClientTestsCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
utils.InitTranslations(utils.Cfg.LocalizationSettings)
api.InitRouter()
api.InitApi()
setupClientTests()
api.StartServer()
runWebClientTests()
api.StopServer()
return nil
}
func setupClientTests() {
*utils.Cfg.TeamSettings.EnableOpenServer = true
*utils.Cfg.ServiceSettings.EnableCommands = false
*utils.Cfg.ServiceSettings.EnableOnlyAdminIntegrations = false
*utils.Cfg.ServiceSettings.EnableCustomEmoji = true
utils.Cfg.ServiceSettings.EnableIncomingWebhooks = false
utils.Cfg.ServiceSettings.EnableOutgoingWebhooks = false
utils.SetDefaultRolesBasedOnConfig()
}
func executeTestCommand(cmd *exec.Cmd) {
cmdOutPipe, err := cmd.StdoutPipe()
if err != nil {
CommandPrintErrorln("Failed to run tests")
return
}
cmdOutReader := bufio.NewScanner(cmdOutPipe)
go func() {
for cmdOutReader.Scan() {
fmt.Println(cmdOutReader.Text())
}
}()
if err := cmd.Run(); err != nil {
CommandPrintErrorln("Client Tests failed")
return
}
}
func runWebClientTests() {
os.Chdir("webapp")
cmd := exec.Command("npm", "test")
executeTestCommand(cmd)
}

432
cmd/platform/user.go Обычный файл
Просмотреть файл

@@ -0,0 +1,432 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"errors"
"fmt"
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/einterfaces"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/utils"
"github.com/spf13/cobra"
)
var userCmd = &cobra.Command{
Use: "user",
Short: "Management of users",
}
var userActivateCmd = &cobra.Command{
Use: "activate [emails, usernames, userIds]",
Short: "Activate users",
Long: "Activate users that have been deactivated.",
Example: ` user activate user@example.com
user activate username`,
RunE: userActivateCmdF,
}
var userDeactivateCmd = &cobra.Command{
Use: "deactivate [emails, usernames, userIds]",
Short: "Deactivate users",
Long: "Deactivate users. Deactivated users are immediately logged out of all sessions and are unable to log back in.",
Example: ` user deactivate user@example.com
user deactivate username`,
RunE: userDeactivateCmdF,
}
var userCreateCmd = &cobra.Command{
Use: "create",
Short: "Create a user",
Long: "Create a user",
Example: ` user create --email user@example.com --username userexample --password Password1
user create --firstname Joe --system_admin --email joe@example.com --username joe --password Password1`,
RunE: userCreateCmdF,
}
var userInviteCmd = &cobra.Command{
Use: "invite [email] [teams]",
Short: "Send user an email invite to a team.",
Long: `Send user an email invite to a team.
You can invite a user to multiple teams by listing them.
You can specify teams by name or ID.`,
Example: ` user invite user@example.com myteam
user invite user@example.com myteam1 myteam2`,
RunE: userInviteCmdF,
}
var resetUserPasswordCmd = &cobra.Command{
Use: "password [user] [password]",
Short: "Set a user's password",
Long: "Set a user's password",
Example: " user password user@example.com Password1",
RunE: resetUserPasswordCmdF,
}
var resetUserMfaCmd = &cobra.Command{
Use: "resetmfa [users]",
Short: "Turn off MFA",
Long: `Turn off multi-factor authentication for a user.
If MFA enforcement is enabled, the user will be forced to re-enable MFA as soon as they login.`,
Example: " user resetmfa user@example.com",
RunE: resetUserMfaCmdF,
}
var deleteUserCmd = &cobra.Command{
Use: "delete [users]",
Short: "Delete users and all posts",
Long: "Permanently delete user and all related information including posts.",
Example: " user delete user@example.com",
RunE: deleteUserCmdF,
}
var deleteAllUsersCmd = &cobra.Command{
Use: "deleteall",
Short: "Delete all users and all posts",
Long: "Permanently delete all users and all related information including posts.",
Example: " user deleteall",
RunE: deleteUserCmdF,
}
var migrateAuthCmd = &cobra.Command{
Use: "migrate_auth [from_auth] [to_auth] [match_field]",
Short: "Mass migrate user accounts authentication type",
Long: `Migrates accounts from one authentication provider to another. For example, you can upgrade your authentication provider from email to ldap.
from_auth:
The authentication service to migrate users accounts from.
Supported options: email, gitlab, saml.
to_auth:
The authentication service to migrate users to.
Supported options: ldap.
match_field:
The field that is guaranteed to be the same in both authentication services. For example, if the users emails are consistent set to email.
Supported options: email, username.
Will display any accounts that are not migrated successfully.`,
Example: " user migrate_auth email ladp email",
RunE: migrateAuthCmdF,
}
var verifyUserCmd = &cobra.Command{
Use: "verify [users]",
Short: "Verify email of users",
Long: "Verify the emails of some users.",
Example: " user verify user1",
RunE: verifyUserCmdF,
}
func init() {
userCreateCmd.Flags().String("username", "", "Username")
userCreateCmd.Flags().String("email", "", "Email")
userCreateCmd.Flags().String("password", "", "Password")
userCreateCmd.Flags().String("nickname", "", "Nickname")
userCreateCmd.Flags().String("firstname", "", "First Name")
userCreateCmd.Flags().String("lastname", "", "Last Name")
userCreateCmd.Flags().String("locale", "", "Locale (ex: en, fr)")
userCreateCmd.Flags().Bool("system_admin", false, "Make the user a system administrator")
deleteUserCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
deleteAllUsersCmd.Flags().Bool("confirm", false, "Confirm you really want to delete the user and a DB backup has been performed.")
userCmd.AddCommand(
userActivateCmd,
userDeactivateCmd,
userCreateCmd,
userInviteCmd,
resetUserPasswordCmd,
resetUserMfaCmd,
deleteUserCmd,
deleteAllUsersCmd,
migrateAuthCmd,
verifyUserCmd,
)
}
func userActivateCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter user(s) to activate.")
}
changeUsersActiveStatus(args, true)
return nil
}
func changeUsersActiveStatus(userArgs []string, active bool) {
users := getUsersFromUserArgs(userArgs)
for i, user := range users {
changeUserActiveStatus(user, userArgs[i], active)
}
}
func changeUserActiveStatus(user *model.User, userArg string, activate bool) {
if user == nil {
CommandPrintErrorln("Can't find user '" + userArg + "'")
return
}
if user.IsLDAPUser() {
CommandPrintErrorln(utils.T("api.user.update_active.no_deactivate_ldap.app_error"))
return
}
if _, err := api.UpdateActive(user, activate); err != nil {
CommandPrintErrorln("Unable to change activation status of user: " + userArg)
}
}
func userDeactivateCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter user(s) to deactivate.")
}
changeUsersActiveStatus(args, false)
return nil
}
func userCreateCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
username, erru := cmd.Flags().GetString("username")
if erru != nil || username == "" {
return errors.New("Username is required")
}
email, erre := cmd.Flags().GetString("email")
if erre != nil || email == "" {
return errors.New("Email is required")
}
password, errp := cmd.Flags().GetString("password")
if errp != nil || password == "" {
return errors.New("Password is required")
}
nickname, _ := cmd.Flags().GetString("nickname")
firstname, _ := cmd.Flags().GetString("firstname")
lastname, _ := cmd.Flags().GetString("lastname")
locale, _ := cmd.Flags().GetString("locale")
system_admin, _ := cmd.Flags().GetBool("system_admin")
user := &model.User{
Username: username,
Email: email,
Password: password,
Nickname: nickname,
FirstName: firstname,
LastName: lastname,
Locale: locale,
}
ruser, err := api.CreateUser(user)
if err != nil {
return errors.New("Unable to create user. Error: " + err.Error())
}
if system_admin {
api.UpdateUserRoles(ruser, "system_user system_admin")
}
CommandPrettyPrintln("Created User")
return nil
}
func userInviteCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
utils.InitHTML()
if len(args) < 2 {
return errors.New("Not enough arguments.")
}
email := args[0]
if !model.IsValidEmail(email) {
return errors.New("Invalid email")
}
teams := getTeamsFromTeamArgs(args[1:])
for i, team := range teams {
inviteUser(email, team, args[i+1])
}
return nil
}
func inviteUser(email string, team *model.Team, teamArg string) {
invites := []string{email}
if team == nil {
CommandPrintErrorln("Can't find team '" + teamArg + "'")
return
}
api.InviteMembers(team, "Administrator", invites)
CommandPrettyPrintln("Invites may or may not have been sent.")
}
func resetUserPasswordCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) != 2 {
return errors.New("Incorect number of arguments.")
}
user := getUserFromUserArg(args[0])
if user == nil {
return errors.New("Unable to find user '" + args[0] + "'")
}
password := args[1]
if result := <-api.Srv.Store.User().UpdatePassword(user.Id, model.HashPassword(password)); result.Err != nil {
return result.Err
}
return nil
}
func resetUserMfaCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter at least one user.")
}
users := getUsersFromUserArgs(args)
for i, user := range users {
if user == nil {
return errors.New("Unable to find user '" + args[i] + "'")
}
if err := api.DeactivateMfa(user.Id); err != nil {
return err
}
}
return nil
}
func deleteUserCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter at least one user.")
}
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag {
var confirm string
CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
CommandPrettyPrintln("Are you sure you want to delete the teams specified? All data will be permanently deleted? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
}
users := getUsersFromUserArgs(args)
for i, user := range users {
if user == nil {
return errors.New("Unable to find user '" + args[i] + "'")
}
if err := api.PermanentDeleteUser(user); err != nil {
return err
}
}
return nil
}
func deleteAllUsersCommandF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) > 0 {
return errors.New("Don't enter any agruments.")
}
confirmFlag, _ := cmd.Flags().GetBool("confirm")
if !confirmFlag {
var confirm string
CommandPrettyPrintln("Have you performed a database backup? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
CommandPrettyPrintln("Are you sure you want to delete the teams specified? All data will be permanently deleted? (YES/NO): ")
fmt.Scanln(&confirm)
if confirm != "YES" {
return errors.New("ABORTED: You did not answer YES exactly, in all capitals.")
}
}
if err := api.PermanentDeleteAllUsers(); err != nil {
return err
} else {
CommandPrettyPrintln("Sucsessfull. All users deleted.")
}
return nil
}
func migrateAuthCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) != 3 {
return errors.New("Enter the correct number of arguments.")
}
fromAuth := args[0]
toAuth := args[1]
matchField := args[2]
if len(fromAuth) == 0 || (fromAuth != "email" && fromAuth != "gitlab" && fromAuth != "saml") {
return errors.New("Invalid from_auth argument")
}
if len(toAuth) == 0 || toAuth != "ldap" {
return errors.New("Invalid to_auth argument")
}
// Email auth in Mattermost system is represented by ""
if fromAuth == "email" {
fromAuth = ""
}
if len(matchField) == 0 || (matchField != "email" && matchField != "username") {
return errors.New("Invalid match_field argument")
}
if migrate := einterfaces.GetAccountMigrationInterface(); migrate != nil {
if err := migrate.MigrateToLdap(fromAuth, matchField); err != nil {
return errors.New("Error while migrating users: " + err.Error())
} else {
CommandPrettyPrintln("Sucessfully migrated accounts.")
}
}
return nil
}
func verifyUserCmdF(cmd *cobra.Command, args []string) error {
initDBCommandContextCobra(cmd)
if len(args) < 1 {
return errors.New("Enter at least one user.")
}
users := getUsersFromUserArgs(args)
for i, user := range users {
if user == nil {
CommandPrintErrorln("Unable to find user '" + args[i] + "'")
}
if cresult := <-api.Srv.Store.User().VerifyEmail(user.Id); cresult.Err != nil {
CommandPrintErrorln("Unable to verify '" + args[i] + "' email. Error: " + cresult.Err.Error())
}
}
return nil
}

38
cmd/platform/userargs.go Обычный файл
Просмотреть файл

@@ -0,0 +1,38 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
)
func getUsersFromUserArgs(userArgs []string) []*model.User {
users := make([]*model.User, 0, len(userArgs))
for _, userArg := range userArgs {
user := getUserFromUserArg(userArg)
users = append(users, user)
}
return users
}
func getUserFromUserArg(userArg string) *model.User {
var user *model.User
if result := <-api.Srv.Store.User().GetByEmail(userArg); result.Err == nil {
user = result.Data.(*model.User)
}
if user == nil {
if result := <-api.Srv.Store.User().GetByUsername(userArg); result.Err == nil {
user = result.Data.(*model.User)
}
}
if user == nil {
if result := <-api.Srv.Store.User().Get(userArg); result.Err == nil {
user = result.Data.(*model.User)
}
}
return user
}

30
cmd/platform/version.go Обычный файл
Просмотреть файл

@@ -0,0 +1,30 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
package main
import (
"github.com/mattermost/platform/api"
"github.com/mattermost/platform/model"
"github.com/mattermost/platform/store"
"github.com/spf13/cobra"
)
var versionCmd = &cobra.Command{
Use: "version",
Short: "Display version information",
Run: versionCmdF,
}
func versionCmdF(cmd *cobra.Command, args []string) {
initDBCommandContextCobra(cmd)
printVersion()
}
func printVersion() {
CommandPrintln("Version: " + model.CurrentVersion)
CommandPrintln("Build Number: " + model.BuildNumber)
CommandPrintln("Build Date: " + model.BuildDate)
CommandPrintln("Build Hash: " + model.BuildHash)
CommandPrintln("Build Enterprise Ready: " + model.BuildEnterpriseReady)
CommandPrintln("DB Version: " + api.Srv.Store.(*store.SqlStore).SchemaVersion)
}