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