github.com/psyb0t/mattermost-server@v4.6.1-0.20180125161845-5503a1351abf+incompatible/model/client4.go (about)

     1  // Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"mime/multipart"
    12  	"net/http"
    13  	"net/url"
    14  	"strconv"
    15  	"strings"
    16  )
    17  
    18  type Response struct {
    19  	StatusCode    int
    20  	Error         *AppError
    21  	RequestId     string
    22  	Etag          string
    23  	ServerVersion string
    24  	Header        http.Header
    25  }
    26  
    27  type Client4 struct {
    28  	Url        string       // The location of the server, for example  "http://localhost:8065"
    29  	ApiUrl     string       // The api location of the server, for example "http://localhost:8065/api/v4"
    30  	HttpClient *http.Client // The http client
    31  	AuthToken  string
    32  	AuthType   string
    33  }
    34  
    35  func NewAPIv4Client(url string) *Client4 {
    36  	return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", ""}
    37  }
    38  
    39  func BuildErrorResponse(r *http.Response, err *AppError) *Response {
    40  	var statusCode int
    41  	var header http.Header
    42  	if r != nil {
    43  		statusCode = r.StatusCode
    44  		header = r.Header
    45  	} else {
    46  		statusCode = 0
    47  		header = make(http.Header)
    48  	}
    49  
    50  	return &Response{
    51  		StatusCode: statusCode,
    52  		Error:      err,
    53  		Header:     header,
    54  	}
    55  }
    56  
    57  func BuildResponse(r *http.Response) *Response {
    58  	return &Response{
    59  		StatusCode:    r.StatusCode,
    60  		RequestId:     r.Header.Get(HEADER_REQUEST_ID),
    61  		Etag:          r.Header.Get(HEADER_ETAG_SERVER),
    62  		ServerVersion: r.Header.Get(HEADER_VERSION_ID),
    63  		Header:        r.Header,
    64  	}
    65  }
    66  
    67  func (c *Client4) SetOAuthToken(token string) {
    68  	c.AuthToken = token
    69  	c.AuthType = HEADER_TOKEN
    70  }
    71  
    72  func (c *Client4) ClearOAuthToken() {
    73  	c.AuthToken = ""
    74  	c.AuthType = HEADER_BEARER
    75  }
    76  
    77  func (c *Client4) GetUsersRoute() string {
    78  	return fmt.Sprintf("/users")
    79  }
    80  
    81  func (c *Client4) GetUserRoute(userId string) string {
    82  	return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
    83  }
    84  
    85  func (c *Client4) GetUserAccessTokensRoute() string {
    86  	return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
    87  }
    88  
    89  func (c *Client4) GetUserAccessTokenRoute(tokenId string) string {
    90  	return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId)
    91  }
    92  
    93  func (c *Client4) GetUserByUsernameRoute(userName string) string {
    94  	return fmt.Sprintf(c.GetUsersRoute()+"/username/%v", userName)
    95  }
    96  
    97  func (c *Client4) GetUserByEmailRoute(email string) string {
    98  	return fmt.Sprintf(c.GetUsersRoute()+"/email/%v", email)
    99  }
   100  
   101  func (c *Client4) GetTeamsRoute() string {
   102  	return fmt.Sprintf("/teams")
   103  }
   104  
   105  func (c *Client4) GetTeamRoute(teamId string) string {
   106  	return fmt.Sprintf(c.GetTeamsRoute()+"/%v", teamId)
   107  }
   108  
   109  func (c *Client4) GetTeamAutoCompleteCommandsRoute(teamId string) string {
   110  	return fmt.Sprintf(c.GetTeamsRoute()+"/%v/commands/autocomplete", teamId)
   111  }
   112  
   113  func (c *Client4) GetTeamByNameRoute(teamName string) string {
   114  	return fmt.Sprintf(c.GetTeamsRoute()+"/name/%v", teamName)
   115  }
   116  
   117  func (c *Client4) GetTeamMemberRoute(teamId, userId string) string {
   118  	return fmt.Sprintf(c.GetTeamRoute(teamId)+"/members/%v", userId)
   119  }
   120  
   121  func (c *Client4) GetTeamMembersRoute(teamId string) string {
   122  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/members")
   123  }
   124  
   125  func (c *Client4) GetTeamStatsRoute(teamId string) string {
   126  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/stats")
   127  }
   128  
   129  func (c *Client4) GetTeamImportRoute(teamId string) string {
   130  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/import")
   131  }
   132  
   133  func (c *Client4) GetChannelsRoute() string {
   134  	return fmt.Sprintf("/channels")
   135  }
   136  
   137  func (c *Client4) GetChannelsForTeamRoute(teamId string) string {
   138  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/channels")
   139  }
   140  
   141  func (c *Client4) GetChannelRoute(channelId string) string {
   142  	return fmt.Sprintf(c.GetChannelsRoute()+"/%v", channelId)
   143  }
   144  
   145  func (c *Client4) GetChannelByNameRoute(channelName, teamId string) string {
   146  	return fmt.Sprintf(c.GetTeamRoute(teamId)+"/channels/name/%v", channelName)
   147  }
   148  
   149  func (c *Client4) GetChannelByNameForTeamNameRoute(channelName, teamName string) string {
   150  	return fmt.Sprintf(c.GetTeamByNameRoute(teamName)+"/channels/name/%v", channelName)
   151  }
   152  
   153  func (c *Client4) GetChannelMembersRoute(channelId string) string {
   154  	return fmt.Sprintf(c.GetChannelRoute(channelId) + "/members")
   155  }
   156  
   157  func (c *Client4) GetChannelMemberRoute(channelId, userId string) string {
   158  	return fmt.Sprintf(c.GetChannelMembersRoute(channelId)+"/%v", userId)
   159  }
   160  
   161  func (c *Client4) GetPostsRoute() string {
   162  	return fmt.Sprintf("/posts")
   163  }
   164  
   165  func (c *Client4) GetConfigRoute() string {
   166  	return fmt.Sprintf("/config")
   167  }
   168  
   169  func (c *Client4) GetLicenseRoute() string {
   170  	return fmt.Sprintf("/license")
   171  }
   172  
   173  func (c *Client4) GetPostRoute(postId string) string {
   174  	return fmt.Sprintf(c.GetPostsRoute()+"/%v", postId)
   175  }
   176  
   177  func (c *Client4) GetFilesRoute() string {
   178  	return fmt.Sprintf("/files")
   179  }
   180  
   181  func (c *Client4) GetFileRoute(fileId string) string {
   182  	return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId)
   183  }
   184  
   185  func (c *Client4) GetPluginsRoute() string {
   186  	return fmt.Sprintf("/plugins")
   187  }
   188  
   189  func (c *Client4) GetPluginRoute(pluginId string) string {
   190  	return fmt.Sprintf(c.GetPluginsRoute()+"/%v", pluginId)
   191  }
   192  
   193  func (c *Client4) GetSystemRoute() string {
   194  	return fmt.Sprintf("/system")
   195  }
   196  
   197  func (c *Client4) GetTestEmailRoute() string {
   198  	return fmt.Sprintf("/email/test")
   199  }
   200  
   201  func (c *Client4) GetDatabaseRoute() string {
   202  	return fmt.Sprintf("/database")
   203  }
   204  
   205  func (c *Client4) GetCacheRoute() string {
   206  	return fmt.Sprintf("/caches")
   207  }
   208  
   209  func (c *Client4) GetClusterRoute() string {
   210  	return fmt.Sprintf("/cluster")
   211  }
   212  
   213  func (c *Client4) GetIncomingWebhooksRoute() string {
   214  	return fmt.Sprintf("/hooks/incoming")
   215  }
   216  
   217  func (c *Client4) GetIncomingWebhookRoute(hookID string) string {
   218  	return fmt.Sprintf(c.GetIncomingWebhooksRoute()+"/%v", hookID)
   219  }
   220  
   221  func (c *Client4) GetComplianceReportsRoute() string {
   222  	return fmt.Sprintf("/compliance/reports")
   223  }
   224  
   225  func (c *Client4) GetComplianceReportRoute(reportId string) string {
   226  	return fmt.Sprintf("/compliance/reports/%v", reportId)
   227  }
   228  
   229  func (c *Client4) GetOutgoingWebhooksRoute() string {
   230  	return fmt.Sprintf("/hooks/outgoing")
   231  }
   232  
   233  func (c *Client4) GetOutgoingWebhookRoute(hookID string) string {
   234  	return fmt.Sprintf(c.GetOutgoingWebhooksRoute()+"/%v", hookID)
   235  }
   236  
   237  func (c *Client4) GetPreferencesRoute(userId string) string {
   238  	return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences")
   239  }
   240  
   241  func (c *Client4) GetUserStatusRoute(userId string) string {
   242  	return fmt.Sprintf(c.GetUserRoute(userId) + "/status")
   243  }
   244  
   245  func (c *Client4) GetUserStatusesRoute() string {
   246  	return fmt.Sprintf(c.GetUsersRoute() + "/status")
   247  }
   248  
   249  func (c *Client4) GetSamlRoute() string {
   250  	return fmt.Sprintf("/saml")
   251  }
   252  
   253  func (c *Client4) GetLdapRoute() string {
   254  	return fmt.Sprintf("/ldap")
   255  }
   256  
   257  func (c *Client4) GetBrandRoute() string {
   258  	return fmt.Sprintf("/brand")
   259  }
   260  
   261  func (c *Client4) GetDataRetentionRoute() string {
   262  	return fmt.Sprintf("/data_retention")
   263  }
   264  
   265  func (c *Client4) GetElasticsearchRoute() string {
   266  	return fmt.Sprintf("/elasticsearch")
   267  }
   268  
   269  func (c *Client4) GetCommandsRoute() string {
   270  	return fmt.Sprintf("/commands")
   271  }
   272  
   273  func (c *Client4) GetCommandRoute(commandId string) string {
   274  	return fmt.Sprintf(c.GetCommandsRoute()+"/%v", commandId)
   275  }
   276  
   277  func (c *Client4) GetEmojisRoute() string {
   278  	return fmt.Sprintf("/emoji")
   279  }
   280  
   281  func (c *Client4) GetEmojiRoute(emojiId string) string {
   282  	return fmt.Sprintf(c.GetEmojisRoute()+"/%v", emojiId)
   283  }
   284  
   285  func (c *Client4) GetEmojiByNameRoute(name string) string {
   286  	return fmt.Sprintf(c.GetEmojisRoute()+"/name/%v", name)
   287  }
   288  
   289  func (c *Client4) GetReactionsRoute() string {
   290  	return fmt.Sprintf("/reactions")
   291  }
   292  
   293  func (c *Client4) GetOAuthAppsRoute() string {
   294  	return fmt.Sprintf("/oauth/apps")
   295  }
   296  
   297  func (c *Client4) GetOAuthAppRoute(appId string) string {
   298  	return fmt.Sprintf("/oauth/apps/%v", appId)
   299  }
   300  
   301  func (c *Client4) GetOpenGraphRoute() string {
   302  	return fmt.Sprintf("/opengraph")
   303  }
   304  
   305  func (c *Client4) GetJobsRoute() string {
   306  	return fmt.Sprintf("/jobs")
   307  }
   308  
   309  func (c *Client4) GetAnalyticsRoute() string {
   310  	return fmt.Sprintf("/analytics")
   311  }
   312  
   313  func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
   314  	return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
   315  }
   316  
   317  func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) {
   318  	return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "")
   319  }
   320  
   321  func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) {
   322  	return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "")
   323  }
   324  
   325  func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) {
   326  	return c.DoApiRequest(http.MethodDelete, c.ApiUrl+url, "", "")
   327  }
   328  
   329  func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) {
   330  	rq, _ := http.NewRequest(method, url, strings.NewReader(data))
   331  	rq.Close = true
   332  
   333  	if len(etag) > 0 {
   334  		rq.Header.Set(HEADER_ETAG_CLIENT, etag)
   335  	}
   336  
   337  	if len(c.AuthToken) > 0 {
   338  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   339  	}
   340  
   341  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
   342  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
   343  	} else if rp.StatusCode == 304 {
   344  		return rp, nil
   345  	} else if rp.StatusCode >= 300 {
   346  		defer closeBody(rp)
   347  		return rp, AppErrorFromJson(rp.Body)
   348  	} else {
   349  		return rp, nil
   350  	}
   351  }
   352  
   353  func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) {
   354  	rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
   355  	rq.Header.Set("Content-Type", contentType)
   356  	rq.Close = true
   357  
   358  	if len(c.AuthToken) > 0 {
   359  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   360  	}
   361  
   362  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
   363  		return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
   364  	} else {
   365  		defer closeBody(rp)
   366  
   367  		if rp.StatusCode >= 300 {
   368  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
   369  		} else {
   370  			return FileUploadResponseFromJson(rp.Body), BuildResponse(rp)
   371  		}
   372  	}
   373  }
   374  
   375  func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) {
   376  	rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
   377  	rq.Header.Set("Content-Type", contentType)
   378  	rq.Close = true
   379  
   380  	if len(c.AuthToken) > 0 {
   381  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   382  	}
   383  
   384  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
   385  		return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
   386  	} else {
   387  		defer closeBody(rp)
   388  
   389  		if rp.StatusCode >= 300 {
   390  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
   391  		} else {
   392  			return EmojiFromJson(rp.Body), BuildResponse(rp)
   393  		}
   394  	}
   395  }
   396  
   397  func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) {
   398  	rq, _ := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
   399  	rq.Header.Set("Content-Type", contentType)
   400  	rq.Close = true
   401  
   402  	if len(c.AuthToken) > 0 {
   403  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   404  	}
   405  
   406  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
   407  		return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
   408  	} else {
   409  		defer closeBody(rp)
   410  
   411  		if rp.StatusCode >= 300 {
   412  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
   413  		} else {
   414  			return MapFromJson(rp.Body), BuildResponse(rp)
   415  		}
   416  	}
   417  }
   418  
   419  // CheckStatusOK is a convenience function for checking the standard OK response
   420  // from the web service.
   421  func CheckStatusOK(r *http.Response) bool {
   422  	m := MapFromJson(r.Body)
   423  	defer closeBody(r)
   424  
   425  	if m != nil && m[STATUS] == STATUS_OK {
   426  		return true
   427  	}
   428  
   429  	return false
   430  }
   431  
   432  // Authentication Section
   433  
   434  // LoginById authenticates a user by user id and password.
   435  func (c *Client4) LoginById(id string, password string) (*User, *Response) {
   436  	m := make(map[string]string)
   437  	m["id"] = id
   438  	m["password"] = password
   439  	return c.login(m)
   440  }
   441  
   442  // Login authenticates a user by login id, which can be username, email or some sort
   443  // of SSO identifier based on server configuration, and a password.
   444  func (c *Client4) Login(loginId string, password string) (*User, *Response) {
   445  	m := make(map[string]string)
   446  	m["login_id"] = loginId
   447  	m["password"] = password
   448  	return c.login(m)
   449  }
   450  
   451  // LoginByLdap authenticates a user by LDAP id and password.
   452  func (c *Client4) LoginByLdap(loginId string, password string) (*User, *Response) {
   453  	m := make(map[string]string)
   454  	m["login_id"] = loginId
   455  	m["password"] = password
   456  	m["ldap_only"] = "true"
   457  	return c.login(m)
   458  }
   459  
   460  // LoginWithDevice authenticates a user by login id (username, email or some sort
   461  // of SSO identifier based on configuration), password and attaches a device id to
   462  // the session.
   463  func (c *Client4) LoginWithDevice(loginId string, password string, deviceId string) (*User, *Response) {
   464  	m := make(map[string]string)
   465  	m["login_id"] = loginId
   466  	m["password"] = password
   467  	m["device_id"] = deviceId
   468  	return c.login(m)
   469  }
   470  
   471  func (c *Client4) login(m map[string]string) (*User, *Response) {
   472  	if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
   473  		return nil, BuildErrorResponse(r, err)
   474  	} else {
   475  		c.AuthToken = r.Header.Get(HEADER_TOKEN)
   476  		c.AuthType = HEADER_BEARER
   477  		defer closeBody(r)
   478  		return UserFromJson(r.Body), BuildResponse(r)
   479  	}
   480  }
   481  
   482  // Logout terminates the current user's session.
   483  func (c *Client4) Logout() (bool, *Response) {
   484  	if r, err := c.DoApiPost("/users/logout", ""); err != nil {
   485  		return false, BuildErrorResponse(r, err)
   486  	} else {
   487  		c.AuthToken = ""
   488  		c.AuthType = HEADER_BEARER
   489  
   490  		defer closeBody(r)
   491  		return CheckStatusOK(r), BuildResponse(r)
   492  	}
   493  }
   494  
   495  // SwitchAccountType changes a user's login type from one type to another.
   496  func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) {
   497  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson()); err != nil {
   498  		return "", BuildErrorResponse(r, err)
   499  	} else {
   500  		defer closeBody(r)
   501  		return MapFromJson(r.Body)["follow_link"], BuildResponse(r)
   502  	}
   503  }
   504  
   505  // User Section
   506  
   507  // CreateUser creates a user in the system based on the provided user struct.
   508  func (c *Client4) CreateUser(user *User) (*User, *Response) {
   509  	if r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson()); err != nil {
   510  		return nil, BuildErrorResponse(r, err)
   511  	} else {
   512  		defer closeBody(r)
   513  		return UserFromJson(r.Body), BuildResponse(r)
   514  	}
   515  }
   516  
   517  // CreateUserWithHash creates a user in the system based on the provided user struct and hash created.
   518  func (c *Client4) CreateUserWithHash(user *User, hash, data string) (*User, *Response) {
   519  	var query string
   520  	if hash != "" && data != "" {
   521  		query = fmt.Sprintf("?d=%v&h=%v", url.QueryEscape(data), hash)
   522  	} else {
   523  		err := NewAppError("MissingHashOrData", "api.user.create_user.missing_hash_or_data.app_error", nil, "", http.StatusBadRequest)
   524  		return nil, &Response{StatusCode: err.StatusCode, Error: err}
   525  	}
   526  	if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil {
   527  		return nil, BuildErrorResponse(r, err)
   528  	} else {
   529  		defer closeBody(r)
   530  		return UserFromJson(r.Body), BuildResponse(r)
   531  	}
   532  }
   533  
   534  // CreateUserWithInviteId creates a user in the system based on the provided invited id.
   535  func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) {
   536  	var query string
   537  	if inviteId != "" {
   538  		query = fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId))
   539  	} else {
   540  		err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest)
   541  		return nil, &Response{StatusCode: err.StatusCode, Error: err}
   542  	}
   543  	if r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson()); err != nil {
   544  		return nil, BuildErrorResponse(r, err)
   545  	} else {
   546  		defer closeBody(r)
   547  		return UserFromJson(r.Body), BuildResponse(r)
   548  	}
   549  }
   550  
   551  // GetMe returns the logged in user.
   552  func (c *Client4) GetMe(etag string) (*User, *Response) {
   553  	if r, err := c.DoApiGet(c.GetUserRoute(ME), etag); err != nil {
   554  		return nil, BuildErrorResponse(r, err)
   555  	} else {
   556  		defer closeBody(r)
   557  		return UserFromJson(r.Body), BuildResponse(r)
   558  	}
   559  }
   560  
   561  // GetUser returns a user based on the provided user id string.
   562  func (c *Client4) GetUser(userId, etag string) (*User, *Response) {
   563  	if r, err := c.DoApiGet(c.GetUserRoute(userId), etag); err != nil {
   564  		return nil, BuildErrorResponse(r, err)
   565  	} else {
   566  		defer closeBody(r)
   567  		return UserFromJson(r.Body), BuildResponse(r)
   568  	}
   569  }
   570  
   571  // GetUserByUsername returns a user based on the provided user name string.
   572  func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) {
   573  	if r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag); err != nil {
   574  		return nil, BuildErrorResponse(r, err)
   575  	} else {
   576  		defer closeBody(r)
   577  		return UserFromJson(r.Body), BuildResponse(r)
   578  	}
   579  }
   580  
   581  // GetUserByEmail returns a user based on the provided user email string.
   582  func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) {
   583  	if r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag); err != nil {
   584  		return nil, BuildErrorResponse(r, err)
   585  	} else {
   586  		defer closeBody(r)
   587  		return UserFromJson(r.Body), BuildResponse(r)
   588  	}
   589  }
   590  
   591  // AutocompleteUsersInTeam returns the users on a team based on search term.
   592  func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, etag string) (*UserAutocomplete, *Response) {
   593  	query := fmt.Sprintf("?in_team=%v&name=%v", teamId, username)
   594  	if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil {
   595  		return nil, BuildErrorResponse(r, err)
   596  	} else {
   597  		defer closeBody(r)
   598  		return UserAutocompleteFromJson(r.Body), BuildResponse(r)
   599  	}
   600  }
   601  
   602  // AutocompleteUsersInChannel returns the users in a channel based on search term.
   603  func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, etag string) (*UserAutocomplete, *Response) {
   604  	query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v", teamId, channelId, username)
   605  	if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil {
   606  		return nil, BuildErrorResponse(r, err)
   607  	} else {
   608  		defer closeBody(r)
   609  		return UserAutocompleteFromJson(r.Body), BuildResponse(r)
   610  	}
   611  }
   612  
   613  // AutocompleteUsers returns the users in the system based on search term.
   614  func (c *Client4) AutocompleteUsers(username string, etag string) (*UserAutocomplete, *Response) {
   615  	query := fmt.Sprintf("?name=%v", username)
   616  	if r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag); err != nil {
   617  		return nil, BuildErrorResponse(r, err)
   618  	} else {
   619  		defer closeBody(r)
   620  		return UserAutocompleteFromJson(r.Body), BuildResponse(r)
   621  	}
   622  }
   623  
   624  // GetProfileImage gets user's profile image. Must be logged in or be a system administrator.
   625  func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) {
   626  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag); err != nil {
   627  		return nil, BuildErrorResponse(r, err)
   628  	} else {
   629  		defer closeBody(r)
   630  
   631  		if data, err := ioutil.ReadAll(r.Body); err != nil {
   632  			return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
   633  		} else {
   634  			return data, BuildResponse(r)
   635  		}
   636  	}
   637  }
   638  
   639  // GetUsers returns a page of users on the system. Page counting starts at 0.
   640  func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) {
   641  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
   642  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   643  		return nil, BuildErrorResponse(r, err)
   644  	} else {
   645  		defer closeBody(r)
   646  		return UserListFromJson(r.Body), BuildResponse(r)
   647  	}
   648  }
   649  
   650  // GetUsersInTeam returns a page of users on a team. Page counting starts at 0.
   651  func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   652  	query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   653  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   654  		return nil, BuildErrorResponse(r, err)
   655  	} else {
   656  		defer closeBody(r)
   657  		return UserListFromJson(r.Body), BuildResponse(r)
   658  	}
   659  }
   660  
   661  // GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0.
   662  func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   663  	query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   664  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   665  		return nil, BuildErrorResponse(r, err)
   666  	} else {
   667  		defer closeBody(r)
   668  		return UserListFromJson(r.Body), BuildResponse(r)
   669  	}
   670  }
   671  
   672  // GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0.
   673  func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   674  	query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   675  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   676  		return nil, BuildErrorResponse(r, err)
   677  	} else {
   678  		defer closeBody(r)
   679  		return UserListFromJson(r.Body), BuildResponse(r)
   680  	}
   681  }
   682  
   683  // GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0.
   684  func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   685  	query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   686  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   687  		return nil, BuildErrorResponse(r, err)
   688  	} else {
   689  		defer closeBody(r)
   690  		return UserListFromJson(r.Body), BuildResponse(r)
   691  	}
   692  }
   693  
   694  // GetUsersInChannel returns a page of users on a team. Page counting starts at 0.
   695  func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
   696  	query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage)
   697  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   698  		return nil, BuildErrorResponse(r, err)
   699  	} else {
   700  		defer closeBody(r)
   701  		return UserListFromJson(r.Body), BuildResponse(r)
   702  	}
   703  }
   704  
   705  // GetUsersNotInChannel returns a page of users on a team. Page counting starts at 0.
   706  func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) {
   707  	query := fmt.Sprintf("?in_team=%v&not_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage)
   708  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   709  		return nil, BuildErrorResponse(r, err)
   710  	} else {
   711  		defer closeBody(r)
   712  		return UserListFromJson(r.Body), BuildResponse(r)
   713  	}
   714  }
   715  
   716  // GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0.
   717  func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) {
   718  	query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage)
   719  	if r, err := c.DoApiGet(c.GetUsersRoute()+query, etag); err != nil {
   720  		return nil, BuildErrorResponse(r, err)
   721  	} else {
   722  		defer closeBody(r)
   723  		return UserListFromJson(r.Body), BuildResponse(r)
   724  	}
   725  }
   726  
   727  // GetUsersByIds returns a list of users based on the provided user ids.
   728  func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) {
   729  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds)); err != nil {
   730  		return nil, BuildErrorResponse(r, err)
   731  	} else {
   732  		defer closeBody(r)
   733  		return UserListFromJson(r.Body), BuildResponse(r)
   734  	}
   735  }
   736  
   737  // GetUsersByUsernames returns a list of users based on the provided usernames.
   738  func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) {
   739  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames)); err != nil {
   740  		return nil, BuildErrorResponse(r, err)
   741  	} else {
   742  		defer closeBody(r)
   743  		return UserListFromJson(r.Body), BuildResponse(r)
   744  	}
   745  }
   746  
   747  // SearchUsers returns a list of users based on some search criteria.
   748  func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) {
   749  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/search", search.ToJson()); err != nil {
   750  		return nil, BuildErrorResponse(r, err)
   751  	} else {
   752  		defer closeBody(r)
   753  		return UserListFromJson(r.Body), BuildResponse(r)
   754  	}
   755  }
   756  
   757  // UpdateUser updates a user in the system based on the provided user struct.
   758  func (c *Client4) UpdateUser(user *User) (*User, *Response) {
   759  	if r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson()); err != nil {
   760  		return nil, BuildErrorResponse(r, err)
   761  	} else {
   762  		defer closeBody(r)
   763  		return UserFromJson(r.Body), BuildResponse(r)
   764  	}
   765  }
   766  
   767  // PatchUser partially updates a user in the system. Any missing fields are not updated.
   768  func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) {
   769  	if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson()); err != nil {
   770  		return nil, BuildErrorResponse(r, err)
   771  	} else {
   772  		defer closeBody(r)
   773  		return UserFromJson(r.Body), BuildResponse(r)
   774  	}
   775  }
   776  
   777  // UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system.
   778  func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) {
   779  	if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson()); err != nil {
   780  		return nil, BuildErrorResponse(r, err)
   781  	} else {
   782  		defer closeBody(r)
   783  		return UserAuthFromJson(r.Body), BuildResponse(r)
   784  	}
   785  }
   786  
   787  // UpdateUserMfa activates multi-factor authentication for a user if activate
   788  // is true and a valid code is provided. If activate is false, then code is not
   789  // required and multi-factor authentication is disabled for the user.
   790  func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Response) {
   791  	requestBody := make(map[string]interface{})
   792  	requestBody["activate"] = activate
   793  	requestBody["code"] = code
   794  
   795  	if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody)); err != nil {
   796  		return false, BuildErrorResponse(r, err)
   797  	} else {
   798  		defer closeBody(r)
   799  		return CheckStatusOK(r), BuildResponse(r)
   800  	}
   801  }
   802  
   803  // CheckUserMfa checks whether a user has MFA active on their account or not based on the
   804  // provided login id.
   805  func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) {
   806  	requestBody := make(map[string]interface{})
   807  	requestBody["login_id"] = loginId
   808  
   809  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody)); err != nil {
   810  		return false, BuildErrorResponse(r, err)
   811  	} else {
   812  		defer closeBody(r)
   813  		data := StringInterfaceFromJson(r.Body)
   814  		if mfaRequired, ok := data["mfa_required"].(bool); !ok {
   815  			return false, BuildResponse(r)
   816  		} else {
   817  			return mfaRequired, BuildResponse(r)
   818  		}
   819  	}
   820  }
   821  
   822  // GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and
   823  // as a base64 encoded image QR code.
   824  func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) {
   825  	if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", ""); err != nil {
   826  		return nil, BuildErrorResponse(r, err)
   827  	} else {
   828  		defer closeBody(r)
   829  		return MfaSecretFromJson(r.Body), BuildResponse(r)
   830  	}
   831  }
   832  
   833  // UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator.
   834  func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) {
   835  	requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword}
   836  	if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody)); err != nil {
   837  		return false, BuildErrorResponse(r, err)
   838  	} else {
   839  		defer closeBody(r)
   840  		return CheckStatusOK(r), BuildResponse(r)
   841  	}
   842  }
   843  
   844  // UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles.
   845  func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) {
   846  	requestBody := map[string]string{"roles": roles}
   847  	if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody)); err != nil {
   848  		return false, BuildErrorResponse(r, err)
   849  	} else {
   850  		defer closeBody(r)
   851  		return CheckStatusOK(r), BuildResponse(r)
   852  	}
   853  }
   854  
   855  // UpdateUserActive updates status of a user whether active or not.
   856  func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) {
   857  	requestBody := make(map[string]interface{})
   858  	requestBody["active"] = active
   859  
   860  	if r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody)); err != nil {
   861  		return false, BuildErrorResponse(r, err)
   862  	} else {
   863  		defer closeBody(r)
   864  		return CheckStatusOK(r), BuildResponse(r)
   865  	}
   866  }
   867  
   868  // DeleteUser deactivates a user in the system based on the provided user id string.
   869  func (c *Client4) DeleteUser(userId string) (bool, *Response) {
   870  	if r, err := c.DoApiDelete(c.GetUserRoute(userId)); err != nil {
   871  		return false, BuildErrorResponse(r, err)
   872  	} else {
   873  		defer closeBody(r)
   874  		return CheckStatusOK(r), BuildResponse(r)
   875  	}
   876  }
   877  
   878  // SendPasswordResetEmail will send a link for password resetting to a user with the
   879  // provided email.
   880  func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) {
   881  	requestBody := map[string]string{"email": email}
   882  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody)); err != nil {
   883  		return false, BuildErrorResponse(r, err)
   884  	} else {
   885  		defer closeBody(r)
   886  		return CheckStatusOK(r), BuildResponse(r)
   887  	}
   888  }
   889  
   890  // ResetPassword uses a recovery code to update reset a user's password.
   891  func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) {
   892  	requestBody := map[string]string{"token": token, "new_password": newPassword}
   893  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody)); err != nil {
   894  		return false, BuildErrorResponse(r, err)
   895  	} else {
   896  		defer closeBody(r)
   897  		return CheckStatusOK(r), BuildResponse(r)
   898  	}
   899  }
   900  
   901  // GetSessions returns a list of sessions based on the provided user id string.
   902  func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) {
   903  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag); err != nil {
   904  		return nil, BuildErrorResponse(r, err)
   905  	} else {
   906  		defer closeBody(r)
   907  		return SessionsFromJson(r.Body), BuildResponse(r)
   908  	}
   909  }
   910  
   911  // RevokeSession revokes a user session based on the provided user id and session id strings.
   912  func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) {
   913  	requestBody := map[string]string{"session_id": sessionId}
   914  	if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody)); err != nil {
   915  		return false, BuildErrorResponse(r, err)
   916  	} else {
   917  		defer closeBody(r)
   918  		return CheckStatusOK(r), BuildResponse(r)
   919  	}
   920  }
   921  
   922  // RevokeAllSessions revokes all sessions for the provided user id string.
   923  func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) {
   924  	if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", ""); err != nil {
   925  		return false, BuildErrorResponse(r, err)
   926  	} else {
   927  		defer closeBody(r)
   928  		return CheckStatusOK(r), BuildResponse(r)
   929  	}
   930  }
   931  
   932  // AttachDeviceId attaches a mobile device ID to the current session.
   933  func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) {
   934  	requestBody := map[string]string{"device_id": deviceId}
   935  	if r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody)); err != nil {
   936  		return false, BuildErrorResponse(r, err)
   937  	} else {
   938  		defer closeBody(r)
   939  		return CheckStatusOK(r), BuildResponse(r)
   940  	}
   941  }
   942  
   943  // GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount
   944  // of unread messages and mentions the current user has for the teams it belongs to.
   945  // An optional team ID can be set to exclude that team from the results. Must be authenticated.
   946  func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) {
   947  	optional := ""
   948  	if teamIdToExclude != "" {
   949  		optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude))
   950  	}
   951  
   952  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, ""); err != nil {
   953  		return nil, BuildErrorResponse(r, err)
   954  	} else {
   955  		defer closeBody(r)
   956  		return TeamsUnreadFromJson(r.Body), BuildResponse(r)
   957  	}
   958  }
   959  
   960  // GetUserAudits returns a list of audit based on the provided user id string.
   961  func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) {
   962  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
   963  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag); err != nil {
   964  		return nil, BuildErrorResponse(r, err)
   965  	} else {
   966  		defer closeBody(r)
   967  		return AuditsFromJson(r.Body), BuildResponse(r)
   968  	}
   969  }
   970  
   971  // VerifyUserEmail will verify a user's email using the supplied token.
   972  func (c *Client4) VerifyUserEmail(token string) (bool, *Response) {
   973  	requestBody := map[string]string{"token": token}
   974  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody)); err != nil {
   975  		return false, BuildErrorResponse(r, err)
   976  	} else {
   977  		defer closeBody(r)
   978  		return CheckStatusOK(r), BuildResponse(r)
   979  	}
   980  }
   981  
   982  // SendVerificationEmail will send an email to the user with the provided email address, if
   983  // that user exists. The email will contain a link that can be used to verify the user's
   984  // email address.
   985  func (c *Client4) SendVerificationEmail(email string) (bool, *Response) {
   986  	requestBody := map[string]string{"email": email}
   987  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody)); err != nil {
   988  		return false, BuildErrorResponse(r, err)
   989  	} else {
   990  		defer closeBody(r)
   991  		return CheckStatusOK(r), BuildResponse(r)
   992  	}
   993  }
   994  
   995  // SetProfileImage sets profile image of the user
   996  func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) {
   997  	body := &bytes.Buffer{}
   998  	writer := multipart.NewWriter(body)
   999  
  1000  	if part, err := writer.CreateFormFile("image", "profile.png"); err != nil {
  1001  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1002  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1003  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1004  	}
  1005  
  1006  	if err := writer.Close(); err != nil {
  1007  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1008  	}
  1009  
  1010  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetUserRoute(userId)+"/image", bytes.NewReader(body.Bytes()))
  1011  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  1012  	rq.Close = true
  1013  
  1014  	if len(c.AuthToken) > 0 {
  1015  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  1016  	}
  1017  
  1018  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  1019  		// set to http.StatusForbidden(403)
  1020  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)}
  1021  	} else {
  1022  		defer closeBody(rp)
  1023  
  1024  		if rp.StatusCode >= 300 {
  1025  			return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  1026  		} else {
  1027  			return CheckStatusOK(rp), BuildResponse(rp)
  1028  		}
  1029  	}
  1030  }
  1031  
  1032  // CreateUserAccessToken will generate a user access token that can be used in place
  1033  // of a session token to access the REST API. Must have the 'create_user_access_token'
  1034  // permission and if generating for another user, must have the 'edit_other_users'
  1035  // permission. A non-blank description is required.
  1036  func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) {
  1037  	requestBody := map[string]string{"description": description}
  1038  	if r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody)); err != nil {
  1039  		return nil, BuildErrorResponse(r, err)
  1040  	} else {
  1041  		defer closeBody(r)
  1042  		return UserAccessTokenFromJson(r.Body), BuildResponse(r)
  1043  	}
  1044  }
  1045  
  1046  // GetUserAccessTokens will get a page of access tokens' id, description, is_active
  1047  // and the user_id in the system. The actual token will not be returned. Must have
  1048  // the 'manage_system' permission.
  1049  func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) {
  1050  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1051  	if r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, ""); err != nil {
  1052  		return nil, BuildErrorResponse(r, err)
  1053  	} else {
  1054  		defer closeBody(r)
  1055  		return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
  1056  	}
  1057  }
  1058  
  1059  // GetUserAccessToken will get a user access tokens' id, description, is_active
  1060  // and the user_id of the user it is for. The actual token will not be returned.
  1061  // Must have the 'read_user_access_token' permission and if getting for another
  1062  // user, must have the 'edit_other_users' permission.
  1063  func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) {
  1064  	if r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), ""); err != nil {
  1065  		return nil, BuildErrorResponse(r, err)
  1066  	} else {
  1067  		defer closeBody(r)
  1068  		return UserAccessTokenFromJson(r.Body), BuildResponse(r)
  1069  	}
  1070  }
  1071  
  1072  // GetUserAccessTokensForUser will get a paged list of user access tokens showing id,
  1073  // description and user_id for each. The actual tokens will not be returned. Must have
  1074  // the 'read_user_access_token' permission and if getting for another user, must have the
  1075  // 'edit_other_users' permission.
  1076  func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) {
  1077  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1078  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, ""); err != nil {
  1079  		return nil, BuildErrorResponse(r, err)
  1080  	} else {
  1081  		defer closeBody(r)
  1082  		return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
  1083  	}
  1084  }
  1085  
  1086  // RevokeUserAccessToken will revoke a user access token by id. Must have the
  1087  // 'revoke_user_access_token' permission and if revoking for another user, must have the
  1088  // 'edit_other_users' permission.
  1089  func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) {
  1090  	requestBody := map[string]string{"token_id": tokenId}
  1091  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody)); err != nil {
  1092  		return false, BuildErrorResponse(r, err)
  1093  	} else {
  1094  		defer closeBody(r)
  1095  		return CheckStatusOK(r), BuildResponse(r)
  1096  	}
  1097  }
  1098  
  1099  // SearchUserAccessTokens returns user access tokens matching the provided search term.
  1100  func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) {
  1101  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson()); err != nil {
  1102  		return nil, BuildErrorResponse(r, err)
  1103  	} else {
  1104  		defer closeBody(r)
  1105  		return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
  1106  	}
  1107  }
  1108  
  1109  // DisableUserAccessToken will disable a user access token by id. Must have the
  1110  // 'revoke_user_access_token' permission and if disabling for another user, must have the
  1111  // 'edit_other_users' permission.
  1112  func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) {
  1113  	requestBody := map[string]string{"token_id": tokenId}
  1114  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody)); err != nil {
  1115  		return false, BuildErrorResponse(r, err)
  1116  	} else {
  1117  		defer closeBody(r)
  1118  		return CheckStatusOK(r), BuildResponse(r)
  1119  	}
  1120  }
  1121  
  1122  // EnableUserAccessToken will enable a user access token by id. Must have the
  1123  // 'create_user_access_token' permission and if enabling for another user, must have the
  1124  // 'edit_other_users' permission.
  1125  func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) {
  1126  	requestBody := map[string]string{"token_id": tokenId}
  1127  	if r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody)); err != nil {
  1128  		return false, BuildErrorResponse(r, err)
  1129  	} else {
  1130  		defer closeBody(r)
  1131  		return CheckStatusOK(r), BuildResponse(r)
  1132  	}
  1133  }
  1134  
  1135  // Team Section
  1136  
  1137  // CreateTeam creates a team in the system based on the provided team struct.
  1138  func (c *Client4) CreateTeam(team *Team) (*Team, *Response) {
  1139  	if r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson()); err != nil {
  1140  		return nil, BuildErrorResponse(r, err)
  1141  	} else {
  1142  		defer closeBody(r)
  1143  		return TeamFromJson(r.Body), BuildResponse(r)
  1144  	}
  1145  }
  1146  
  1147  // GetTeam returns a team based on the provided team id string.
  1148  func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) {
  1149  	if r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag); err != nil {
  1150  		return nil, BuildErrorResponse(r, err)
  1151  	} else {
  1152  		defer closeBody(r)
  1153  		return TeamFromJson(r.Body), BuildResponse(r)
  1154  	}
  1155  }
  1156  
  1157  // GetAllTeams returns all teams based on permissions.
  1158  func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) {
  1159  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1160  	if r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag); err != nil {
  1161  		return nil, BuildErrorResponse(r, err)
  1162  	} else {
  1163  		defer closeBody(r)
  1164  		return TeamListFromJson(r.Body), BuildResponse(r)
  1165  	}
  1166  }
  1167  
  1168  // GetTeamByName returns a team based on the provided team name string.
  1169  func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) {
  1170  	if r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag); err != nil {
  1171  		return nil, BuildErrorResponse(r, err)
  1172  	} else {
  1173  		defer closeBody(r)
  1174  		return TeamFromJson(r.Body), BuildResponse(r)
  1175  	}
  1176  }
  1177  
  1178  // SearchTeams returns teams matching the provided search term.
  1179  func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) {
  1180  	if r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson()); err != nil {
  1181  		return nil, BuildErrorResponse(r, err)
  1182  	} else {
  1183  		defer closeBody(r)
  1184  		return TeamListFromJson(r.Body), BuildResponse(r)
  1185  	}
  1186  }
  1187  
  1188  // TeamExists returns true or false if the team exist or not.
  1189  func (c *Client4) TeamExists(name, etag string) (bool, *Response) {
  1190  	if r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag); err != nil {
  1191  		return false, BuildErrorResponse(r, err)
  1192  	} else {
  1193  		defer closeBody(r)
  1194  		return MapBoolFromJson(r.Body)["exists"], BuildResponse(r)
  1195  	}
  1196  }
  1197  
  1198  // GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user
  1199  // or be a system administrator.
  1200  func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) {
  1201  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag); err != nil {
  1202  		return nil, BuildErrorResponse(r, err)
  1203  	} else {
  1204  		defer closeBody(r)
  1205  		return TeamListFromJson(r.Body), BuildResponse(r)
  1206  	}
  1207  }
  1208  
  1209  // GetTeamMember returns a team member based on the provided team and user id strings.
  1210  func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) {
  1211  	if r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag); err != nil {
  1212  		return nil, BuildErrorResponse(r, err)
  1213  	} else {
  1214  		defer closeBody(r)
  1215  		return TeamMemberFromJson(r.Body), BuildResponse(r)
  1216  	}
  1217  }
  1218  
  1219  // UpdateTeamMemberRoles will update the roles on a team for a user.
  1220  func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) {
  1221  	requestBody := map[string]string{"roles": newRoles}
  1222  	if r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody)); err != nil {
  1223  		return false, BuildErrorResponse(r, err)
  1224  	} else {
  1225  		defer closeBody(r)
  1226  		return CheckStatusOK(r), BuildResponse(r)
  1227  	}
  1228  }
  1229  
  1230  // UpdateTeam will update a team.
  1231  func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) {
  1232  	if r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson()); err != nil {
  1233  		return nil, BuildErrorResponse(r, err)
  1234  	} else {
  1235  		defer closeBody(r)
  1236  		return TeamFromJson(r.Body), BuildResponse(r)
  1237  	}
  1238  }
  1239  
  1240  // PatchTeam partially updates a team. Any missing fields are not updated.
  1241  func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) {
  1242  	if r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson()); err != nil {
  1243  		return nil, BuildErrorResponse(r, err)
  1244  	} else {
  1245  		defer closeBody(r)
  1246  		return TeamFromJson(r.Body), BuildResponse(r)
  1247  	}
  1248  }
  1249  
  1250  // SoftDeleteTeam deletes the team softly (archive only, not permanent delete).
  1251  func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) {
  1252  	if r, err := c.DoApiDelete(c.GetTeamRoute(teamId)); err != nil {
  1253  		return false, BuildErrorResponse(r, err)
  1254  	} else {
  1255  		defer closeBody(r)
  1256  		return CheckStatusOK(r), BuildResponse(r)
  1257  	}
  1258  }
  1259  
  1260  // PermanentDeleteTeam deletes the team, should only be used when needed for
  1261  // compliance and the like
  1262  func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) {
  1263  	if r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true"); err != nil {
  1264  		return false, BuildErrorResponse(r, err)
  1265  	} else {
  1266  		defer closeBody(r)
  1267  		return CheckStatusOK(r), BuildResponse(r)
  1268  	}
  1269  }
  1270  
  1271  // GetTeamMembers returns team members based on the provided team id string.
  1272  func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) {
  1273  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1274  	if r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag); err != nil {
  1275  		return nil, BuildErrorResponse(r, err)
  1276  	} else {
  1277  		defer closeBody(r)
  1278  		return TeamMembersFromJson(r.Body), BuildResponse(r)
  1279  	}
  1280  }
  1281  
  1282  // GetTeamMembersForUser returns the team members for a user.
  1283  func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) {
  1284  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag); err != nil {
  1285  		return nil, BuildErrorResponse(r, err)
  1286  	} else {
  1287  		defer closeBody(r)
  1288  		return TeamMembersFromJson(r.Body), BuildResponse(r)
  1289  	}
  1290  }
  1291  
  1292  // GetTeamMembersByIds will return an array of team members based on the
  1293  // team id and a list of user ids provided. Must be authenticated.
  1294  func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) {
  1295  	if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil {
  1296  		return nil, BuildErrorResponse(r, err)
  1297  	} else {
  1298  		defer closeBody(r)
  1299  		return TeamMembersFromJson(r.Body), BuildResponse(r)
  1300  	}
  1301  }
  1302  
  1303  // AddTeamMember adds user to a team and return a team member.
  1304  func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) {
  1305  	member := &TeamMember{TeamId: teamId, UserId: userId}
  1306  
  1307  	if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson()); err != nil {
  1308  		return nil, BuildErrorResponse(r, err)
  1309  	} else {
  1310  		defer closeBody(r)
  1311  		return TeamMemberFromJson(r.Body), BuildResponse(r)
  1312  	}
  1313  }
  1314  
  1315  // AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id
  1316  // or an invite hash/data pair.
  1317  func (c *Client4) AddTeamMemberFromInvite(hash, dataToHash, inviteId string) (*TeamMember, *Response) {
  1318  	var query string
  1319  
  1320  	if inviteId != "" {
  1321  		query += fmt.Sprintf("?invite_id=%v", inviteId)
  1322  	}
  1323  
  1324  	if hash != "" && dataToHash != "" {
  1325  		query += fmt.Sprintf("?hash=%v&data=%v", hash, dataToHash)
  1326  	}
  1327  
  1328  	if r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, ""); err != nil {
  1329  		return nil, BuildErrorResponse(r, err)
  1330  	} else {
  1331  		defer closeBody(r)
  1332  		return TeamMemberFromJson(r.Body), BuildResponse(r)
  1333  	}
  1334  }
  1335  
  1336  // AddTeamMembers adds a number of users to a team and returns the team members.
  1337  func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember, *Response) {
  1338  	var members []*TeamMember
  1339  	for _, userId := range userIds {
  1340  		member := &TeamMember{TeamId: teamId, UserId: userId}
  1341  		members = append(members, member)
  1342  	}
  1343  
  1344  	if r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members)); err != nil {
  1345  		return nil, BuildErrorResponse(r, err)
  1346  	} else {
  1347  		defer closeBody(r)
  1348  		return TeamMembersFromJson(r.Body), BuildResponse(r)
  1349  	}
  1350  }
  1351  
  1352  // RemoveTeamMember will remove a user from a team.
  1353  func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
  1354  	if r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId)); err != nil {
  1355  		return false, BuildErrorResponse(r, err)
  1356  	} else {
  1357  		defer closeBody(r)
  1358  		return CheckStatusOK(r), BuildResponse(r)
  1359  	}
  1360  }
  1361  
  1362  // GetTeamStats returns a team stats based on the team id string.
  1363  // Must be authenticated.
  1364  func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) {
  1365  	if r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag); err != nil {
  1366  		return nil, BuildErrorResponse(r, err)
  1367  	} else {
  1368  		defer closeBody(r)
  1369  		return TeamStatsFromJson(r.Body), BuildResponse(r)
  1370  	}
  1371  }
  1372  
  1373  // GetTeamUnread will return a TeamUnread object that contains the amount of
  1374  // unread messages and mentions the user has for the specified team.
  1375  // Must be authenticated.
  1376  func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) {
  1377  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", ""); err != nil {
  1378  		return nil, BuildErrorResponse(r, err)
  1379  	} else {
  1380  		defer closeBody(r)
  1381  		return TeamUnreadFromJson(r.Body), BuildResponse(r)
  1382  	}
  1383  }
  1384  
  1385  // ImportTeam will import an exported team from other app into a existing team.
  1386  func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, teamId string) (map[string]string, *Response) {
  1387  	body := &bytes.Buffer{}
  1388  	writer := multipart.NewWriter(body)
  1389  
  1390  	if part, err := writer.CreateFormFile("file", filename); err != nil {
  1391  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1392  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1393  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1394  	}
  1395  
  1396  	if part, err := writer.CreateFormField("filesize"); err != nil {
  1397  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
  1398  	} else if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil {
  1399  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
  1400  	}
  1401  
  1402  	if part, err := writer.CreateFormField("importFrom"); err != nil {
  1403  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
  1404  	} else if _, err = io.Copy(part, strings.NewReader(importFrom)); err != nil {
  1405  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
  1406  	}
  1407  
  1408  	if err := writer.Close(); err != nil {
  1409  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1410  	}
  1411  
  1412  	return c.DoUploadImportTeam(c.GetTeamImportRoute(teamId), body.Bytes(), writer.FormDataContentType())
  1413  }
  1414  
  1415  // InviteUsersToTeam invite users by email to the team.
  1416  func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) {
  1417  	if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails)); err != nil {
  1418  		return false, BuildErrorResponse(r, err)
  1419  	} else {
  1420  		defer closeBody(r)
  1421  		return CheckStatusOK(r), BuildResponse(r)
  1422  	}
  1423  }
  1424  
  1425  // GetTeamInviteInfo returns a team object from an invite id containing sanitized information.
  1426  func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) {
  1427  	if r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, ""); err != nil {
  1428  		return nil, BuildErrorResponse(r, err)
  1429  	} else {
  1430  		defer closeBody(r)
  1431  		return TeamFromJson(r.Body), BuildResponse(r)
  1432  	}
  1433  }
  1434  
  1435  // Channel Section
  1436  
  1437  // CreateChannel creates a channel based on the provided channel struct.
  1438  func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) {
  1439  	if r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson()); err != nil {
  1440  		return nil, BuildErrorResponse(r, err)
  1441  	} else {
  1442  		defer closeBody(r)
  1443  		return ChannelFromJson(r.Body), BuildResponse(r)
  1444  	}
  1445  }
  1446  
  1447  // UpdateChannel update a channel based on the provided channel struct.
  1448  func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) {
  1449  	if r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson()); err != nil {
  1450  		return nil, BuildErrorResponse(r, err)
  1451  	} else {
  1452  		defer closeBody(r)
  1453  		return ChannelFromJson(r.Body), BuildResponse(r)
  1454  	}
  1455  }
  1456  
  1457  // PatchChannel partially updates a channel. Any missing fields are not updated.
  1458  func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) {
  1459  	if r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson()); err != nil {
  1460  		return nil, BuildErrorResponse(r, err)
  1461  	} else {
  1462  		defer closeBody(r)
  1463  		return ChannelFromJson(r.Body), BuildResponse(r)
  1464  	}
  1465  }
  1466  
  1467  // RestoreChannel restores a previously deleted channel. Any missing fields are not updated.
  1468  func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) {
  1469  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", ""); err != nil {
  1470  		return nil, BuildErrorResponse(r, err)
  1471  	} else {
  1472  		defer closeBody(r)
  1473  		return ChannelFromJson(r.Body), BuildResponse(r)
  1474  	}
  1475  }
  1476  
  1477  // CreateDirectChannel creates a direct message channel based on the two user
  1478  // ids provided.
  1479  func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) {
  1480  	requestBody := []string{userId1, userId2}
  1481  	if r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody)); err != nil {
  1482  		return nil, BuildErrorResponse(r, err)
  1483  	} else {
  1484  		defer closeBody(r)
  1485  		return ChannelFromJson(r.Body), BuildResponse(r)
  1486  	}
  1487  }
  1488  
  1489  // CreateGroupChannel creates a group message channel based on userIds provided
  1490  func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) {
  1491  	if r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds)); err != nil {
  1492  		return nil, BuildErrorResponse(r, err)
  1493  	} else {
  1494  		defer closeBody(r)
  1495  		return ChannelFromJson(r.Body), BuildResponse(r)
  1496  	}
  1497  }
  1498  
  1499  // GetChannel returns a channel based on the provided channel id string.
  1500  func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) {
  1501  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag); err != nil {
  1502  		return nil, BuildErrorResponse(r, err)
  1503  	} else {
  1504  		defer closeBody(r)
  1505  		return ChannelFromJson(r.Body), BuildResponse(r)
  1506  	}
  1507  }
  1508  
  1509  // GetChannelStats returns statistics for a channel.
  1510  func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) {
  1511  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag); err != nil {
  1512  		return nil, BuildErrorResponse(r, err)
  1513  	} else {
  1514  		defer closeBody(r)
  1515  		return ChannelStatsFromJson(r.Body), BuildResponse(r)
  1516  	}
  1517  }
  1518  
  1519  // GetPinnedPosts gets a list of pinned posts.
  1520  func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) {
  1521  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag); err != nil {
  1522  		return nil, BuildErrorResponse(r, err)
  1523  	} else {
  1524  		defer closeBody(r)
  1525  		return PostListFromJson(r.Body), BuildResponse(r)
  1526  	}
  1527  }
  1528  
  1529  // GetPublicChannelsForTeam returns a list of public channels based on the provided team id string.
  1530  func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
  1531  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1532  	if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil {
  1533  		return nil, BuildErrorResponse(r, err)
  1534  	} else {
  1535  		defer closeBody(r)
  1536  		return ChannelSliceFromJson(r.Body), BuildResponse(r)
  1537  	}
  1538  }
  1539  
  1540  // GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string.
  1541  func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
  1542  	query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage)
  1543  	if r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag); err != nil {
  1544  		return nil, BuildErrorResponse(r, err)
  1545  	} else {
  1546  		defer closeBody(r)
  1547  		return ChannelSliceFromJson(r.Body), BuildResponse(r)
  1548  	}
  1549  }
  1550  
  1551  // GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string
  1552  func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) {
  1553  	if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds)); err != nil {
  1554  		return nil, BuildErrorResponse(r, err)
  1555  	} else {
  1556  		defer closeBody(r)
  1557  		return ChannelSliceFromJson(r.Body), BuildResponse(r)
  1558  	}
  1559  }
  1560  
  1561  // GetChannelsForTeamForUser returns a list channels of on a team for a user.
  1562  func (c *Client4) GetChannelsForTeamForUser(teamId, userId, etag string) ([]*Channel, *Response) {
  1563  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag); err != nil {
  1564  		return nil, BuildErrorResponse(r, err)
  1565  	} else {
  1566  		defer closeBody(r)
  1567  		return ChannelSliceFromJson(r.Body), BuildResponse(r)
  1568  	}
  1569  }
  1570  
  1571  // SearchChannels returns the channels on a team matching the provided search term.
  1572  func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
  1573  	if r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson()); err != nil {
  1574  		return nil, BuildErrorResponse(r, err)
  1575  	} else {
  1576  		defer closeBody(r)
  1577  		return ChannelSliceFromJson(r.Body), BuildResponse(r)
  1578  	}
  1579  }
  1580  
  1581  // DeleteChannel deletes channel based on the provided channel id string.
  1582  func (c *Client4) DeleteChannel(channelId string) (bool, *Response) {
  1583  	if r, err := c.DoApiDelete(c.GetChannelRoute(channelId)); err != nil {
  1584  		return false, BuildErrorResponse(r, err)
  1585  	} else {
  1586  		defer closeBody(r)
  1587  		return CheckStatusOK(r), BuildResponse(r)
  1588  	}
  1589  }
  1590  
  1591  // GetChannelByName returns a channel based on the provided channel name and team id strings.
  1592  func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) {
  1593  	if r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag); err != nil {
  1594  		return nil, BuildErrorResponse(r, err)
  1595  	} else {
  1596  		defer closeBody(r)
  1597  		return ChannelFromJson(r.Body), BuildResponse(r)
  1598  	}
  1599  }
  1600  
  1601  // GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings.
  1602  func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) {
  1603  	if r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag); err != nil {
  1604  		return nil, BuildErrorResponse(r, err)
  1605  	} else {
  1606  		defer closeBody(r)
  1607  		return ChannelFromJson(r.Body), BuildResponse(r)
  1608  	}
  1609  }
  1610  
  1611  // GetChannelMembers gets a page of channel members.
  1612  func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) {
  1613  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1614  	if r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag); err != nil {
  1615  		return nil, BuildErrorResponse(r, err)
  1616  	} else {
  1617  		defer closeBody(r)
  1618  		return ChannelMembersFromJson(r.Body), BuildResponse(r)
  1619  	}
  1620  }
  1621  
  1622  // GetChannelMembersByIds gets the channel members in a channel for a list of user ids.
  1623  func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) {
  1624  	if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds)); err != nil {
  1625  		return nil, BuildErrorResponse(r, err)
  1626  	} else {
  1627  		defer closeBody(r)
  1628  		return ChannelMembersFromJson(r.Body), BuildResponse(r)
  1629  
  1630  	}
  1631  }
  1632  
  1633  // GetChannelMember gets a channel member.
  1634  func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) {
  1635  	if r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag); err != nil {
  1636  		return nil, BuildErrorResponse(r, err)
  1637  	} else {
  1638  		defer closeBody(r)
  1639  		return ChannelMemberFromJson(r.Body), BuildResponse(r)
  1640  	}
  1641  }
  1642  
  1643  // GetChannelMembersForUser gets all the channel members for a user on a team.
  1644  func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) {
  1645  	if r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag); err != nil {
  1646  		return nil, BuildErrorResponse(r, err)
  1647  	} else {
  1648  		defer closeBody(r)
  1649  		return ChannelMembersFromJson(r.Body), BuildResponse(r)
  1650  	}
  1651  }
  1652  
  1653  // ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user.
  1654  func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) {
  1655  	url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId)
  1656  	if r, err := c.DoApiPost(url, view.ToJson()); err != nil {
  1657  		return nil, BuildErrorResponse(r, err)
  1658  	} else {
  1659  		defer closeBody(r)
  1660  		return ChannelViewResponseFromJson(r.Body), BuildResponse(r)
  1661  	}
  1662  }
  1663  
  1664  // GetChannelUnread will return a ChannelUnread object that contains the number of
  1665  // unread messages and mentions for a user.
  1666  func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) {
  1667  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", ""); err != nil {
  1668  		return nil, BuildErrorResponse(r, err)
  1669  	} else {
  1670  		defer closeBody(r)
  1671  		return ChannelUnreadFromJson(r.Body), BuildResponse(r)
  1672  	}
  1673  }
  1674  
  1675  // UpdateChannelRoles will update the roles on a channel for a user.
  1676  func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) {
  1677  	requestBody := map[string]string{"roles": roles}
  1678  	if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody)); err != nil {
  1679  		return false, BuildErrorResponse(r, err)
  1680  	} else {
  1681  		defer closeBody(r)
  1682  		return CheckStatusOK(r), BuildResponse(r)
  1683  	}
  1684  }
  1685  
  1686  // UpdateChannelNotifyProps will update the notification properties on a channel for a user.
  1687  func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) {
  1688  	if r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props)); err != nil {
  1689  		return false, BuildErrorResponse(r, err)
  1690  	} else {
  1691  		defer closeBody(r)
  1692  		return CheckStatusOK(r), BuildResponse(r)
  1693  	}
  1694  }
  1695  
  1696  // AddChannelMember adds user to channel and return a channel member.
  1697  func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) {
  1698  	requestBody := map[string]string{"user_id": userId}
  1699  	if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil {
  1700  		return nil, BuildErrorResponse(r, err)
  1701  	} else {
  1702  		defer closeBody(r)
  1703  		return ChannelMemberFromJson(r.Body), BuildResponse(r)
  1704  	}
  1705  }
  1706  
  1707  // AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId.
  1708  func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) {
  1709  	requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId}
  1710  	if r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody)); err != nil {
  1711  		return nil, BuildErrorResponse(r, err)
  1712  	} else {
  1713  		defer closeBody(r)
  1714  		return ChannelMemberFromJson(r.Body), BuildResponse(r)
  1715  	}
  1716  }
  1717  
  1718  // RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel.
  1719  func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) {
  1720  	if r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId)); err != nil {
  1721  		return false, BuildErrorResponse(r, err)
  1722  	} else {
  1723  		defer closeBody(r)
  1724  		return CheckStatusOK(r), BuildResponse(r)
  1725  	}
  1726  }
  1727  
  1728  // Post Section
  1729  
  1730  // CreatePost creates a post based on the provided post struct.
  1731  func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
  1732  	if r, err := c.DoApiPost(c.GetPostsRoute(), post.ToJson()); err != nil {
  1733  		return nil, BuildErrorResponse(r, err)
  1734  	} else {
  1735  		defer closeBody(r)
  1736  		return PostFromJson(r.Body), BuildResponse(r)
  1737  	}
  1738  }
  1739  
  1740  // UpdatePost updates a post based on the provided post struct.
  1741  func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) {
  1742  	if r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToJson()); err != nil {
  1743  		return nil, BuildErrorResponse(r, err)
  1744  	} else {
  1745  		defer closeBody(r)
  1746  		return PostFromJson(r.Body), BuildResponse(r)
  1747  	}
  1748  }
  1749  
  1750  // PatchPost partially updates a post. Any missing fields are not updated.
  1751  func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) {
  1752  	if r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson()); err != nil {
  1753  		return nil, BuildErrorResponse(r, err)
  1754  	} else {
  1755  		defer closeBody(r)
  1756  		return PostFromJson(r.Body), BuildResponse(r)
  1757  	}
  1758  }
  1759  
  1760  // PinPost pin a post based on provided post id string.
  1761  func (c *Client4) PinPost(postId string) (bool, *Response) {
  1762  	if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", ""); err != nil {
  1763  		return false, BuildErrorResponse(r, err)
  1764  	} else {
  1765  		defer closeBody(r)
  1766  		return CheckStatusOK(r), BuildResponse(r)
  1767  	}
  1768  }
  1769  
  1770  // UnpinPost unpin a post based on provided post id string.
  1771  func (c *Client4) UnpinPost(postId string) (bool, *Response) {
  1772  	if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", ""); err != nil {
  1773  		return false, BuildErrorResponse(r, err)
  1774  	} else {
  1775  		defer closeBody(r)
  1776  		return CheckStatusOK(r), BuildResponse(r)
  1777  	}
  1778  }
  1779  
  1780  // GetPost gets a single post.
  1781  func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) {
  1782  	if r, err := c.DoApiGet(c.GetPostRoute(postId), etag); err != nil {
  1783  		return nil, BuildErrorResponse(r, err)
  1784  	} else {
  1785  		defer closeBody(r)
  1786  		return PostFromJson(r.Body), BuildResponse(r)
  1787  	}
  1788  }
  1789  
  1790  // DeletePost deletes a post from the provided post id string.
  1791  func (c *Client4) DeletePost(postId string) (bool, *Response) {
  1792  	if r, err := c.DoApiDelete(c.GetPostRoute(postId)); err != nil {
  1793  		return false, BuildErrorResponse(r, err)
  1794  	} else {
  1795  		defer closeBody(r)
  1796  		return CheckStatusOK(r), BuildResponse(r)
  1797  	}
  1798  }
  1799  
  1800  // GetPostThread gets a post with all the other posts in the same thread.
  1801  func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) {
  1802  	if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag); err != nil {
  1803  		return nil, BuildErrorResponse(r, err)
  1804  	} else {
  1805  		defer closeBody(r)
  1806  		return PostListFromJson(r.Body), BuildResponse(r)
  1807  	}
  1808  }
  1809  
  1810  // GetPostsForChannel gets a page of posts with an array for ordering for a channel.
  1811  func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) {
  1812  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1813  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
  1814  		return nil, BuildErrorResponse(r, err)
  1815  	} else {
  1816  		defer closeBody(r)
  1817  		return PostListFromJson(r.Body), BuildResponse(r)
  1818  	}
  1819  }
  1820  
  1821  // GetFlaggedPostsForUser returns flagged posts of a user based on user id string.
  1822  func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) {
  1823  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1824  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil {
  1825  		return nil, BuildErrorResponse(r, err)
  1826  	} else {
  1827  		defer closeBody(r)
  1828  		return PostListFromJson(r.Body), BuildResponse(r)
  1829  	}
  1830  }
  1831  
  1832  // GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string.
  1833  func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, page int, perPage int) (*PostList, *Response) {
  1834  	if len(teamId) == 0 || len(teamId) != 26 {
  1835  		return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInTeam", "model.client.get_flagged_posts_in_team.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
  1836  	}
  1837  
  1838  	query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage)
  1839  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil {
  1840  		return nil, BuildErrorResponse(r, err)
  1841  	} else {
  1842  		defer closeBody(r)
  1843  		return PostListFromJson(r.Body), BuildResponse(r)
  1844  	}
  1845  }
  1846  
  1847  // GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string.
  1848  func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId string, page int, perPage int) (*PostList, *Response) {
  1849  	if len(channelId) == 0 || len(channelId) != 26 {
  1850  		return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInChannel", "model.client.get_flagged_posts_in_channel.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
  1851  	}
  1852  
  1853  	query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage)
  1854  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, ""); err != nil {
  1855  		return nil, BuildErrorResponse(r, err)
  1856  	} else {
  1857  		defer closeBody(r)
  1858  		return PostListFromJson(r.Body), BuildResponse(r)
  1859  	}
  1860  }
  1861  
  1862  // GetPostsSince gets posts created after a specified time as Unix time in milliseconds.
  1863  func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) {
  1864  	query := fmt.Sprintf("?since=%v", time)
  1865  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, ""); err != nil {
  1866  		return nil, BuildErrorResponse(r, err)
  1867  	} else {
  1868  		defer closeBody(r)
  1869  		return PostListFromJson(r.Body), BuildResponse(r)
  1870  	}
  1871  }
  1872  
  1873  // GetPostsAfter gets a page of posts that were posted after the post provided.
  1874  func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
  1875  	query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId)
  1876  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
  1877  		return nil, BuildErrorResponse(r, err)
  1878  	} else {
  1879  		defer closeBody(r)
  1880  		return PostListFromJson(r.Body), BuildResponse(r)
  1881  	}
  1882  }
  1883  
  1884  // GetPostsBefore gets a page of posts that were posted before the post provided.
  1885  func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
  1886  	query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId)
  1887  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag); err != nil {
  1888  		return nil, BuildErrorResponse(r, err)
  1889  	} else {
  1890  		defer closeBody(r)
  1891  		return PostListFromJson(r.Body), BuildResponse(r)
  1892  	}
  1893  }
  1894  
  1895  // SearchPosts returns any posts with matching terms string.
  1896  func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*PostList, *Response) {
  1897  	requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch}
  1898  	if r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody)); err != nil {
  1899  		return nil, BuildErrorResponse(r, err)
  1900  	} else {
  1901  		defer closeBody(r)
  1902  		return PostListFromJson(r.Body), BuildResponse(r)
  1903  	}
  1904  }
  1905  
  1906  // DoPostAction performs a post action.
  1907  func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) {
  1908  	if r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, ""); err != nil {
  1909  		return false, BuildErrorResponse(r, err)
  1910  	} else {
  1911  		defer closeBody(r)
  1912  		return CheckStatusOK(r), BuildResponse(r)
  1913  	}
  1914  }
  1915  
  1916  // File Section
  1917  
  1918  // UploadFile will upload a file to a channel, to be later attached to a post.
  1919  func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
  1920  	body := &bytes.Buffer{}
  1921  	writer := multipart.NewWriter(body)
  1922  
  1923  	if part, err := writer.CreateFormFile("files", filename); err != nil {
  1924  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1925  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1926  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1927  	}
  1928  
  1929  	if part, err := writer.CreateFormField("channel_id"); err != nil {
  1930  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
  1931  	} else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
  1932  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
  1933  	}
  1934  
  1935  	if err := writer.Close(); err != nil {
  1936  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1937  	}
  1938  
  1939  	return c.DoUploadFile(c.GetFilesRoute(), body.Bytes(), writer.FormDataContentType())
  1940  }
  1941  
  1942  // GetFile gets the bytes for a file by id.
  1943  func (c *Client4) GetFile(fileId string) ([]byte, *Response) {
  1944  	if r, err := c.DoApiGet(c.GetFileRoute(fileId), ""); err != nil {
  1945  		return nil, BuildErrorResponse(r, err)
  1946  	} else {
  1947  		defer closeBody(r)
  1948  
  1949  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1950  			return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1951  		} else {
  1952  			return data, BuildResponse(r)
  1953  		}
  1954  	}
  1955  }
  1956  
  1957  // DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it
  1958  func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) {
  1959  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), ""); err != nil {
  1960  		return nil, BuildErrorResponse(r, err)
  1961  	} else {
  1962  		defer closeBody(r)
  1963  
  1964  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1965  			return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1966  		} else {
  1967  			return data, BuildResponse(r)
  1968  		}
  1969  	}
  1970  }
  1971  
  1972  // GetFileThumbnail gets the bytes for a file by id.
  1973  func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) {
  1974  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", ""); err != nil {
  1975  		return nil, BuildErrorResponse(r, err)
  1976  	} else {
  1977  		defer closeBody(r)
  1978  
  1979  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1980  			return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1981  		} else {
  1982  			return data, BuildResponse(r)
  1983  		}
  1984  	}
  1985  }
  1986  
  1987  // DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it.
  1988  func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) {
  1989  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), ""); err != nil {
  1990  		return nil, BuildErrorResponse(r, err)
  1991  	} else {
  1992  		defer closeBody(r)
  1993  
  1994  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1995  			return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1996  		} else {
  1997  			return data, BuildResponse(r)
  1998  		}
  1999  	}
  2000  }
  2001  
  2002  // GetFileLink gets the public link of a file by id.
  2003  func (c *Client4) GetFileLink(fileId string) (string, *Response) {
  2004  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", ""); err != nil {
  2005  		return "", BuildErrorResponse(r, err)
  2006  	} else {
  2007  		defer closeBody(r)
  2008  
  2009  		return MapFromJson(r.Body)["link"], BuildResponse(r)
  2010  	}
  2011  }
  2012  
  2013  // GetFilePreview gets the bytes for a file by id.
  2014  func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) {
  2015  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", ""); err != nil {
  2016  		return nil, BuildErrorResponse(r, err)
  2017  	} else {
  2018  		defer closeBody(r)
  2019  
  2020  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  2021  			return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2022  		} else {
  2023  			return data, BuildResponse(r)
  2024  		}
  2025  	}
  2026  }
  2027  
  2028  // DownloadFilePreview gets the bytes for a file by id.
  2029  func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) {
  2030  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), ""); err != nil {
  2031  		return nil, BuildErrorResponse(r, err)
  2032  	} else {
  2033  		defer closeBody(r)
  2034  
  2035  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  2036  			return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2037  		} else {
  2038  			return data, BuildResponse(r)
  2039  		}
  2040  	}
  2041  }
  2042  
  2043  // GetFileInfo gets all the file info objects.
  2044  func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) {
  2045  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", ""); err != nil {
  2046  		return nil, BuildErrorResponse(r, err)
  2047  	} else {
  2048  		defer closeBody(r)
  2049  		return FileInfoFromJson(r.Body), BuildResponse(r)
  2050  	}
  2051  }
  2052  
  2053  // GetFileInfosForPost gets all the file info objects attached to a post.
  2054  func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) {
  2055  	if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag); err != nil {
  2056  		return nil, BuildErrorResponse(r, err)
  2057  	} else {
  2058  		defer closeBody(r)
  2059  		return FileInfosFromJson(r.Body), BuildResponse(r)
  2060  	}
  2061  }
  2062  
  2063  // General/System Section
  2064  
  2065  // GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above.
  2066  func (c *Client4) GetPing() (string, *Response) {
  2067  	if r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", ""); r != nil && r.StatusCode == 500 {
  2068  		defer r.Body.Close()
  2069  		return "unhealthy", BuildErrorResponse(r, err)
  2070  	} else if err != nil {
  2071  		return "", BuildErrorResponse(r, err)
  2072  	} else {
  2073  		defer closeBody(r)
  2074  		return MapFromJson(r.Body)["status"], BuildResponse(r)
  2075  	}
  2076  }
  2077  
  2078  // TestEmail will attempt to connect to the configured SMTP server.
  2079  func (c *Client4) TestEmail() (bool, *Response) {
  2080  	if r, err := c.DoApiPost(c.GetTestEmailRoute(), ""); err != nil {
  2081  		return false, BuildErrorResponse(r, err)
  2082  	} else {
  2083  		defer closeBody(r)
  2084  		return CheckStatusOK(r), BuildResponse(r)
  2085  	}
  2086  }
  2087  
  2088  // GetConfig will retrieve the server config with some sanitized items.
  2089  func (c *Client4) GetConfig() (*Config, *Response) {
  2090  	if r, err := c.DoApiGet(c.GetConfigRoute(), ""); err != nil {
  2091  		return nil, BuildErrorResponse(r, err)
  2092  	} else {
  2093  		defer closeBody(r)
  2094  		return ConfigFromJson(r.Body), BuildResponse(r)
  2095  	}
  2096  }
  2097  
  2098  // ReloadConfig will reload the server configuration.
  2099  func (c *Client4) ReloadConfig() (bool, *Response) {
  2100  	if r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", ""); err != nil {
  2101  		return false, BuildErrorResponse(r, err)
  2102  	} else {
  2103  		defer closeBody(r)
  2104  		return CheckStatusOK(r), BuildResponse(r)
  2105  	}
  2106  }
  2107  
  2108  // GetOldClientConfig will retrieve the parts of the server configuration needed by the
  2109  // client, formatted in the old format.
  2110  func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) {
  2111  	if r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag); err != nil {
  2112  		return nil, BuildErrorResponse(r, err)
  2113  	} else {
  2114  		defer closeBody(r)
  2115  		return MapFromJson(r.Body), BuildResponse(r)
  2116  	}
  2117  }
  2118  
  2119  // GetOldClientLicense will retrieve the parts of the server license needed by the
  2120  // client, formatted in the old format.
  2121  func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) {
  2122  	if r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag); err != nil {
  2123  		return nil, BuildErrorResponse(r, err)
  2124  	} else {
  2125  		defer closeBody(r)
  2126  		return MapFromJson(r.Body), BuildResponse(r)
  2127  	}
  2128  }
  2129  
  2130  // DatabaseRecycle will recycle the connections. Discard current connection and get new one.
  2131  func (c *Client4) DatabaseRecycle() (bool, *Response) {
  2132  	if r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", ""); err != nil {
  2133  		return false, BuildErrorResponse(r, err)
  2134  	} else {
  2135  		defer closeBody(r)
  2136  		return CheckStatusOK(r), BuildResponse(r)
  2137  	}
  2138  }
  2139  
  2140  // InvalidateCaches will purge the cache and can affect the performance while is cleaning.
  2141  func (c *Client4) InvalidateCaches() (bool, *Response) {
  2142  	if r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", ""); err != nil {
  2143  		return false, BuildErrorResponse(r, err)
  2144  	} else {
  2145  		defer closeBody(r)
  2146  		return CheckStatusOK(r), BuildResponse(r)
  2147  	}
  2148  }
  2149  
  2150  // UpdateConfig will update the server configuration.
  2151  func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) {
  2152  	if r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()); err != nil {
  2153  		return nil, BuildErrorResponse(r, err)
  2154  	} else {
  2155  		defer closeBody(r)
  2156  		return ConfigFromJson(r.Body), BuildResponse(r)
  2157  	}
  2158  }
  2159  
  2160  // UploadLicenseFile will add a license file to the system.
  2161  func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) {
  2162  	body := &bytes.Buffer{}
  2163  	writer := multipart.NewWriter(body)
  2164  
  2165  	if part, err := writer.CreateFormFile("license", "test-license.mattermost-license"); err != nil {
  2166  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2167  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2168  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2169  	}
  2170  
  2171  	if err := writer.Close(); err != nil {
  2172  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  2173  	}
  2174  
  2175  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetLicenseRoute(), bytes.NewReader(body.Bytes()))
  2176  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  2177  	rq.Close = true
  2178  
  2179  	if len(c.AuthToken) > 0 {
  2180  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  2181  	}
  2182  
  2183  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  2184  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  2185  	} else {
  2186  		defer closeBody(rp)
  2187  
  2188  		if rp.StatusCode >= 300 {
  2189  			return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2190  		} else {
  2191  			return CheckStatusOK(rp), BuildResponse(rp)
  2192  		}
  2193  	}
  2194  }
  2195  
  2196  // RemoveLicenseFile will remove the server license it exists. Note that this will
  2197  // disable all enterprise features.
  2198  func (c *Client4) RemoveLicenseFile() (bool, *Response) {
  2199  	if r, err := c.DoApiDelete(c.GetLicenseRoute()); err != nil {
  2200  		return false, BuildErrorResponse(r, err)
  2201  	} else {
  2202  		defer closeBody(r)
  2203  		return CheckStatusOK(r), BuildResponse(r)
  2204  	}
  2205  }
  2206  
  2207  // GetAnalyticsOld will retrieve analytics using the old format. New format is not
  2208  // available but the "/analytics" endpoint is reserved for it. The "name" argument is optional
  2209  // and defaults to "standard". The "teamId" argument is optional and will limit results
  2210  // to a specific team.
  2211  func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) {
  2212  	query := fmt.Sprintf("?name=%v&teamId=%v", name, teamId)
  2213  	if r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, ""); err != nil {
  2214  		return nil, BuildErrorResponse(r, err)
  2215  	} else {
  2216  		defer closeBody(r)
  2217  		return AnalyticsRowsFromJson(r.Body), BuildResponse(r)
  2218  	}
  2219  }
  2220  
  2221  // Webhooks Section
  2222  
  2223  // CreateIncomingWebhook creates an incoming webhook for a channel.
  2224  func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
  2225  	if r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()); err != nil {
  2226  		return nil, BuildErrorResponse(r, err)
  2227  	} else {
  2228  		defer closeBody(r)
  2229  		return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2230  	}
  2231  }
  2232  
  2233  // UpdateIncomingWebhook updates an incoming webhook for a channel.
  2234  func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
  2235  	if r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()); err != nil {
  2236  		return nil, BuildErrorResponse(r, err)
  2237  	} else {
  2238  		defer closeBody(r)
  2239  		return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2240  	}
  2241  }
  2242  
  2243  // GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0.
  2244  func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
  2245  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2246  	if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
  2247  		return nil, BuildErrorResponse(r, err)
  2248  	} else {
  2249  		defer closeBody(r)
  2250  		return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
  2251  	}
  2252  }
  2253  
  2254  // GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0.
  2255  func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
  2256  	query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
  2257  	if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
  2258  		return nil, BuildErrorResponse(r, err)
  2259  	} else {
  2260  		defer closeBody(r)
  2261  		return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
  2262  	}
  2263  }
  2264  
  2265  // GetIncomingWebhook returns an Incoming webhook given the hook ID
  2266  func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) {
  2267  	if r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag); err != nil {
  2268  		return nil, BuildErrorResponse(r, err)
  2269  	} else {
  2270  		defer closeBody(r)
  2271  		return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2272  	}
  2273  }
  2274  
  2275  // DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID
  2276  func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) {
  2277  	if r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)); err != nil {
  2278  		return false, BuildErrorResponse(r, err)
  2279  	} else {
  2280  		defer closeBody(r)
  2281  		return CheckStatusOK(r), BuildResponse(r)
  2282  	}
  2283  }
  2284  
  2285  // CreateOutgoingWebhook creates an outgoing webhook for a team or channel.
  2286  func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
  2287  	if r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()); err != nil {
  2288  		return nil, BuildErrorResponse(r, err)
  2289  	} else {
  2290  		defer closeBody(r)
  2291  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2292  	}
  2293  }
  2294  
  2295  // UpdateOutgoingWebhook creates an outgoing webhook for a team or channel.
  2296  func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
  2297  	if r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()); err != nil {
  2298  		return nil, BuildErrorResponse(r, err)
  2299  	} else {
  2300  		defer closeBody(r)
  2301  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2302  	}
  2303  }
  2304  
  2305  // GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0.
  2306  func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2307  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2308  	if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
  2309  		return nil, BuildErrorResponse(r, err)
  2310  	} else {
  2311  		defer closeBody(r)
  2312  		return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2313  	}
  2314  }
  2315  
  2316  // GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id.
  2317  func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) {
  2318  	if r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), ""); err != nil {
  2319  		return nil, BuildErrorResponse(r, err)
  2320  	} else {
  2321  		defer closeBody(r)
  2322  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2323  	}
  2324  }
  2325  
  2326  // GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0.
  2327  func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2328  	query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId)
  2329  	if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
  2330  		return nil, BuildErrorResponse(r, err)
  2331  	} else {
  2332  		defer closeBody(r)
  2333  		return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2334  	}
  2335  }
  2336  
  2337  // GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0.
  2338  func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2339  	query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
  2340  	if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
  2341  		return nil, BuildErrorResponse(r, err)
  2342  	} else {
  2343  		defer closeBody(r)
  2344  		return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2345  	}
  2346  }
  2347  
  2348  // RegenOutgoingHookToken regenerate the outgoing webhook token.
  2349  func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) {
  2350  	if r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", ""); err != nil {
  2351  		return nil, BuildErrorResponse(r, err)
  2352  	} else {
  2353  		defer closeBody(r)
  2354  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2355  	}
  2356  }
  2357  
  2358  // DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id.
  2359  func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) {
  2360  	if r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)); err != nil {
  2361  		return false, BuildErrorResponse(r, err)
  2362  	} else {
  2363  		defer closeBody(r)
  2364  		return CheckStatusOK(r), BuildResponse(r)
  2365  	}
  2366  }
  2367  
  2368  // Preferences Section
  2369  
  2370  // GetPreferences returns the user's preferences.
  2371  func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
  2372  	if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil {
  2373  		return nil, BuildErrorResponse(r, err)
  2374  	} else {
  2375  		preferences, _ := PreferencesFromJson(r.Body)
  2376  		defer closeBody(r)
  2377  		return preferences, BuildResponse(r)
  2378  	}
  2379  }
  2380  
  2381  // UpdatePreferences saves the user's preferences.
  2382  func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
  2383  	if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil {
  2384  		return false, BuildErrorResponse(r, err)
  2385  	} else {
  2386  		defer closeBody(r)
  2387  		return true, BuildResponse(r)
  2388  	}
  2389  }
  2390  
  2391  // DeletePreferences deletes the user's preferences.
  2392  func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
  2393  	if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil {
  2394  		return false, BuildErrorResponse(r, err)
  2395  	} else {
  2396  		defer closeBody(r)
  2397  		return true, BuildResponse(r)
  2398  	}
  2399  }
  2400  
  2401  // GetPreferencesByCategory returns the user's preferences from the provided category string.
  2402  func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) {
  2403  	url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category)
  2404  	if r, err := c.DoApiGet(url, ""); err != nil {
  2405  		return nil, BuildErrorResponse(r, err)
  2406  	} else {
  2407  		preferences, _ := PreferencesFromJson(r.Body)
  2408  		defer closeBody(r)
  2409  		return preferences, BuildResponse(r)
  2410  	}
  2411  }
  2412  
  2413  // GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string.
  2414  func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) {
  2415  	url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName)
  2416  	if r, err := c.DoApiGet(url, ""); err != nil {
  2417  		return nil, BuildErrorResponse(r, err)
  2418  	} else {
  2419  		defer closeBody(r)
  2420  		return PreferenceFromJson(r.Body), BuildResponse(r)
  2421  	}
  2422  }
  2423  
  2424  // SAML Section
  2425  
  2426  // GetSamlMetadata returns metadata for the SAML configuration.
  2427  func (c *Client4) GetSamlMetadata() (string, *Response) {
  2428  	if r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", ""); err != nil {
  2429  		return "", BuildErrorResponse(r, err)
  2430  	} else {
  2431  		defer closeBody(r)
  2432  		buf := new(bytes.Buffer)
  2433  		buf.ReadFrom(r.Body)
  2434  		return buf.String(), BuildResponse(r)
  2435  	}
  2436  }
  2437  
  2438  func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
  2439  	body := &bytes.Buffer{}
  2440  	writer := multipart.NewWriter(body)
  2441  
  2442  	if part, err := writer.CreateFormFile("certificate", filename); err != nil {
  2443  		return nil, nil, err
  2444  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2445  		return nil, nil, err
  2446  	}
  2447  
  2448  	if err := writer.Close(); err != nil {
  2449  		return nil, nil, err
  2450  	}
  2451  
  2452  	return body.Bytes(), writer, nil
  2453  }
  2454  
  2455  // UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
  2456  func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
  2457  	body, writer, err := samlFileToMultipart(data, filename)
  2458  	if err != nil {
  2459  		return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  2460  	}
  2461  
  2462  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/idp", body, writer.FormDataContentType())
  2463  	return resp.Error == nil, resp
  2464  }
  2465  
  2466  // UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
  2467  func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
  2468  	body, writer, err := samlFileToMultipart(data, filename)
  2469  	if err != nil {
  2470  		return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  2471  	}
  2472  
  2473  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/public", body, writer.FormDataContentType())
  2474  	return resp.Error == nil, resp
  2475  }
  2476  
  2477  // UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
  2478  func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
  2479  	body, writer, err := samlFileToMultipart(data, filename)
  2480  	if err != nil {
  2481  		return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  2482  	}
  2483  
  2484  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/private", body, writer.FormDataContentType())
  2485  	return resp.Error == nil, resp
  2486  }
  2487  
  2488  // DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  2489  func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) {
  2490  	if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp"); err != nil {
  2491  		return false, BuildErrorResponse(r, err)
  2492  	} else {
  2493  		defer closeBody(r)
  2494  		return CheckStatusOK(r), BuildResponse(r)
  2495  	}
  2496  }
  2497  
  2498  // DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  2499  func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) {
  2500  	if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public"); err != nil {
  2501  		return false, BuildErrorResponse(r, err)
  2502  	} else {
  2503  		defer closeBody(r)
  2504  		return CheckStatusOK(r), BuildResponse(r)
  2505  	}
  2506  }
  2507  
  2508  // DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  2509  func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) {
  2510  	if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private"); err != nil {
  2511  		return false, BuildErrorResponse(r, err)
  2512  	} else {
  2513  		defer closeBody(r)
  2514  		return CheckStatusOK(r), BuildResponse(r)
  2515  	}
  2516  }
  2517  
  2518  // GetSamlCertificateStatus returns metadata for the SAML configuration.
  2519  func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) {
  2520  	if r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", ""); err != nil {
  2521  		return nil, BuildErrorResponse(r, err)
  2522  	} else {
  2523  		defer closeBody(r)
  2524  		return SamlCertificateStatusFromJson(r.Body), BuildResponse(r)
  2525  	}
  2526  }
  2527  
  2528  // Compliance Section
  2529  
  2530  // CreateComplianceReport creates an incoming webhook for a channel.
  2531  func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) {
  2532  	if r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()); err != nil {
  2533  		return nil, BuildErrorResponse(r, err)
  2534  	} else {
  2535  		defer closeBody(r)
  2536  		return ComplianceFromJson(r.Body), BuildResponse(r)
  2537  	}
  2538  }
  2539  
  2540  // GetComplianceReports returns list of compliance reports.
  2541  func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) {
  2542  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2543  	if r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, ""); err != nil {
  2544  		return nil, BuildErrorResponse(r, err)
  2545  	} else {
  2546  		defer closeBody(r)
  2547  		return CompliancesFromJson(r.Body), BuildResponse(r)
  2548  	}
  2549  }
  2550  
  2551  // GetComplianceReport returns a compliance report.
  2552  func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) {
  2553  	if r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), ""); err != nil {
  2554  		return nil, BuildErrorResponse(r, err)
  2555  	} else {
  2556  		defer closeBody(r)
  2557  		return ComplianceFromJson(r.Body), BuildResponse(r)
  2558  	}
  2559  }
  2560  
  2561  // DownloadComplianceReport returns a full compliance report as a file.
  2562  func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) {
  2563  	var rq *http.Request
  2564  	rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil)
  2565  	rq.Close = true
  2566  
  2567  	if len(c.AuthToken) > 0 {
  2568  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  2569  	}
  2570  
  2571  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  2572  		return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  2573  	} else {
  2574  		defer closeBody(rp)
  2575  
  2576  		if rp.StatusCode >= 300 {
  2577  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2578  		} else if data, err := ioutil.ReadAll(rp.Body); err != nil {
  2579  			return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode))
  2580  		} else {
  2581  			return data, BuildResponse(rp)
  2582  		}
  2583  	}
  2584  }
  2585  
  2586  // Cluster Section
  2587  
  2588  // GetClusterStatus returns the status of all the configured cluster nodes.
  2589  func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) {
  2590  	if r, err := c.DoApiGet(c.GetClusterRoute()+"/status", ""); err != nil {
  2591  		return nil, BuildErrorResponse(r, err)
  2592  	} else {
  2593  		defer closeBody(r)
  2594  		return ClusterInfosFromJson(r.Body), BuildResponse(r)
  2595  	}
  2596  }
  2597  
  2598  // LDAP Section
  2599  
  2600  // SyncLdap will force a sync with the configured LDAP server.
  2601  func (c *Client4) SyncLdap() (bool, *Response) {
  2602  	if r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", ""); err != nil {
  2603  		return false, BuildErrorResponse(r, err)
  2604  	} else {
  2605  		defer closeBody(r)
  2606  		return CheckStatusOK(r), BuildResponse(r)
  2607  	}
  2608  }
  2609  
  2610  // TestLdap will attempt to connect to the configured LDAP server and return OK if configured
  2611  // correctly.
  2612  func (c *Client4) TestLdap() (bool, *Response) {
  2613  	if r, err := c.DoApiPost(c.GetLdapRoute()+"/test", ""); err != nil {
  2614  		return false, BuildErrorResponse(r, err)
  2615  	} else {
  2616  		defer closeBody(r)
  2617  		return CheckStatusOK(r), BuildResponse(r)
  2618  	}
  2619  }
  2620  
  2621  // Audits Section
  2622  
  2623  // GetAudits returns a list of audits for the whole system.
  2624  func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) {
  2625  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2626  	if r, err := c.DoApiGet("/audits"+query, etag); err != nil {
  2627  		return nil, BuildErrorResponse(r, err)
  2628  	} else {
  2629  		defer closeBody(r)
  2630  		return AuditsFromJson(r.Body), BuildResponse(r)
  2631  	}
  2632  }
  2633  
  2634  // Brand Section
  2635  
  2636  // GetBrandImage retrieves the previously uploaded brand image.
  2637  func (c *Client4) GetBrandImage() ([]byte, *Response) {
  2638  	if r, err := c.DoApiGet(c.GetBrandRoute()+"/image", ""); err != nil {
  2639  		return nil, BuildErrorResponse(r, err)
  2640  	} else {
  2641  		defer closeBody(r)
  2642  
  2643  		if r.StatusCode >= 300 {
  2644  			return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body))
  2645  		} else if data, err := ioutil.ReadAll(r.Body); err != nil {
  2646  			return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2647  		} else {
  2648  			return data, BuildResponse(r)
  2649  		}
  2650  	}
  2651  }
  2652  
  2653  // UploadBrandImage sets the brand image for the system.
  2654  func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) {
  2655  	body := &bytes.Buffer{}
  2656  	writer := multipart.NewWriter(body)
  2657  
  2658  	if part, err := writer.CreateFormFile("image", "brand.png"); err != nil {
  2659  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2660  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2661  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2662  	}
  2663  
  2664  	if err := writer.Close(); err != nil {
  2665  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  2666  	}
  2667  
  2668  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetBrandRoute()+"/image", bytes.NewReader(body.Bytes()))
  2669  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  2670  	rq.Close = true
  2671  
  2672  	if len(c.AuthToken) > 0 {
  2673  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  2674  	}
  2675  
  2676  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  2677  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  2678  	} else {
  2679  		defer closeBody(rp)
  2680  
  2681  		if rp.StatusCode >= 300 {
  2682  			return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2683  		} else {
  2684  			return CheckStatusOK(rp), BuildResponse(rp)
  2685  		}
  2686  	}
  2687  }
  2688  
  2689  // Logs Section
  2690  
  2691  // GetLogs page of logs as a string array.
  2692  func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) {
  2693  	query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage)
  2694  	if r, err := c.DoApiGet("/logs"+query, ""); err != nil {
  2695  		return nil, BuildErrorResponse(r, err)
  2696  	} else {
  2697  		defer closeBody(r)
  2698  		return ArrayFromJson(r.Body), BuildResponse(r)
  2699  	}
  2700  }
  2701  
  2702  // PostLog is a convenience Web Service call so clients can log messages into
  2703  // the server-side logs.  For example we typically log javascript error messages
  2704  // into the server-side.  It returns the log message if the logging was successful.
  2705  func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) {
  2706  	if r, err := c.DoApiPost("/logs", MapToJson(message)); err != nil {
  2707  		return nil, BuildErrorResponse(r, err)
  2708  	} else {
  2709  		defer closeBody(r)
  2710  		return MapFromJson(r.Body), BuildResponse(r)
  2711  	}
  2712  }
  2713  
  2714  // OAuth Section
  2715  
  2716  // CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  2717  func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
  2718  	if r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()); err != nil {
  2719  		return nil, BuildErrorResponse(r, err)
  2720  	} else {
  2721  		defer closeBody(r)
  2722  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2723  	}
  2724  }
  2725  
  2726  // UpdateOAuthApp
  2727  func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
  2728  	if r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()); err != nil {
  2729  		return nil, BuildErrorResponse(r, err)
  2730  	} else {
  2731  		defer closeBody(r)
  2732  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2733  	}
  2734  }
  2735  
  2736  // GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
  2737  func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) {
  2738  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2739  	if r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, ""); err != nil {
  2740  		return nil, BuildErrorResponse(r, err)
  2741  	} else {
  2742  		defer closeBody(r)
  2743  		return OAuthAppListFromJson(r.Body), BuildResponse(r)
  2744  	}
  2745  }
  2746  
  2747  // GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  2748  func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) {
  2749  	if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), ""); err != nil {
  2750  		return nil, BuildErrorResponse(r, err)
  2751  	} else {
  2752  		defer closeBody(r)
  2753  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2754  	}
  2755  }
  2756  
  2757  // GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  2758  func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) {
  2759  	if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", ""); err != nil {
  2760  		return nil, BuildErrorResponse(r, err)
  2761  	} else {
  2762  		defer closeBody(r)
  2763  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2764  	}
  2765  }
  2766  
  2767  // DeleteOAuthApp deletes a registered OAuth 2.0 client application.
  2768  func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) {
  2769  	if r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)); err != nil {
  2770  		return false, BuildErrorResponse(r, err)
  2771  	} else {
  2772  		defer closeBody(r)
  2773  		return CheckStatusOK(r), BuildResponse(r)
  2774  	}
  2775  }
  2776  
  2777  // RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application.
  2778  func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) {
  2779  	if r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", ""); err != nil {
  2780  		return nil, BuildErrorResponse(r, err)
  2781  	} else {
  2782  		defer closeBody(r)
  2783  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2784  	}
  2785  }
  2786  
  2787  // GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account.
  2788  func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) {
  2789  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2790  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, ""); err != nil {
  2791  		return nil, BuildErrorResponse(r, err)
  2792  	} else {
  2793  		defer closeBody(r)
  2794  		return OAuthAppListFromJson(r.Body), BuildResponse(r)
  2795  	}
  2796  }
  2797  
  2798  // AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow.
  2799  func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) {
  2800  	if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), ""); err != nil {
  2801  		return "", BuildErrorResponse(r, err)
  2802  	} else {
  2803  		defer closeBody(r)
  2804  		return MapFromJson(r.Body)["redirect"], BuildResponse(r)
  2805  	}
  2806  }
  2807  
  2808  // DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account.
  2809  func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) {
  2810  	requestData := map[string]string{"client_id": appId}
  2811  	if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), ""); err != nil {
  2812  		return false, BuildErrorResponse(r, err)
  2813  	} else {
  2814  		defer closeBody(r)
  2815  		return CheckStatusOK(r), BuildResponse(r)
  2816  	}
  2817  }
  2818  
  2819  // Elasticsearch Section
  2820  
  2821  // TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured
  2822  // correctly.
  2823  func (c *Client4) TestElasticsearch() (bool, *Response) {
  2824  	if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", ""); err != nil {
  2825  		return false, BuildErrorResponse(r, err)
  2826  	} else {
  2827  		defer closeBody(r)
  2828  		return CheckStatusOK(r), BuildResponse(r)
  2829  	}
  2830  }
  2831  
  2832  // PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes.
  2833  func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
  2834  	if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", ""); err != nil {
  2835  		return false, BuildErrorResponse(r, err)
  2836  	} else {
  2837  		defer closeBody(r)
  2838  		return CheckStatusOK(r), BuildResponse(r)
  2839  	}
  2840  }
  2841  
  2842  // Data Retention Section
  2843  
  2844  // GetDataRetentionPolicy will get the current server data retention policy details.
  2845  func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) {
  2846  	if r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", ""); err != nil {
  2847  		return nil, BuildErrorResponse(r, err)
  2848  	} else {
  2849  		defer closeBody(r)
  2850  		return DataRetentionPolicyFromJson(r.Body), BuildResponse(r)
  2851  	}
  2852  }
  2853  
  2854  // Commands Section
  2855  
  2856  // CreateCommand will create a new command if the user have the right permissions.
  2857  func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) {
  2858  	if r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()); err != nil {
  2859  		return nil, BuildErrorResponse(r, err)
  2860  	} else {
  2861  		defer closeBody(r)
  2862  		return CommandFromJson(r.Body), BuildResponse(r)
  2863  	}
  2864  }
  2865  
  2866  // UpdateCommand updates a command based on the provided Command struct
  2867  func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) {
  2868  	if r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()); err != nil {
  2869  		return nil, BuildErrorResponse(r, err)
  2870  	} else {
  2871  		defer closeBody(r)
  2872  		return CommandFromJson(r.Body), BuildResponse(r)
  2873  	}
  2874  }
  2875  
  2876  // DeleteCommand deletes a command based on the provided command id string
  2877  func (c *Client4) DeleteCommand(commandId string) (bool, *Response) {
  2878  	if r, err := c.DoApiDelete(c.GetCommandRoute(commandId)); err != nil {
  2879  		return false, BuildErrorResponse(r, err)
  2880  	} else {
  2881  		defer closeBody(r)
  2882  		return CheckStatusOK(r), BuildResponse(r)
  2883  	}
  2884  }
  2885  
  2886  // ListCommands will retrieve a list of commands available in the team.
  2887  func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) {
  2888  	query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly)
  2889  	if r, err := c.DoApiGet(c.GetCommandsRoute()+query, ""); err != nil {
  2890  		return nil, BuildErrorResponse(r, err)
  2891  	} else {
  2892  		defer closeBody(r)
  2893  		return CommandListFromJson(r.Body), BuildResponse(r)
  2894  	}
  2895  }
  2896  
  2897  // ExecuteCommand executes a given slash command.
  2898  func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) {
  2899  	commandArgs := &CommandArgs{
  2900  		ChannelId: channelId,
  2901  		Command:   command,
  2902  	}
  2903  	if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
  2904  		return nil, BuildErrorResponse(r, err)
  2905  	} else {
  2906  		defer closeBody(r)
  2907  		return CommandResponseFromJson(r.Body), BuildResponse(r)
  2908  	}
  2909  }
  2910  
  2911  // ExecuteCommand executes a given slash command against the specified team
  2912  // Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case
  2913  func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) {
  2914  	commandArgs := &CommandArgs{
  2915  		ChannelId: channelId,
  2916  		TeamId:    teamId,
  2917  		Command:   command,
  2918  	}
  2919  	if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
  2920  		return nil, BuildErrorResponse(r, err)
  2921  	} else {
  2922  		defer closeBody(r)
  2923  		return CommandResponseFromJson(r.Body), BuildResponse(r)
  2924  	}
  2925  }
  2926  
  2927  // ListCommands will retrieve a list of commands available in the team.
  2928  func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) {
  2929  	if r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), ""); err != nil {
  2930  		return nil, BuildErrorResponse(r, err)
  2931  	} else {
  2932  		defer closeBody(r)
  2933  		return CommandListFromJson(r.Body), BuildResponse(r)
  2934  	}
  2935  }
  2936  
  2937  // RegenCommandToken will create a new token if the user have the right permissions.
  2938  func (c *Client4) RegenCommandToken(commandId string) (string, *Response) {
  2939  	if r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", ""); err != nil {
  2940  		return "", BuildErrorResponse(r, err)
  2941  	} else {
  2942  		defer closeBody(r)
  2943  		return MapFromJson(r.Body)["token"], BuildResponse(r)
  2944  	}
  2945  }
  2946  
  2947  // Status Section
  2948  
  2949  // GetUserStatus returns a user based on the provided user id string.
  2950  func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) {
  2951  	if r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag); err != nil {
  2952  		return nil, BuildErrorResponse(r, err)
  2953  	} else {
  2954  		defer closeBody(r)
  2955  		return StatusFromJson(r.Body), BuildResponse(r)
  2956  	}
  2957  }
  2958  
  2959  // GetUsersStatusesByIds returns a list of users status based on the provided user ids.
  2960  func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) {
  2961  	if r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)); err != nil {
  2962  		return nil, BuildErrorResponse(r, err)
  2963  	} else {
  2964  		defer closeBody(r)
  2965  		return StatusListFromJson(r.Body), BuildResponse(r)
  2966  	}
  2967  }
  2968  
  2969  // UpdateUserStatus sets a user's status based on the provided user id string.
  2970  func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) {
  2971  	if r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()); err != nil {
  2972  		return nil, BuildErrorResponse(r, err)
  2973  	} else {
  2974  		defer closeBody(r)
  2975  		return StatusFromJson(r.Body), BuildResponse(r)
  2976  
  2977  	}
  2978  }
  2979  
  2980  // Webrtc Section
  2981  
  2982  // GetWebrtcToken returns a valid token, stun server and turn server with credentials to
  2983  // use with the Mattermost WebRTC service.
  2984  func (c *Client4) GetWebrtcToken() (*WebrtcInfoResponse, *Response) {
  2985  	if r, err := c.DoApiGet("/webrtc/token", ""); err != nil {
  2986  		return nil, BuildErrorResponse(r, err)
  2987  	} else {
  2988  		defer closeBody(r)
  2989  		return WebrtcInfoResponseFromJson(r.Body), BuildResponse(r)
  2990  	}
  2991  }
  2992  
  2993  // Emoji Section
  2994  
  2995  // CreateEmoji will save an emoji to the server if the current user has permission
  2996  // to do so. If successful, the provided emoji will be returned with its Id field
  2997  // filled in. Otherwise, an error will be returned.
  2998  func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *Response) {
  2999  	body := &bytes.Buffer{}
  3000  	writer := multipart.NewWriter(body)
  3001  
  3002  	if part, err := writer.CreateFormFile("image", filename); err != nil {
  3003  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
  3004  	} else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
  3005  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
  3006  	}
  3007  
  3008  	if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
  3009  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)}
  3010  	}
  3011  
  3012  	if err := writer.Close(); err != nil {
  3013  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)}
  3014  	}
  3015  
  3016  	return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType())
  3017  }
  3018  
  3019  // GetEmojiList returns a page of custom emoji on the system.
  3020  func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) {
  3021  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3022  	if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil {
  3023  		return nil, BuildErrorResponse(r, err)
  3024  	} else {
  3025  		defer closeBody(r)
  3026  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3027  	}
  3028  }
  3029  
  3030  // GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort
  3031  // parameter, blank for no sorting and "name" to sort by emoji names.
  3032  func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) {
  3033  	query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort)
  3034  	if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil {
  3035  		return nil, BuildErrorResponse(r, err)
  3036  	} else {
  3037  		defer closeBody(r)
  3038  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3039  	}
  3040  }
  3041  
  3042  // DeleteEmoji delete an custom emoji on the provided emoji id string.
  3043  func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) {
  3044  	if r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)); err != nil {
  3045  		return false, BuildErrorResponse(r, err)
  3046  	} else {
  3047  		defer closeBody(r)
  3048  		return CheckStatusOK(r), BuildResponse(r)
  3049  	}
  3050  }
  3051  
  3052  // GetEmoji returns a custom emoji based on the emojiId string.
  3053  func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) {
  3054  	if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), ""); err != nil {
  3055  		return nil, BuildErrorResponse(r, err)
  3056  	} else {
  3057  		defer closeBody(r)
  3058  		return EmojiFromJson(r.Body), BuildResponse(r)
  3059  	}
  3060  }
  3061  
  3062  // GetEmojiByName returns a custom emoji based on the name string.
  3063  func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) {
  3064  	if r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), ""); err != nil {
  3065  		return nil, BuildErrorResponse(r, err)
  3066  	} else {
  3067  		defer closeBody(r)
  3068  		return EmojiFromJson(r.Body), BuildResponse(r)
  3069  	}
  3070  }
  3071  
  3072  // GetEmojiImage returns the emoji image.
  3073  func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) {
  3074  	if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", ""); err != nil {
  3075  		return nil, BuildErrorResponse(r, err)
  3076  	} else {
  3077  		defer closeBody(r)
  3078  
  3079  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  3080  			return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  3081  		} else {
  3082  			return data, BuildResponse(r)
  3083  		}
  3084  	}
  3085  }
  3086  
  3087  // SearchEmoji returns a list of emoji matching some search criteria.
  3088  func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) {
  3089  	if r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()); err != nil {
  3090  		return nil, BuildErrorResponse(r, err)
  3091  	} else {
  3092  		defer closeBody(r)
  3093  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3094  	}
  3095  }
  3096  
  3097  // AutocompleteEmoji returns a list of emoji starting with or matching name.
  3098  func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) {
  3099  	query := fmt.Sprintf("?name=%v", name)
  3100  	if r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, ""); err != nil {
  3101  		return nil, BuildErrorResponse(r, err)
  3102  	} else {
  3103  		defer closeBody(r)
  3104  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3105  	}
  3106  }
  3107  
  3108  // Reaction Section
  3109  
  3110  // SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned.
  3111  func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) {
  3112  	if r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()); err != nil {
  3113  		return nil, BuildErrorResponse(r, err)
  3114  	} else {
  3115  		defer closeBody(r)
  3116  		return ReactionFromJson(r.Body), BuildResponse(r)
  3117  	}
  3118  }
  3119  
  3120  // GetReactions returns a list of reactions to a post.
  3121  func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) {
  3122  	if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", ""); err != nil {
  3123  		return nil, BuildErrorResponse(r, err)
  3124  	} else {
  3125  		defer closeBody(r)
  3126  		return ReactionsFromJson(r.Body), BuildResponse(r)
  3127  	}
  3128  }
  3129  
  3130  // DeleteReaction deletes reaction of a user in a post.
  3131  func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) {
  3132  	if r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)); err != nil {
  3133  		return false, BuildErrorResponse(r, err)
  3134  	} else {
  3135  		defer closeBody(r)
  3136  		return CheckStatusOK(r), BuildResponse(r)
  3137  	}
  3138  }
  3139  
  3140  // Open Graph Metadata Section
  3141  
  3142  // OpenGraph return the open graph metadata for a particular url if the site have the metadata
  3143  func (c *Client4) OpenGraph(url string) (map[string]string, *Response) {
  3144  	requestBody := make(map[string]string)
  3145  	requestBody["url"] = url
  3146  
  3147  	if r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)); err != nil {
  3148  		return nil, BuildErrorResponse(r, err)
  3149  	} else {
  3150  		defer closeBody(r)
  3151  		return MapFromJson(r.Body), BuildResponse(r)
  3152  	}
  3153  }
  3154  
  3155  // Jobs Section
  3156  
  3157  // GetJob gets a single job.
  3158  func (c *Client4) GetJob(id string) (*Job, *Response) {
  3159  	if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), ""); err != nil {
  3160  		return nil, BuildErrorResponse(r, err)
  3161  	} else {
  3162  		defer closeBody(r)
  3163  		return JobFromJson(r.Body), BuildResponse(r)
  3164  	}
  3165  }
  3166  
  3167  // Get all jobs, sorted with the job that was created most recently first.
  3168  func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) {
  3169  	if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), ""); err != nil {
  3170  		return nil, BuildErrorResponse(r, err)
  3171  	} else {
  3172  		defer closeBody(r)
  3173  		return JobsFromJson(r.Body), BuildResponse(r)
  3174  	}
  3175  }
  3176  
  3177  // GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first.
  3178  func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) {
  3179  	if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), ""); err != nil {
  3180  		return nil, BuildErrorResponse(r, err)
  3181  	} else {
  3182  		defer closeBody(r)
  3183  		return JobsFromJson(r.Body), BuildResponse(r)
  3184  	}
  3185  }
  3186  
  3187  // CreateJob creates a job based on the provided job struct.
  3188  func (c *Client4) CreateJob(job *Job) (*Job, *Response) {
  3189  	if r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()); err != nil {
  3190  		return nil, BuildErrorResponse(r, err)
  3191  	} else {
  3192  		defer closeBody(r)
  3193  		return JobFromJson(r.Body), BuildResponse(r)
  3194  	}
  3195  }
  3196  
  3197  // CancelJob requests the cancellation of the job with the provided Id.
  3198  func (c *Client4) CancelJob(jobId string) (bool, *Response) {
  3199  	if r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), ""); err != nil {
  3200  		return false, BuildErrorResponse(r, err)
  3201  	} else {
  3202  		defer closeBody(r)
  3203  		return CheckStatusOK(r), BuildResponse(r)
  3204  	}
  3205  }
  3206  
  3207  // Plugin Section
  3208  
  3209  // UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin.
  3210  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3211  func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
  3212  	body := new(bytes.Buffer)
  3213  	writer := multipart.NewWriter(body)
  3214  
  3215  	if part, err := writer.CreateFormFile("plugin", "plugin.tar.gz"); err != nil {
  3216  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  3217  	} else if _, err = io.Copy(part, file); err != nil {
  3218  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  3219  	}
  3220  
  3221  	if err := writer.Close(); err != nil {
  3222  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  3223  	}
  3224  
  3225  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body)
  3226  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  3227  	rq.Close = true
  3228  
  3229  	if len(c.AuthToken) > 0 {
  3230  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  3231  	}
  3232  
  3233  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  3234  		return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0))
  3235  	} else {
  3236  		defer closeBody(rp)
  3237  
  3238  		if rp.StatusCode >= 300 {
  3239  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  3240  		} else {
  3241  			return ManifestFromJson(rp.Body), BuildResponse(rp)
  3242  		}
  3243  	}
  3244  }
  3245  
  3246  // GetPlugins will return a list of plugin manifests for currently active plugins.
  3247  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3248  func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
  3249  	if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil {
  3250  		return nil, BuildErrorResponse(r, err)
  3251  	} else {
  3252  		defer closeBody(r)
  3253  		return PluginsResponseFromJson(r.Body), BuildResponse(r)
  3254  	}
  3255  }
  3256  
  3257  // RemovePlugin will deactivate and delete a plugin.
  3258  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3259  func (c *Client4) RemovePlugin(id string) (bool, *Response) {
  3260  	if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil {
  3261  		return false, BuildErrorResponse(r, err)
  3262  	} else {
  3263  		defer closeBody(r)
  3264  		return CheckStatusOK(r), BuildResponse(r)
  3265  	}
  3266  }
  3267  
  3268  // GetWebappPlugins will return a list of plugins that the webapp should download.
  3269  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3270  func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
  3271  	if r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", ""); err != nil {
  3272  		return nil, BuildErrorResponse(r, err)
  3273  	} else {
  3274  		defer closeBody(r)
  3275  		return ManifestListFromJson(r.Body), BuildResponse(r)
  3276  	}
  3277  }
  3278  
  3279  // ActivatePlugin will activate an plugin installed.
  3280  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3281  func (c *Client4) ActivatePlugin(id string) (bool, *Response) {
  3282  	if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/activate", ""); err != nil {
  3283  		return false, BuildErrorResponse(r, err)
  3284  	} else {
  3285  		defer closeBody(r)
  3286  		return CheckStatusOK(r), BuildResponse(r)
  3287  	}
  3288  }
  3289  
  3290  // DeactivatePlugin will deactivate an active plugin.
  3291  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3292  func (c *Client4) DeactivatePlugin(id string) (bool, *Response) {
  3293  	if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/deactivate", ""); err != nil {
  3294  		return false, BuildErrorResponse(r, err)
  3295  	} else {
  3296  		defer closeBody(r)
  3297  		return CheckStatusOK(r), BuildResponse(r)
  3298  	}
  3299  }