github.com/wgh-/mattermost-server@v4.8.0-rc2+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.ToUnsanitizedJson()); 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.ToUnsanitizedJson()); 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 using a multipart request, to be later attached to a post.
  1919  // This method is functionally equivalent to Client4.UploadFileAsRequestBody.
  1920  func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
  1921  	body := &bytes.Buffer{}
  1922  	writer := multipart.NewWriter(body)
  1923  
  1924  	if part, err := writer.CreateFormFile("files", filename); err != nil {
  1925  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1926  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1927  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1928  	}
  1929  
  1930  	if part, err := writer.CreateFormField("channel_id"); err != nil {
  1931  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
  1932  	} else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
  1933  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
  1934  	}
  1935  
  1936  	if err := writer.Close(); err != nil {
  1937  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1938  	}
  1939  
  1940  	return c.DoUploadFile(c.GetFilesRoute(), body.Bytes(), writer.FormDataContentType())
  1941  }
  1942  
  1943  // UploadFileAsRequestBody will upload a file to a channel as the body of a request, to be later attached
  1944  // to a post. This method is functionally equivalent to Client4.UploadFile.
  1945  func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
  1946  	return c.DoUploadFile(c.GetFilesRoute()+fmt.Sprintf("?channel_id=%v&filename=%v", url.QueryEscape(channelId), url.QueryEscape(filename)), data, http.DetectContentType(data))
  1947  }
  1948  
  1949  // GetFile gets the bytes for a file by id.
  1950  func (c *Client4) GetFile(fileId string) ([]byte, *Response) {
  1951  	if r, err := c.DoApiGet(c.GetFileRoute(fileId), ""); err != nil {
  1952  		return nil, BuildErrorResponse(r, err)
  1953  	} else {
  1954  		defer closeBody(r)
  1955  
  1956  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1957  			return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1958  		} else {
  1959  			return data, BuildResponse(r)
  1960  		}
  1961  	}
  1962  }
  1963  
  1964  // DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it
  1965  func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) {
  1966  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), ""); err != nil {
  1967  		return nil, BuildErrorResponse(r, err)
  1968  	} else {
  1969  		defer closeBody(r)
  1970  
  1971  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1972  			return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1973  		} else {
  1974  			return data, BuildResponse(r)
  1975  		}
  1976  	}
  1977  }
  1978  
  1979  // GetFileThumbnail gets the bytes for a file by id.
  1980  func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) {
  1981  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", ""); err != nil {
  1982  		return nil, BuildErrorResponse(r, err)
  1983  	} else {
  1984  		defer closeBody(r)
  1985  
  1986  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  1987  			return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  1988  		} else {
  1989  			return data, BuildResponse(r)
  1990  		}
  1991  	}
  1992  }
  1993  
  1994  // DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it.
  1995  func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) {
  1996  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), ""); err != nil {
  1997  		return nil, BuildErrorResponse(r, err)
  1998  	} else {
  1999  		defer closeBody(r)
  2000  
  2001  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  2002  			return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2003  		} else {
  2004  			return data, BuildResponse(r)
  2005  		}
  2006  	}
  2007  }
  2008  
  2009  // GetFileLink gets the public link of a file by id.
  2010  func (c *Client4) GetFileLink(fileId string) (string, *Response) {
  2011  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", ""); err != nil {
  2012  		return "", BuildErrorResponse(r, err)
  2013  	} else {
  2014  		defer closeBody(r)
  2015  
  2016  		return MapFromJson(r.Body)["link"], BuildResponse(r)
  2017  	}
  2018  }
  2019  
  2020  // GetFilePreview gets the bytes for a file by id.
  2021  func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) {
  2022  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", ""); err != nil {
  2023  		return nil, BuildErrorResponse(r, err)
  2024  	} else {
  2025  		defer closeBody(r)
  2026  
  2027  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  2028  			return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2029  		} else {
  2030  			return data, BuildResponse(r)
  2031  		}
  2032  	}
  2033  }
  2034  
  2035  // DownloadFilePreview gets the bytes for a file by id.
  2036  func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) {
  2037  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), ""); err != nil {
  2038  		return nil, BuildErrorResponse(r, err)
  2039  	} else {
  2040  		defer closeBody(r)
  2041  
  2042  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  2043  			return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2044  		} else {
  2045  			return data, BuildResponse(r)
  2046  		}
  2047  	}
  2048  }
  2049  
  2050  // GetFileInfo gets all the file info objects.
  2051  func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) {
  2052  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", ""); err != nil {
  2053  		return nil, BuildErrorResponse(r, err)
  2054  	} else {
  2055  		defer closeBody(r)
  2056  		return FileInfoFromJson(r.Body), BuildResponse(r)
  2057  	}
  2058  }
  2059  
  2060  // GetFileInfosForPost gets all the file info objects attached to a post.
  2061  func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) {
  2062  	if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag); err != nil {
  2063  		return nil, BuildErrorResponse(r, err)
  2064  	} else {
  2065  		defer closeBody(r)
  2066  		return FileInfosFromJson(r.Body), BuildResponse(r)
  2067  	}
  2068  }
  2069  
  2070  // General/System Section
  2071  
  2072  // GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above.
  2073  func (c *Client4) GetPing() (string, *Response) {
  2074  	if r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", ""); r != nil && r.StatusCode == 500 {
  2075  		defer r.Body.Close()
  2076  		return "unhealthy", BuildErrorResponse(r, err)
  2077  	} else if err != nil {
  2078  		return "", BuildErrorResponse(r, err)
  2079  	} else {
  2080  		defer closeBody(r)
  2081  		return MapFromJson(r.Body)["status"], BuildResponse(r)
  2082  	}
  2083  }
  2084  
  2085  // TestEmail will attempt to connect to the configured SMTP server.
  2086  func (c *Client4) TestEmail() (bool, *Response) {
  2087  	if r, err := c.DoApiPost(c.GetTestEmailRoute(), ""); err != nil {
  2088  		return false, BuildErrorResponse(r, err)
  2089  	} else {
  2090  		defer closeBody(r)
  2091  		return CheckStatusOK(r), BuildResponse(r)
  2092  	}
  2093  }
  2094  
  2095  // GetConfig will retrieve the server config with some sanitized items.
  2096  func (c *Client4) GetConfig() (*Config, *Response) {
  2097  	if r, err := c.DoApiGet(c.GetConfigRoute(), ""); err != nil {
  2098  		return nil, BuildErrorResponse(r, err)
  2099  	} else {
  2100  		defer closeBody(r)
  2101  		return ConfigFromJson(r.Body), BuildResponse(r)
  2102  	}
  2103  }
  2104  
  2105  // ReloadConfig will reload the server configuration.
  2106  func (c *Client4) ReloadConfig() (bool, *Response) {
  2107  	if r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", ""); err != nil {
  2108  		return false, BuildErrorResponse(r, err)
  2109  	} else {
  2110  		defer closeBody(r)
  2111  		return CheckStatusOK(r), BuildResponse(r)
  2112  	}
  2113  }
  2114  
  2115  // GetOldClientConfig will retrieve the parts of the server configuration needed by the
  2116  // client, formatted in the old format.
  2117  func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) {
  2118  	if r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag); err != nil {
  2119  		return nil, BuildErrorResponse(r, err)
  2120  	} else {
  2121  		defer closeBody(r)
  2122  		return MapFromJson(r.Body), BuildResponse(r)
  2123  	}
  2124  }
  2125  
  2126  // GetOldClientLicense will retrieve the parts of the server license needed by the
  2127  // client, formatted in the old format.
  2128  func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) {
  2129  	if r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag); err != nil {
  2130  		return nil, BuildErrorResponse(r, err)
  2131  	} else {
  2132  		defer closeBody(r)
  2133  		return MapFromJson(r.Body), BuildResponse(r)
  2134  	}
  2135  }
  2136  
  2137  // DatabaseRecycle will recycle the connections. Discard current connection and get new one.
  2138  func (c *Client4) DatabaseRecycle() (bool, *Response) {
  2139  	if r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", ""); err != nil {
  2140  		return false, BuildErrorResponse(r, err)
  2141  	} else {
  2142  		defer closeBody(r)
  2143  		return CheckStatusOK(r), BuildResponse(r)
  2144  	}
  2145  }
  2146  
  2147  // InvalidateCaches will purge the cache and can affect the performance while is cleaning.
  2148  func (c *Client4) InvalidateCaches() (bool, *Response) {
  2149  	if r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", ""); err != nil {
  2150  		return false, BuildErrorResponse(r, err)
  2151  	} else {
  2152  		defer closeBody(r)
  2153  		return CheckStatusOK(r), BuildResponse(r)
  2154  	}
  2155  }
  2156  
  2157  // UpdateConfig will update the server configuration.
  2158  func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) {
  2159  	if r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson()); err != nil {
  2160  		return nil, BuildErrorResponse(r, err)
  2161  	} else {
  2162  		defer closeBody(r)
  2163  		return ConfigFromJson(r.Body), BuildResponse(r)
  2164  	}
  2165  }
  2166  
  2167  // UploadLicenseFile will add a license file to the system.
  2168  func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) {
  2169  	body := &bytes.Buffer{}
  2170  	writer := multipart.NewWriter(body)
  2171  
  2172  	if part, err := writer.CreateFormFile("license", "test-license.mattermost-license"); err != nil {
  2173  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2174  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2175  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2176  	}
  2177  
  2178  	if err := writer.Close(); err != nil {
  2179  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  2180  	}
  2181  
  2182  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetLicenseRoute(), bytes.NewReader(body.Bytes()))
  2183  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  2184  	rq.Close = true
  2185  
  2186  	if len(c.AuthToken) > 0 {
  2187  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  2188  	}
  2189  
  2190  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  2191  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  2192  	} else {
  2193  		defer closeBody(rp)
  2194  
  2195  		if rp.StatusCode >= 300 {
  2196  			return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2197  		} else {
  2198  			return CheckStatusOK(rp), BuildResponse(rp)
  2199  		}
  2200  	}
  2201  }
  2202  
  2203  // RemoveLicenseFile will remove the server license it exists. Note that this will
  2204  // disable all enterprise features.
  2205  func (c *Client4) RemoveLicenseFile() (bool, *Response) {
  2206  	if r, err := c.DoApiDelete(c.GetLicenseRoute()); err != nil {
  2207  		return false, BuildErrorResponse(r, err)
  2208  	} else {
  2209  		defer closeBody(r)
  2210  		return CheckStatusOK(r), BuildResponse(r)
  2211  	}
  2212  }
  2213  
  2214  // GetAnalyticsOld will retrieve analytics using the old format. New format is not
  2215  // available but the "/analytics" endpoint is reserved for it. The "name" argument is optional
  2216  // and defaults to "standard". The "teamId" argument is optional and will limit results
  2217  // to a specific team.
  2218  func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) {
  2219  	query := fmt.Sprintf("?name=%v&teamId=%v", name, teamId)
  2220  	if r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, ""); err != nil {
  2221  		return nil, BuildErrorResponse(r, err)
  2222  	} else {
  2223  		defer closeBody(r)
  2224  		return AnalyticsRowsFromJson(r.Body), BuildResponse(r)
  2225  	}
  2226  }
  2227  
  2228  // Webhooks Section
  2229  
  2230  // CreateIncomingWebhook creates an incoming webhook for a channel.
  2231  func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
  2232  	if r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson()); err != nil {
  2233  		return nil, BuildErrorResponse(r, err)
  2234  	} else {
  2235  		defer closeBody(r)
  2236  		return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2237  	}
  2238  }
  2239  
  2240  // UpdateIncomingWebhook updates an incoming webhook for a channel.
  2241  func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
  2242  	if r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson()); err != nil {
  2243  		return nil, BuildErrorResponse(r, err)
  2244  	} else {
  2245  		defer closeBody(r)
  2246  		return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2247  	}
  2248  }
  2249  
  2250  // GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0.
  2251  func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
  2252  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2253  	if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
  2254  		return nil, BuildErrorResponse(r, err)
  2255  	} else {
  2256  		defer closeBody(r)
  2257  		return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
  2258  	}
  2259  }
  2260  
  2261  // GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0.
  2262  func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
  2263  	query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
  2264  	if r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag); err != nil {
  2265  		return nil, BuildErrorResponse(r, err)
  2266  	} else {
  2267  		defer closeBody(r)
  2268  		return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
  2269  	}
  2270  }
  2271  
  2272  // GetIncomingWebhook returns an Incoming webhook given the hook ID
  2273  func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) {
  2274  	if r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag); err != nil {
  2275  		return nil, BuildErrorResponse(r, err)
  2276  	} else {
  2277  		defer closeBody(r)
  2278  		return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2279  	}
  2280  }
  2281  
  2282  // DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID
  2283  func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) {
  2284  	if r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID)); err != nil {
  2285  		return false, BuildErrorResponse(r, err)
  2286  	} else {
  2287  		defer closeBody(r)
  2288  		return CheckStatusOK(r), BuildResponse(r)
  2289  	}
  2290  }
  2291  
  2292  // CreateOutgoingWebhook creates an outgoing webhook for a team or channel.
  2293  func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
  2294  	if r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson()); err != nil {
  2295  		return nil, BuildErrorResponse(r, err)
  2296  	} else {
  2297  		defer closeBody(r)
  2298  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2299  	}
  2300  }
  2301  
  2302  // UpdateOutgoingWebhook creates an outgoing webhook for a team or channel.
  2303  func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
  2304  	if r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson()); err != nil {
  2305  		return nil, BuildErrorResponse(r, err)
  2306  	} else {
  2307  		defer closeBody(r)
  2308  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2309  	}
  2310  }
  2311  
  2312  // GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0.
  2313  func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2314  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2315  	if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
  2316  		return nil, BuildErrorResponse(r, err)
  2317  	} else {
  2318  		defer closeBody(r)
  2319  		return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2320  	}
  2321  }
  2322  
  2323  // GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id.
  2324  func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) {
  2325  	if r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), ""); err != nil {
  2326  		return nil, BuildErrorResponse(r, err)
  2327  	} else {
  2328  		defer closeBody(r)
  2329  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2330  	}
  2331  }
  2332  
  2333  // GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0.
  2334  func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2335  	query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId)
  2336  	if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
  2337  		return nil, BuildErrorResponse(r, err)
  2338  	} else {
  2339  		defer closeBody(r)
  2340  		return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2341  	}
  2342  }
  2343  
  2344  // GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0.
  2345  func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2346  	query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
  2347  	if r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag); err != nil {
  2348  		return nil, BuildErrorResponse(r, err)
  2349  	} else {
  2350  		defer closeBody(r)
  2351  		return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2352  	}
  2353  }
  2354  
  2355  // RegenOutgoingHookToken regenerate the outgoing webhook token.
  2356  func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) {
  2357  	if r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", ""); err != nil {
  2358  		return nil, BuildErrorResponse(r, err)
  2359  	} else {
  2360  		defer closeBody(r)
  2361  		return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2362  	}
  2363  }
  2364  
  2365  // DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id.
  2366  func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) {
  2367  	if r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId)); err != nil {
  2368  		return false, BuildErrorResponse(r, err)
  2369  	} else {
  2370  		defer closeBody(r)
  2371  		return CheckStatusOK(r), BuildResponse(r)
  2372  	}
  2373  }
  2374  
  2375  // Preferences Section
  2376  
  2377  // GetPreferences returns the user's preferences.
  2378  func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
  2379  	if r, err := c.DoApiGet(c.GetPreferencesRoute(userId), ""); err != nil {
  2380  		return nil, BuildErrorResponse(r, err)
  2381  	} else {
  2382  		preferences, _ := PreferencesFromJson(r.Body)
  2383  		defer closeBody(r)
  2384  		return preferences, BuildResponse(r)
  2385  	}
  2386  }
  2387  
  2388  // UpdatePreferences saves the user's preferences.
  2389  func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
  2390  	if r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson()); err != nil {
  2391  		return false, BuildErrorResponse(r, err)
  2392  	} else {
  2393  		defer closeBody(r)
  2394  		return true, BuildResponse(r)
  2395  	}
  2396  }
  2397  
  2398  // DeletePreferences deletes the user's preferences.
  2399  func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
  2400  	if r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson()); err != nil {
  2401  		return false, BuildErrorResponse(r, err)
  2402  	} else {
  2403  		defer closeBody(r)
  2404  		return true, BuildResponse(r)
  2405  	}
  2406  }
  2407  
  2408  // GetPreferencesByCategory returns the user's preferences from the provided category string.
  2409  func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) {
  2410  	url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category)
  2411  	if r, err := c.DoApiGet(url, ""); err != nil {
  2412  		return nil, BuildErrorResponse(r, err)
  2413  	} else {
  2414  		preferences, _ := PreferencesFromJson(r.Body)
  2415  		defer closeBody(r)
  2416  		return preferences, BuildResponse(r)
  2417  	}
  2418  }
  2419  
  2420  // GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string.
  2421  func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) {
  2422  	url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName)
  2423  	if r, err := c.DoApiGet(url, ""); err != nil {
  2424  		return nil, BuildErrorResponse(r, err)
  2425  	} else {
  2426  		defer closeBody(r)
  2427  		return PreferenceFromJson(r.Body), BuildResponse(r)
  2428  	}
  2429  }
  2430  
  2431  // SAML Section
  2432  
  2433  // GetSamlMetadata returns metadata for the SAML configuration.
  2434  func (c *Client4) GetSamlMetadata() (string, *Response) {
  2435  	if r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", ""); err != nil {
  2436  		return "", BuildErrorResponse(r, err)
  2437  	} else {
  2438  		defer closeBody(r)
  2439  		buf := new(bytes.Buffer)
  2440  		buf.ReadFrom(r.Body)
  2441  		return buf.String(), BuildResponse(r)
  2442  	}
  2443  }
  2444  
  2445  func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
  2446  	body := &bytes.Buffer{}
  2447  	writer := multipart.NewWriter(body)
  2448  
  2449  	if part, err := writer.CreateFormFile("certificate", filename); err != nil {
  2450  		return nil, nil, err
  2451  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2452  		return nil, nil, err
  2453  	}
  2454  
  2455  	if err := writer.Close(); err != nil {
  2456  		return nil, nil, err
  2457  	}
  2458  
  2459  	return body.Bytes(), writer, nil
  2460  }
  2461  
  2462  // UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
  2463  func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
  2464  	body, writer, err := samlFileToMultipart(data, filename)
  2465  	if err != nil {
  2466  		return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  2467  	}
  2468  
  2469  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/idp", body, writer.FormDataContentType())
  2470  	return resp.Error == nil, resp
  2471  }
  2472  
  2473  // UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
  2474  func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
  2475  	body, writer, err := samlFileToMultipart(data, filename)
  2476  	if err != nil {
  2477  		return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  2478  	}
  2479  
  2480  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/public", body, writer.FormDataContentType())
  2481  	return resp.Error == nil, resp
  2482  }
  2483  
  2484  // UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
  2485  func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
  2486  	body, writer, err := samlFileToMultipart(data, filename)
  2487  	if err != nil {
  2488  		return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  2489  	}
  2490  
  2491  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/private", body, writer.FormDataContentType())
  2492  	return resp.Error == nil, resp
  2493  }
  2494  
  2495  // DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  2496  func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) {
  2497  	if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp"); err != nil {
  2498  		return false, BuildErrorResponse(r, err)
  2499  	} else {
  2500  		defer closeBody(r)
  2501  		return CheckStatusOK(r), BuildResponse(r)
  2502  	}
  2503  }
  2504  
  2505  // DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  2506  func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) {
  2507  	if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public"); err != nil {
  2508  		return false, BuildErrorResponse(r, err)
  2509  	} else {
  2510  		defer closeBody(r)
  2511  		return CheckStatusOK(r), BuildResponse(r)
  2512  	}
  2513  }
  2514  
  2515  // DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  2516  func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) {
  2517  	if r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private"); err != nil {
  2518  		return false, BuildErrorResponse(r, err)
  2519  	} else {
  2520  		defer closeBody(r)
  2521  		return CheckStatusOK(r), BuildResponse(r)
  2522  	}
  2523  }
  2524  
  2525  // GetSamlCertificateStatus returns metadata for the SAML configuration.
  2526  func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) {
  2527  	if r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", ""); err != nil {
  2528  		return nil, BuildErrorResponse(r, err)
  2529  	} else {
  2530  		defer closeBody(r)
  2531  		return SamlCertificateStatusFromJson(r.Body), BuildResponse(r)
  2532  	}
  2533  }
  2534  
  2535  // Compliance Section
  2536  
  2537  // CreateComplianceReport creates an incoming webhook for a channel.
  2538  func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) {
  2539  	if r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson()); err != nil {
  2540  		return nil, BuildErrorResponse(r, err)
  2541  	} else {
  2542  		defer closeBody(r)
  2543  		return ComplianceFromJson(r.Body), BuildResponse(r)
  2544  	}
  2545  }
  2546  
  2547  // GetComplianceReports returns list of compliance reports.
  2548  func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) {
  2549  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2550  	if r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, ""); err != nil {
  2551  		return nil, BuildErrorResponse(r, err)
  2552  	} else {
  2553  		defer closeBody(r)
  2554  		return CompliancesFromJson(r.Body), BuildResponse(r)
  2555  	}
  2556  }
  2557  
  2558  // GetComplianceReport returns a compliance report.
  2559  func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) {
  2560  	if r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), ""); err != nil {
  2561  		return nil, BuildErrorResponse(r, err)
  2562  	} else {
  2563  		defer closeBody(r)
  2564  		return ComplianceFromJson(r.Body), BuildResponse(r)
  2565  	}
  2566  }
  2567  
  2568  // DownloadComplianceReport returns a full compliance report as a file.
  2569  func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) {
  2570  	var rq *http.Request
  2571  	rq, _ = http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil)
  2572  	rq.Close = true
  2573  
  2574  	if len(c.AuthToken) > 0 {
  2575  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  2576  	}
  2577  
  2578  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  2579  		return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  2580  	} else {
  2581  		defer closeBody(rp)
  2582  
  2583  		if rp.StatusCode >= 300 {
  2584  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2585  		} else if data, err := ioutil.ReadAll(rp.Body); err != nil {
  2586  			return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode))
  2587  		} else {
  2588  			return data, BuildResponse(rp)
  2589  		}
  2590  	}
  2591  }
  2592  
  2593  // Cluster Section
  2594  
  2595  // GetClusterStatus returns the status of all the configured cluster nodes.
  2596  func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) {
  2597  	if r, err := c.DoApiGet(c.GetClusterRoute()+"/status", ""); err != nil {
  2598  		return nil, BuildErrorResponse(r, err)
  2599  	} else {
  2600  		defer closeBody(r)
  2601  		return ClusterInfosFromJson(r.Body), BuildResponse(r)
  2602  	}
  2603  }
  2604  
  2605  // LDAP Section
  2606  
  2607  // SyncLdap will force a sync with the configured LDAP server.
  2608  func (c *Client4) SyncLdap() (bool, *Response) {
  2609  	if r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", ""); err != nil {
  2610  		return false, BuildErrorResponse(r, err)
  2611  	} else {
  2612  		defer closeBody(r)
  2613  		return CheckStatusOK(r), BuildResponse(r)
  2614  	}
  2615  }
  2616  
  2617  // TestLdap will attempt to connect to the configured LDAP server and return OK if configured
  2618  // correctly.
  2619  func (c *Client4) TestLdap() (bool, *Response) {
  2620  	if r, err := c.DoApiPost(c.GetLdapRoute()+"/test", ""); err != nil {
  2621  		return false, BuildErrorResponse(r, err)
  2622  	} else {
  2623  		defer closeBody(r)
  2624  		return CheckStatusOK(r), BuildResponse(r)
  2625  	}
  2626  }
  2627  
  2628  // Audits Section
  2629  
  2630  // GetAudits returns a list of audits for the whole system.
  2631  func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) {
  2632  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2633  	if r, err := c.DoApiGet("/audits"+query, etag); err != nil {
  2634  		return nil, BuildErrorResponse(r, err)
  2635  	} else {
  2636  		defer closeBody(r)
  2637  		return AuditsFromJson(r.Body), BuildResponse(r)
  2638  	}
  2639  }
  2640  
  2641  // Brand Section
  2642  
  2643  // GetBrandImage retrieves the previously uploaded brand image.
  2644  func (c *Client4) GetBrandImage() ([]byte, *Response) {
  2645  	if r, err := c.DoApiGet(c.GetBrandRoute()+"/image", ""); err != nil {
  2646  		return nil, BuildErrorResponse(r, err)
  2647  	} else {
  2648  		defer closeBody(r)
  2649  
  2650  		if r.StatusCode >= 300 {
  2651  			return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body))
  2652  		} else if data, err := ioutil.ReadAll(r.Body); err != nil {
  2653  			return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2654  		} else {
  2655  			return data, BuildResponse(r)
  2656  		}
  2657  	}
  2658  }
  2659  
  2660  // UploadBrandImage sets the brand image for the system.
  2661  func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) {
  2662  	body := &bytes.Buffer{}
  2663  	writer := multipart.NewWriter(body)
  2664  
  2665  	if part, err := writer.CreateFormFile("image", "brand.png"); err != nil {
  2666  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2667  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2668  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2669  	}
  2670  
  2671  	if err := writer.Close(); err != nil {
  2672  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  2673  	}
  2674  
  2675  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetBrandRoute()+"/image", bytes.NewReader(body.Bytes()))
  2676  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  2677  	rq.Close = true
  2678  
  2679  	if len(c.AuthToken) > 0 {
  2680  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  2681  	}
  2682  
  2683  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  2684  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  2685  	} else {
  2686  		defer closeBody(rp)
  2687  
  2688  		if rp.StatusCode >= 300 {
  2689  			return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2690  		} else {
  2691  			return CheckStatusOK(rp), BuildResponse(rp)
  2692  		}
  2693  	}
  2694  }
  2695  
  2696  // Logs Section
  2697  
  2698  // GetLogs page of logs as a string array.
  2699  func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) {
  2700  	query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage)
  2701  	if r, err := c.DoApiGet("/logs"+query, ""); err != nil {
  2702  		return nil, BuildErrorResponse(r, err)
  2703  	} else {
  2704  		defer closeBody(r)
  2705  		return ArrayFromJson(r.Body), BuildResponse(r)
  2706  	}
  2707  }
  2708  
  2709  // PostLog is a convenience Web Service call so clients can log messages into
  2710  // the server-side logs.  For example we typically log javascript error messages
  2711  // into the server-side.  It returns the log message if the logging was successful.
  2712  func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) {
  2713  	if r, err := c.DoApiPost("/logs", MapToJson(message)); err != nil {
  2714  		return nil, BuildErrorResponse(r, err)
  2715  	} else {
  2716  		defer closeBody(r)
  2717  		return MapFromJson(r.Body), BuildResponse(r)
  2718  	}
  2719  }
  2720  
  2721  // OAuth Section
  2722  
  2723  // CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  2724  func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
  2725  	if r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson()); err != nil {
  2726  		return nil, BuildErrorResponse(r, err)
  2727  	} else {
  2728  		defer closeBody(r)
  2729  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2730  	}
  2731  }
  2732  
  2733  // UpdateOAuthApp
  2734  func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
  2735  	if r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson()); err != nil {
  2736  		return nil, BuildErrorResponse(r, err)
  2737  	} else {
  2738  		defer closeBody(r)
  2739  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2740  	}
  2741  }
  2742  
  2743  // GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
  2744  func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) {
  2745  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2746  	if r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, ""); err != nil {
  2747  		return nil, BuildErrorResponse(r, err)
  2748  	} else {
  2749  		defer closeBody(r)
  2750  		return OAuthAppListFromJson(r.Body), BuildResponse(r)
  2751  	}
  2752  }
  2753  
  2754  // GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  2755  func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) {
  2756  	if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), ""); err != nil {
  2757  		return nil, BuildErrorResponse(r, err)
  2758  	} else {
  2759  		defer closeBody(r)
  2760  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2761  	}
  2762  }
  2763  
  2764  // GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  2765  func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) {
  2766  	if r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", ""); err != nil {
  2767  		return nil, BuildErrorResponse(r, err)
  2768  	} else {
  2769  		defer closeBody(r)
  2770  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2771  	}
  2772  }
  2773  
  2774  // DeleteOAuthApp deletes a registered OAuth 2.0 client application.
  2775  func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) {
  2776  	if r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId)); err != nil {
  2777  		return false, BuildErrorResponse(r, err)
  2778  	} else {
  2779  		defer closeBody(r)
  2780  		return CheckStatusOK(r), BuildResponse(r)
  2781  	}
  2782  }
  2783  
  2784  // RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application.
  2785  func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) {
  2786  	if r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", ""); err != nil {
  2787  		return nil, BuildErrorResponse(r, err)
  2788  	} else {
  2789  		defer closeBody(r)
  2790  		return OAuthAppFromJson(r.Body), BuildResponse(r)
  2791  	}
  2792  }
  2793  
  2794  // GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account.
  2795  func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) {
  2796  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2797  	if r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, ""); err != nil {
  2798  		return nil, BuildErrorResponse(r, err)
  2799  	} else {
  2800  		defer closeBody(r)
  2801  		return OAuthAppListFromJson(r.Body), BuildResponse(r)
  2802  	}
  2803  }
  2804  
  2805  // AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow.
  2806  func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) {
  2807  	if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), ""); err != nil {
  2808  		return "", BuildErrorResponse(r, err)
  2809  	} else {
  2810  		defer closeBody(r)
  2811  		return MapFromJson(r.Body)["redirect"], BuildResponse(r)
  2812  	}
  2813  }
  2814  
  2815  // DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account.
  2816  func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) {
  2817  	requestData := map[string]string{"client_id": appId}
  2818  	if r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), ""); err != nil {
  2819  		return false, BuildErrorResponse(r, err)
  2820  	} else {
  2821  		defer closeBody(r)
  2822  		return CheckStatusOK(r), BuildResponse(r)
  2823  	}
  2824  }
  2825  
  2826  // Elasticsearch Section
  2827  
  2828  // TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured
  2829  // correctly.
  2830  func (c *Client4) TestElasticsearch() (bool, *Response) {
  2831  	if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", ""); err != nil {
  2832  		return false, BuildErrorResponse(r, err)
  2833  	} else {
  2834  		defer closeBody(r)
  2835  		return CheckStatusOK(r), BuildResponse(r)
  2836  	}
  2837  }
  2838  
  2839  // PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes.
  2840  func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
  2841  	if r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", ""); err != nil {
  2842  		return false, BuildErrorResponse(r, err)
  2843  	} else {
  2844  		defer closeBody(r)
  2845  		return CheckStatusOK(r), BuildResponse(r)
  2846  	}
  2847  }
  2848  
  2849  // Data Retention Section
  2850  
  2851  // GetDataRetentionPolicy will get the current server data retention policy details.
  2852  func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) {
  2853  	if r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", ""); err != nil {
  2854  		return nil, BuildErrorResponse(r, err)
  2855  	} else {
  2856  		defer closeBody(r)
  2857  		return DataRetentionPolicyFromJson(r.Body), BuildResponse(r)
  2858  	}
  2859  }
  2860  
  2861  // Commands Section
  2862  
  2863  // CreateCommand will create a new command if the user have the right permissions.
  2864  func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) {
  2865  	if r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson()); err != nil {
  2866  		return nil, BuildErrorResponse(r, err)
  2867  	} else {
  2868  		defer closeBody(r)
  2869  		return CommandFromJson(r.Body), BuildResponse(r)
  2870  	}
  2871  }
  2872  
  2873  // UpdateCommand updates a command based on the provided Command struct
  2874  func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) {
  2875  	if r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson()); err != nil {
  2876  		return nil, BuildErrorResponse(r, err)
  2877  	} else {
  2878  		defer closeBody(r)
  2879  		return CommandFromJson(r.Body), BuildResponse(r)
  2880  	}
  2881  }
  2882  
  2883  // DeleteCommand deletes a command based on the provided command id string
  2884  func (c *Client4) DeleteCommand(commandId string) (bool, *Response) {
  2885  	if r, err := c.DoApiDelete(c.GetCommandRoute(commandId)); err != nil {
  2886  		return false, BuildErrorResponse(r, err)
  2887  	} else {
  2888  		defer closeBody(r)
  2889  		return CheckStatusOK(r), BuildResponse(r)
  2890  	}
  2891  }
  2892  
  2893  // ListCommands will retrieve a list of commands available in the team.
  2894  func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) {
  2895  	query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly)
  2896  	if r, err := c.DoApiGet(c.GetCommandsRoute()+query, ""); err != nil {
  2897  		return nil, BuildErrorResponse(r, err)
  2898  	} else {
  2899  		defer closeBody(r)
  2900  		return CommandListFromJson(r.Body), BuildResponse(r)
  2901  	}
  2902  }
  2903  
  2904  // ExecuteCommand executes a given slash command.
  2905  func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) {
  2906  	commandArgs := &CommandArgs{
  2907  		ChannelId: channelId,
  2908  		Command:   command,
  2909  	}
  2910  	if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
  2911  		return nil, BuildErrorResponse(r, err)
  2912  	} else {
  2913  		defer closeBody(r)
  2914  		return CommandResponseFromJson(r.Body), BuildResponse(r)
  2915  	}
  2916  }
  2917  
  2918  // ExecuteCommand executes a given slash command against the specified team
  2919  // Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case
  2920  func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) {
  2921  	commandArgs := &CommandArgs{
  2922  		ChannelId: channelId,
  2923  		TeamId:    teamId,
  2924  		Command:   command,
  2925  	}
  2926  	if r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson()); err != nil {
  2927  		return nil, BuildErrorResponse(r, err)
  2928  	} else {
  2929  		defer closeBody(r)
  2930  		return CommandResponseFromJson(r.Body), BuildResponse(r)
  2931  	}
  2932  }
  2933  
  2934  // ListCommands will retrieve a list of commands available in the team.
  2935  func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) {
  2936  	if r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), ""); err != nil {
  2937  		return nil, BuildErrorResponse(r, err)
  2938  	} else {
  2939  		defer closeBody(r)
  2940  		return CommandListFromJson(r.Body), BuildResponse(r)
  2941  	}
  2942  }
  2943  
  2944  // RegenCommandToken will create a new token if the user have the right permissions.
  2945  func (c *Client4) RegenCommandToken(commandId string) (string, *Response) {
  2946  	if r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", ""); err != nil {
  2947  		return "", BuildErrorResponse(r, err)
  2948  	} else {
  2949  		defer closeBody(r)
  2950  		return MapFromJson(r.Body)["token"], BuildResponse(r)
  2951  	}
  2952  }
  2953  
  2954  // Status Section
  2955  
  2956  // GetUserStatus returns a user based on the provided user id string.
  2957  func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) {
  2958  	if r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag); err != nil {
  2959  		return nil, BuildErrorResponse(r, err)
  2960  	} else {
  2961  		defer closeBody(r)
  2962  		return StatusFromJson(r.Body), BuildResponse(r)
  2963  	}
  2964  }
  2965  
  2966  // GetUsersStatusesByIds returns a list of users status based on the provided user ids.
  2967  func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) {
  2968  	if r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds)); err != nil {
  2969  		return nil, BuildErrorResponse(r, err)
  2970  	} else {
  2971  		defer closeBody(r)
  2972  		return StatusListFromJson(r.Body), BuildResponse(r)
  2973  	}
  2974  }
  2975  
  2976  // UpdateUserStatus sets a user's status based on the provided user id string.
  2977  func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) {
  2978  	if r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson()); err != nil {
  2979  		return nil, BuildErrorResponse(r, err)
  2980  	} else {
  2981  		defer closeBody(r)
  2982  		return StatusFromJson(r.Body), BuildResponse(r)
  2983  
  2984  	}
  2985  }
  2986  
  2987  // Webrtc Section
  2988  
  2989  // GetWebrtcToken returns a valid token, stun server and turn server with credentials to
  2990  // use with the Mattermost WebRTC service.
  2991  func (c *Client4) GetWebrtcToken() (*WebrtcInfoResponse, *Response) {
  2992  	if r, err := c.DoApiGet("/webrtc/token", ""); err != nil {
  2993  		return nil, BuildErrorResponse(r, err)
  2994  	} else {
  2995  		defer closeBody(r)
  2996  		return WebrtcInfoResponseFromJson(r.Body), BuildResponse(r)
  2997  	}
  2998  }
  2999  
  3000  // Emoji Section
  3001  
  3002  // CreateEmoji will save an emoji to the server if the current user has permission
  3003  // to do so. If successful, the provided emoji will be returned with its Id field
  3004  // filled in. Otherwise, an error will be returned.
  3005  func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *Response) {
  3006  	body := &bytes.Buffer{}
  3007  	writer := multipart.NewWriter(body)
  3008  
  3009  	if part, err := writer.CreateFormFile("image", filename); err != nil {
  3010  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
  3011  	} else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
  3012  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
  3013  	}
  3014  
  3015  	if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
  3016  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)}
  3017  	}
  3018  
  3019  	if err := writer.Close(); err != nil {
  3020  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)}
  3021  	}
  3022  
  3023  	return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType())
  3024  }
  3025  
  3026  // GetEmojiList returns a page of custom emoji on the system.
  3027  func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) {
  3028  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3029  	if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil {
  3030  		return nil, BuildErrorResponse(r, err)
  3031  	} else {
  3032  		defer closeBody(r)
  3033  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3034  	}
  3035  }
  3036  
  3037  // GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort
  3038  // parameter, blank for no sorting and "name" to sort by emoji names.
  3039  func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) {
  3040  	query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort)
  3041  	if r, err := c.DoApiGet(c.GetEmojisRoute()+query, ""); err != nil {
  3042  		return nil, BuildErrorResponse(r, err)
  3043  	} else {
  3044  		defer closeBody(r)
  3045  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3046  	}
  3047  }
  3048  
  3049  // DeleteEmoji delete an custom emoji on the provided emoji id string.
  3050  func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) {
  3051  	if r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId)); err != nil {
  3052  		return false, BuildErrorResponse(r, err)
  3053  	} else {
  3054  		defer closeBody(r)
  3055  		return CheckStatusOK(r), BuildResponse(r)
  3056  	}
  3057  }
  3058  
  3059  // GetEmoji returns a custom emoji based on the emojiId string.
  3060  func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) {
  3061  	if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), ""); err != nil {
  3062  		return nil, BuildErrorResponse(r, err)
  3063  	} else {
  3064  		defer closeBody(r)
  3065  		return EmojiFromJson(r.Body), BuildResponse(r)
  3066  	}
  3067  }
  3068  
  3069  // GetEmojiByName returns a custom emoji based on the name string.
  3070  func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) {
  3071  	if r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), ""); err != nil {
  3072  		return nil, BuildErrorResponse(r, err)
  3073  	} else {
  3074  		defer closeBody(r)
  3075  		return EmojiFromJson(r.Body), BuildResponse(r)
  3076  	}
  3077  }
  3078  
  3079  // GetEmojiImage returns the emoji image.
  3080  func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) {
  3081  	if r, err := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", ""); err != nil {
  3082  		return nil, BuildErrorResponse(r, err)
  3083  	} else {
  3084  		defer closeBody(r)
  3085  
  3086  		if data, err := ioutil.ReadAll(r.Body); err != nil {
  3087  			return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  3088  		} else {
  3089  			return data, BuildResponse(r)
  3090  		}
  3091  	}
  3092  }
  3093  
  3094  // SearchEmoji returns a list of emoji matching some search criteria.
  3095  func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) {
  3096  	if r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson()); err != nil {
  3097  		return nil, BuildErrorResponse(r, err)
  3098  	} else {
  3099  		defer closeBody(r)
  3100  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3101  	}
  3102  }
  3103  
  3104  // AutocompleteEmoji returns a list of emoji starting with or matching name.
  3105  func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) {
  3106  	query := fmt.Sprintf("?name=%v", name)
  3107  	if r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, ""); err != nil {
  3108  		return nil, BuildErrorResponse(r, err)
  3109  	} else {
  3110  		defer closeBody(r)
  3111  		return EmojiListFromJson(r.Body), BuildResponse(r)
  3112  	}
  3113  }
  3114  
  3115  // Reaction Section
  3116  
  3117  // SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned.
  3118  func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) {
  3119  	if r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson()); err != nil {
  3120  		return nil, BuildErrorResponse(r, err)
  3121  	} else {
  3122  		defer closeBody(r)
  3123  		return ReactionFromJson(r.Body), BuildResponse(r)
  3124  	}
  3125  }
  3126  
  3127  // GetReactions returns a list of reactions to a post.
  3128  func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) {
  3129  	if r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", ""); err != nil {
  3130  		return nil, BuildErrorResponse(r, err)
  3131  	} else {
  3132  		defer closeBody(r)
  3133  		return ReactionsFromJson(r.Body), BuildResponse(r)
  3134  	}
  3135  }
  3136  
  3137  // DeleteReaction deletes reaction of a user in a post.
  3138  func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) {
  3139  	if r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)); err != nil {
  3140  		return false, BuildErrorResponse(r, err)
  3141  	} else {
  3142  		defer closeBody(r)
  3143  		return CheckStatusOK(r), BuildResponse(r)
  3144  	}
  3145  }
  3146  
  3147  // Open Graph Metadata Section
  3148  
  3149  // OpenGraph return the open graph metadata for a particular url if the site have the metadata
  3150  func (c *Client4) OpenGraph(url string) (map[string]string, *Response) {
  3151  	requestBody := make(map[string]string)
  3152  	requestBody["url"] = url
  3153  
  3154  	if r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody)); err != nil {
  3155  		return nil, BuildErrorResponse(r, err)
  3156  	} else {
  3157  		defer closeBody(r)
  3158  		return MapFromJson(r.Body), BuildResponse(r)
  3159  	}
  3160  }
  3161  
  3162  // Jobs Section
  3163  
  3164  // GetJob gets a single job.
  3165  func (c *Client4) GetJob(id string) (*Job, *Response) {
  3166  	if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), ""); err != nil {
  3167  		return nil, BuildErrorResponse(r, err)
  3168  	} else {
  3169  		defer closeBody(r)
  3170  		return JobFromJson(r.Body), BuildResponse(r)
  3171  	}
  3172  }
  3173  
  3174  // Get all jobs, sorted with the job that was created most recently first.
  3175  func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) {
  3176  	if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), ""); err != nil {
  3177  		return nil, BuildErrorResponse(r, err)
  3178  	} else {
  3179  		defer closeBody(r)
  3180  		return JobsFromJson(r.Body), BuildResponse(r)
  3181  	}
  3182  }
  3183  
  3184  // GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first.
  3185  func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) {
  3186  	if r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), ""); err != nil {
  3187  		return nil, BuildErrorResponse(r, err)
  3188  	} else {
  3189  		defer closeBody(r)
  3190  		return JobsFromJson(r.Body), BuildResponse(r)
  3191  	}
  3192  }
  3193  
  3194  // CreateJob creates a job based on the provided job struct.
  3195  func (c *Client4) CreateJob(job *Job) (*Job, *Response) {
  3196  	if r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson()); err != nil {
  3197  		return nil, BuildErrorResponse(r, err)
  3198  	} else {
  3199  		defer closeBody(r)
  3200  		return JobFromJson(r.Body), BuildResponse(r)
  3201  	}
  3202  }
  3203  
  3204  // CancelJob requests the cancellation of the job with the provided Id.
  3205  func (c *Client4) CancelJob(jobId string) (bool, *Response) {
  3206  	if r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), ""); err != nil {
  3207  		return false, BuildErrorResponse(r, err)
  3208  	} else {
  3209  		defer closeBody(r)
  3210  		return CheckStatusOK(r), BuildResponse(r)
  3211  	}
  3212  }
  3213  
  3214  // Plugin Section
  3215  
  3216  // UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin.
  3217  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3218  func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
  3219  	body := new(bytes.Buffer)
  3220  	writer := multipart.NewWriter(body)
  3221  
  3222  	if part, err := writer.CreateFormFile("plugin", "plugin.tar.gz"); err != nil {
  3223  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  3224  	} else if _, err = io.Copy(part, file); err != nil {
  3225  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  3226  	}
  3227  
  3228  	if err := writer.Close(); err != nil {
  3229  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  3230  	}
  3231  
  3232  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body)
  3233  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  3234  	rq.Close = true
  3235  
  3236  	if len(c.AuthToken) > 0 {
  3237  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  3238  	}
  3239  
  3240  	if rp, err := c.HttpClient.Do(rq); err != nil || rp == nil {
  3241  		return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0))
  3242  	} else {
  3243  		defer closeBody(rp)
  3244  
  3245  		if rp.StatusCode >= 300 {
  3246  			return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  3247  		} else {
  3248  			return ManifestFromJson(rp.Body), BuildResponse(rp)
  3249  		}
  3250  	}
  3251  }
  3252  
  3253  // GetPlugins will return a list of plugin manifests for currently active plugins.
  3254  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3255  func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
  3256  	if r, err := c.DoApiGet(c.GetPluginsRoute(), ""); err != nil {
  3257  		return nil, BuildErrorResponse(r, err)
  3258  	} else {
  3259  		defer closeBody(r)
  3260  		return PluginsResponseFromJson(r.Body), BuildResponse(r)
  3261  	}
  3262  }
  3263  
  3264  // RemovePlugin will deactivate and delete a plugin.
  3265  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3266  func (c *Client4) RemovePlugin(id string) (bool, *Response) {
  3267  	if r, err := c.DoApiDelete(c.GetPluginRoute(id)); err != nil {
  3268  		return false, BuildErrorResponse(r, err)
  3269  	} else {
  3270  		defer closeBody(r)
  3271  		return CheckStatusOK(r), BuildResponse(r)
  3272  	}
  3273  }
  3274  
  3275  // GetWebappPlugins will return a list of plugins that the webapp should download.
  3276  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3277  func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
  3278  	if r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", ""); err != nil {
  3279  		return nil, BuildErrorResponse(r, err)
  3280  	} else {
  3281  		defer closeBody(r)
  3282  		return ManifestListFromJson(r.Body), BuildResponse(r)
  3283  	}
  3284  }
  3285  
  3286  // ActivatePlugin will activate an plugin installed.
  3287  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3288  func (c *Client4) ActivatePlugin(id string) (bool, *Response) {
  3289  	if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/activate", ""); err != nil {
  3290  		return false, BuildErrorResponse(r, err)
  3291  	} else {
  3292  		defer closeBody(r)
  3293  		return CheckStatusOK(r), BuildResponse(r)
  3294  	}
  3295  }
  3296  
  3297  // DeactivatePlugin will deactivate an active plugin.
  3298  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  3299  func (c *Client4) DeactivatePlugin(id string) (bool, *Response) {
  3300  	if r, err := c.DoApiPost(c.GetPluginRoute(id)+"/deactivate", ""); err != nil {
  3301  		return false, BuildErrorResponse(r, err)
  3302  	} else {
  3303  		defer closeBody(r)
  3304  		return CheckStatusOK(r), BuildResponse(r)
  3305  	}
  3306  }