github.com/rajatvaryani/mattermost-server@v5.11.1+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  	"encoding/json"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"mime/multipart"
    13  	"net/http"
    14  	"net/url"
    15  	"strconv"
    16  	"strings"
    17  	"time"
    18  )
    19  
    20  const (
    21  	HEADER_REQUEST_ID         = "X-Request-ID"
    22  	HEADER_VERSION_ID         = "X-Version-ID"
    23  	HEADER_CLUSTER_ID         = "X-Cluster-ID"
    24  	HEADER_ETAG_SERVER        = "ETag"
    25  	HEADER_ETAG_CLIENT        = "If-None-Match"
    26  	HEADER_FORWARDED          = "X-Forwarded-For"
    27  	HEADER_REAL_IP            = "X-Real-IP"
    28  	HEADER_FORWARDED_PROTO    = "X-Forwarded-Proto"
    29  	HEADER_TOKEN              = "token"
    30  	HEADER_CSRF_TOKEN         = "X-CSRF-Token"
    31  	HEADER_BEARER             = "BEARER"
    32  	HEADER_AUTH               = "Authorization"
    33  	HEADER_REQUESTED_WITH     = "X-Requested-With"
    34  	HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
    35  	STATUS                    = "status"
    36  	STATUS_OK                 = "OK"
    37  	STATUS_FAIL               = "FAIL"
    38  	STATUS_REMOVE             = "REMOVE"
    39  
    40  	CLIENT_DIR = "client"
    41  
    42  	API_URL_SUFFIX_V1 = "/api/v1"
    43  	API_URL_SUFFIX_V4 = "/api/v4"
    44  	API_URL_SUFFIX    = API_URL_SUFFIX_V4
    45  )
    46  
    47  type Response struct {
    48  	StatusCode    int
    49  	Error         *AppError
    50  	RequestId     string
    51  	Etag          string
    52  	ServerVersion string
    53  	Header        http.Header
    54  }
    55  
    56  type Client4 struct {
    57  	Url        string       // The location of the server, for example  "http://localhost:8065"
    58  	ApiUrl     string       // The api location of the server, for example "http://localhost:8065/api/v4"
    59  	HttpClient *http.Client // The http client
    60  	AuthToken  string
    61  	AuthType   string
    62  	HttpHeader map[string]string // Headers to be copied over for each request
    63  }
    64  
    65  func closeBody(r *http.Response) {
    66  	if r.Body != nil {
    67  		_, _ = ioutil.ReadAll(r.Body)
    68  		_ = r.Body.Close()
    69  	}
    70  }
    71  
    72  // Must is a convenience function used for testing.
    73  func (c *Client4) Must(result interface{}, resp *Response) interface{} {
    74  	if resp.Error != nil {
    75  		time.Sleep(time.Second)
    76  		panic(resp.Error)
    77  	}
    78  
    79  	return result
    80  }
    81  
    82  func NewAPIv4Client(url string) *Client4 {
    83  	return &Client4{url, url + API_URL_SUFFIX, &http.Client{}, "", "", map[string]string{}}
    84  }
    85  
    86  func BuildErrorResponse(r *http.Response, err *AppError) *Response {
    87  	var statusCode int
    88  	var header http.Header
    89  	if r != nil {
    90  		statusCode = r.StatusCode
    91  		header = r.Header
    92  	} else {
    93  		statusCode = 0
    94  		header = make(http.Header)
    95  	}
    96  
    97  	return &Response{
    98  		StatusCode: statusCode,
    99  		Error:      err,
   100  		Header:     header,
   101  	}
   102  }
   103  
   104  func BuildResponse(r *http.Response) *Response {
   105  	return &Response{
   106  		StatusCode:    r.StatusCode,
   107  		RequestId:     r.Header.Get(HEADER_REQUEST_ID),
   108  		Etag:          r.Header.Get(HEADER_ETAG_SERVER),
   109  		ServerVersion: r.Header.Get(HEADER_VERSION_ID),
   110  		Header:        r.Header,
   111  	}
   112  }
   113  
   114  func (c *Client4) MockSession(sessionToken string) {
   115  	c.AuthToken = sessionToken
   116  	c.AuthType = HEADER_BEARER
   117  }
   118  
   119  func (c *Client4) SetOAuthToken(token string) {
   120  	c.AuthToken = token
   121  	c.AuthType = HEADER_TOKEN
   122  }
   123  
   124  func (c *Client4) ClearOAuthToken() {
   125  	c.AuthToken = ""
   126  	c.AuthType = HEADER_BEARER
   127  }
   128  
   129  func (c *Client4) GetUsersRoute() string {
   130  	return fmt.Sprintf("/users")
   131  }
   132  
   133  func (c *Client4) GetUserRoute(userId string) string {
   134  	return fmt.Sprintf(c.GetUsersRoute()+"/%v", userId)
   135  }
   136  
   137  func (c *Client4) GetUserAccessTokensRoute() string {
   138  	return fmt.Sprintf(c.GetUsersRoute() + "/tokens")
   139  }
   140  
   141  func (c *Client4) GetUserAccessTokenRoute(tokenId string) string {
   142  	return fmt.Sprintf(c.GetUsersRoute()+"/tokens/%v", tokenId)
   143  }
   144  
   145  func (c *Client4) GetUserByUsernameRoute(userName string) string {
   146  	return fmt.Sprintf(c.GetUsersRoute()+"/username/%v", userName)
   147  }
   148  
   149  func (c *Client4) GetUserByEmailRoute(email string) string {
   150  	return fmt.Sprintf(c.GetUsersRoute()+"/email/%v", email)
   151  }
   152  
   153  func (c *Client4) GetBotsRoute() string {
   154  	return fmt.Sprintf("/bots")
   155  }
   156  
   157  func (c *Client4) GetBotRoute(botUserId string) string {
   158  	return fmt.Sprintf("%s/%s", c.GetBotsRoute(), botUserId)
   159  }
   160  
   161  func (c *Client4) GetTeamsRoute() string {
   162  	return fmt.Sprintf("/teams")
   163  }
   164  
   165  func (c *Client4) GetTeamRoute(teamId string) string {
   166  	return fmt.Sprintf(c.GetTeamsRoute()+"/%v", teamId)
   167  }
   168  
   169  func (c *Client4) GetTeamAutoCompleteCommandsRoute(teamId string) string {
   170  	return fmt.Sprintf(c.GetTeamsRoute()+"/%v/commands/autocomplete", teamId)
   171  }
   172  
   173  func (c *Client4) GetTeamByNameRoute(teamName string) string {
   174  	return fmt.Sprintf(c.GetTeamsRoute()+"/name/%v", teamName)
   175  }
   176  
   177  func (c *Client4) GetTeamMemberRoute(teamId, userId string) string {
   178  	return fmt.Sprintf(c.GetTeamRoute(teamId)+"/members/%v", userId)
   179  }
   180  
   181  func (c *Client4) GetTeamMembersRoute(teamId string) string {
   182  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/members")
   183  }
   184  
   185  func (c *Client4) GetTeamStatsRoute(teamId string) string {
   186  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/stats")
   187  }
   188  
   189  func (c *Client4) GetTeamImportRoute(teamId string) string {
   190  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/import")
   191  }
   192  
   193  func (c *Client4) GetChannelsRoute() string {
   194  	return fmt.Sprintf("/channels")
   195  }
   196  
   197  func (c *Client4) GetChannelsForTeamRoute(teamId string) string {
   198  	return fmt.Sprintf(c.GetTeamRoute(teamId) + "/channels")
   199  }
   200  
   201  func (c *Client4) GetChannelRoute(channelId string) string {
   202  	return fmt.Sprintf(c.GetChannelsRoute()+"/%v", channelId)
   203  }
   204  
   205  func (c *Client4) GetChannelByNameRoute(channelName, teamId string) string {
   206  	return fmt.Sprintf(c.GetTeamRoute(teamId)+"/channels/name/%v", channelName)
   207  }
   208  
   209  func (c *Client4) GetChannelByNameForTeamNameRoute(channelName, teamName string) string {
   210  	return fmt.Sprintf(c.GetTeamByNameRoute(teamName)+"/channels/name/%v", channelName)
   211  }
   212  
   213  func (c *Client4) GetChannelMembersRoute(channelId string) string {
   214  	return fmt.Sprintf(c.GetChannelRoute(channelId) + "/members")
   215  }
   216  
   217  func (c *Client4) GetChannelMemberRoute(channelId, userId string) string {
   218  	return fmt.Sprintf(c.GetChannelMembersRoute(channelId)+"/%v", userId)
   219  }
   220  
   221  func (c *Client4) GetPostsRoute() string {
   222  	return fmt.Sprintf("/posts")
   223  }
   224  
   225  func (c *Client4) GetPostsEphemeralRoute() string {
   226  	return fmt.Sprintf("/posts/ephemeral")
   227  }
   228  
   229  func (c *Client4) GetConfigRoute() string {
   230  	return fmt.Sprintf("/config")
   231  }
   232  
   233  func (c *Client4) GetLicenseRoute() string {
   234  	return fmt.Sprintf("/license")
   235  }
   236  
   237  func (c *Client4) GetPostRoute(postId string) string {
   238  	return fmt.Sprintf(c.GetPostsRoute()+"/%v", postId)
   239  }
   240  
   241  func (c *Client4) GetFilesRoute() string {
   242  	return fmt.Sprintf("/files")
   243  }
   244  
   245  func (c *Client4) GetFileRoute(fileId string) string {
   246  	return fmt.Sprintf(c.GetFilesRoute()+"/%v", fileId)
   247  }
   248  
   249  func (c *Client4) GetPluginsRoute() string {
   250  	return fmt.Sprintf("/plugins")
   251  }
   252  
   253  func (c *Client4) GetPluginRoute(pluginId string) string {
   254  	return fmt.Sprintf(c.GetPluginsRoute()+"/%v", pluginId)
   255  }
   256  
   257  func (c *Client4) GetSystemRoute() string {
   258  	return fmt.Sprintf("/system")
   259  }
   260  
   261  func (c *Client4) GetTestEmailRoute() string {
   262  	return fmt.Sprintf("/email/test")
   263  }
   264  
   265  func (c *Client4) GetTestS3Route() string {
   266  	return fmt.Sprintf("/file/s3_test")
   267  }
   268  
   269  func (c *Client4) GetDatabaseRoute() string {
   270  	return fmt.Sprintf("/database")
   271  }
   272  
   273  func (c *Client4) GetCacheRoute() string {
   274  	return fmt.Sprintf("/caches")
   275  }
   276  
   277  func (c *Client4) GetClusterRoute() string {
   278  	return fmt.Sprintf("/cluster")
   279  }
   280  
   281  func (c *Client4) GetIncomingWebhooksRoute() string {
   282  	return fmt.Sprintf("/hooks/incoming")
   283  }
   284  
   285  func (c *Client4) GetIncomingWebhookRoute(hookID string) string {
   286  	return fmt.Sprintf(c.GetIncomingWebhooksRoute()+"/%v", hookID)
   287  }
   288  
   289  func (c *Client4) GetComplianceReportsRoute() string {
   290  	return fmt.Sprintf("/compliance/reports")
   291  }
   292  
   293  func (c *Client4) GetComplianceReportRoute(reportId string) string {
   294  	return fmt.Sprintf("/compliance/reports/%v", reportId)
   295  }
   296  
   297  func (c *Client4) GetOutgoingWebhooksRoute() string {
   298  	return fmt.Sprintf("/hooks/outgoing")
   299  }
   300  
   301  func (c *Client4) GetOutgoingWebhookRoute(hookID string) string {
   302  	return fmt.Sprintf(c.GetOutgoingWebhooksRoute()+"/%v", hookID)
   303  }
   304  
   305  func (c *Client4) GetPreferencesRoute(userId string) string {
   306  	return fmt.Sprintf(c.GetUserRoute(userId) + "/preferences")
   307  }
   308  
   309  func (c *Client4) GetUserStatusRoute(userId string) string {
   310  	return fmt.Sprintf(c.GetUserRoute(userId) + "/status")
   311  }
   312  
   313  func (c *Client4) GetUserStatusesRoute() string {
   314  	return fmt.Sprintf(c.GetUsersRoute() + "/status")
   315  }
   316  
   317  func (c *Client4) GetSamlRoute() string {
   318  	return fmt.Sprintf("/saml")
   319  }
   320  
   321  func (c *Client4) GetLdapRoute() string {
   322  	return fmt.Sprintf("/ldap")
   323  }
   324  
   325  func (c *Client4) GetBrandRoute() string {
   326  	return fmt.Sprintf("/brand")
   327  }
   328  
   329  func (c *Client4) GetDataRetentionRoute() string {
   330  	return fmt.Sprintf("/data_retention")
   331  }
   332  
   333  func (c *Client4) GetElasticsearchRoute() string {
   334  	return fmt.Sprintf("/elasticsearch")
   335  }
   336  
   337  func (c *Client4) GetCommandsRoute() string {
   338  	return fmt.Sprintf("/commands")
   339  }
   340  
   341  func (c *Client4) GetCommandRoute(commandId string) string {
   342  	return fmt.Sprintf(c.GetCommandsRoute()+"/%v", commandId)
   343  }
   344  
   345  func (c *Client4) GetEmojisRoute() string {
   346  	return fmt.Sprintf("/emoji")
   347  }
   348  
   349  func (c *Client4) GetEmojiRoute(emojiId string) string {
   350  	return fmt.Sprintf(c.GetEmojisRoute()+"/%v", emojiId)
   351  }
   352  
   353  func (c *Client4) GetEmojiByNameRoute(name string) string {
   354  	return fmt.Sprintf(c.GetEmojisRoute()+"/name/%v", name)
   355  }
   356  
   357  func (c *Client4) GetReactionsRoute() string {
   358  	return fmt.Sprintf("/reactions")
   359  }
   360  
   361  func (c *Client4) GetOAuthAppsRoute() string {
   362  	return fmt.Sprintf("/oauth/apps")
   363  }
   364  
   365  func (c *Client4) GetOAuthAppRoute(appId string) string {
   366  	return fmt.Sprintf("/oauth/apps/%v", appId)
   367  }
   368  
   369  func (c *Client4) GetOpenGraphRoute() string {
   370  	return fmt.Sprintf("/opengraph")
   371  }
   372  
   373  func (c *Client4) GetJobsRoute() string {
   374  	return fmt.Sprintf("/jobs")
   375  }
   376  
   377  func (c *Client4) GetRolesRoute() string {
   378  	return fmt.Sprintf("/roles")
   379  }
   380  
   381  func (c *Client4) GetSchemesRoute() string {
   382  	return fmt.Sprintf("/schemes")
   383  }
   384  
   385  func (c *Client4) GetSchemeRoute(id string) string {
   386  	return c.GetSchemesRoute() + fmt.Sprintf("/%v", id)
   387  }
   388  
   389  func (c *Client4) GetAnalyticsRoute() string {
   390  	return fmt.Sprintf("/analytics")
   391  }
   392  
   393  func (c *Client4) GetTimezonesRoute() string {
   394  	return fmt.Sprintf(c.GetSystemRoute() + "/timezones")
   395  }
   396  
   397  func (c *Client4) GetChannelSchemeRoute(channelId string) string {
   398  	return fmt.Sprintf(c.GetChannelsRoute()+"/%v/scheme", channelId)
   399  }
   400  
   401  func (c *Client4) GetTeamSchemeRoute(teamId string) string {
   402  	return fmt.Sprintf(c.GetTeamsRoute()+"/%v/scheme", teamId)
   403  }
   404  
   405  func (c *Client4) GetTotalUsersStatsRoute() string {
   406  	return fmt.Sprintf(c.GetUsersRoute() + "/stats")
   407  }
   408  
   409  func (c *Client4) GetRedirectLocationRoute() string {
   410  	return fmt.Sprintf("/redirect_location")
   411  }
   412  
   413  func (c *Client4) GetUserTermsOfServiceRoute(userId string) string {
   414  	return c.GetUserRoute(userId) + "/terms_of_service"
   415  }
   416  
   417  func (c *Client4) GetTermsOfServiceRoute() string {
   418  	return "/terms_of_service"
   419  }
   420  
   421  func (c *Client4) GetGroupsRoute() string {
   422  	return "/groups"
   423  }
   424  
   425  func (c *Client4) GetGroupRoute(groupID string) string {
   426  	return fmt.Sprintf("%s/%s", c.GetGroupsRoute(), groupID)
   427  }
   428  
   429  func (c *Client4) GetGroupSyncableRoute(groupID, syncableID string, syncableType GroupSyncableType) string {
   430  	return fmt.Sprintf("%s/%ss/%s", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String()), syncableID)
   431  }
   432  
   433  func (c *Client4) GetGroupSyncablesRoute(groupID string, syncableType GroupSyncableType) string {
   434  	return fmt.Sprintf("%s/%ss", c.GetGroupRoute(groupID), strings.ToLower(syncableType.String()))
   435  }
   436  
   437  func (c *Client4) DoApiGet(url string, etag string) (*http.Response, *AppError) {
   438  	return c.DoApiRequest(http.MethodGet, c.ApiUrl+url, "", etag)
   439  }
   440  
   441  func (c *Client4) DoApiPost(url string, data string) (*http.Response, *AppError) {
   442  	return c.DoApiRequest(http.MethodPost, c.ApiUrl+url, data, "")
   443  }
   444  
   445  func (c *Client4) doApiPostBytes(url string, data []byte) (*http.Response, *AppError) {
   446  	return c.doApiRequestBytes(http.MethodPost, c.ApiUrl+url, data, "")
   447  }
   448  
   449  func (c *Client4) DoApiPut(url string, data string) (*http.Response, *AppError) {
   450  	return c.DoApiRequest(http.MethodPut, c.ApiUrl+url, data, "")
   451  }
   452  
   453  func (c *Client4) doApiPutBytes(url string, data []byte) (*http.Response, *AppError) {
   454  	return c.doApiRequestBytes(http.MethodPut, c.ApiUrl+url, data, "")
   455  }
   456  
   457  func (c *Client4) DoApiDelete(url string) (*http.Response, *AppError) {
   458  	return c.DoApiRequest(http.MethodDelete, c.ApiUrl+url, "", "")
   459  }
   460  
   461  func (c *Client4) DoApiRequest(method, url, data, etag string) (*http.Response, *AppError) {
   462  	return c.doApiRequestReader(method, url, strings.NewReader(data), etag)
   463  }
   464  
   465  func (c *Client4) doApiRequestBytes(method, url string, data []byte, etag string) (*http.Response, *AppError) {
   466  	return c.doApiRequestReader(method, url, bytes.NewReader(data), etag)
   467  }
   468  
   469  func (c *Client4) doApiRequestReader(method, url string, data io.Reader, etag string) (*http.Response, *AppError) {
   470  	rq, err := http.NewRequest(method, url, data)
   471  	if err != nil {
   472  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)
   473  	}
   474  
   475  	if len(etag) > 0 {
   476  		rq.Header.Set(HEADER_ETAG_CLIENT, etag)
   477  	}
   478  
   479  	if len(c.AuthToken) > 0 {
   480  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   481  	}
   482  
   483  	if c.HttpHeader != nil && len(c.HttpHeader) > 0 {
   484  		for k, v := range c.HttpHeader {
   485  			rq.Header.Set(k, v)
   486  		}
   487  	}
   488  
   489  	rp, err := c.HttpClient.Do(rq)
   490  	if err != nil || rp == nil {
   491  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
   492  	}
   493  
   494  	if rp.StatusCode == 304 {
   495  		return rp, nil
   496  	}
   497  
   498  	if rp.StatusCode >= 300 {
   499  		defer closeBody(rp)
   500  		return rp, AppErrorFromJson(rp.Body)
   501  	}
   502  
   503  	return rp, nil
   504  }
   505  
   506  func (c *Client4) DoUploadFile(url string, data []byte, contentType string) (*FileUploadResponse, *Response) {
   507  	return c.doUploadFile(url, bytes.NewReader(data), contentType, 0)
   508  }
   509  
   510  func (c *Client4) doUploadFile(url string, body io.Reader, contentType string, contentLength int64) (*FileUploadResponse, *Response) {
   511  	rq, err := http.NewRequest("POST", c.ApiUrl+url, body)
   512  	if err != nil {
   513  		return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
   514  	}
   515  	if contentLength != 0 {
   516  		rq.ContentLength = contentLength
   517  	}
   518  	rq.Header.Set("Content-Type", contentType)
   519  
   520  	if len(c.AuthToken) > 0 {
   521  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   522  	}
   523  
   524  	rp, err := c.HttpClient.Do(rq)
   525  	if err != nil || rp == nil {
   526  		return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
   527  	}
   528  	defer closeBody(rp)
   529  
   530  	if rp.StatusCode >= 300 {
   531  		return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
   532  	}
   533  
   534  	return FileUploadResponseFromJson(rp.Body), BuildResponse(rp)
   535  }
   536  
   537  func (c *Client4) DoEmojiUploadFile(url string, data []byte, contentType string) (*Emoji, *Response) {
   538  	rq, err := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
   539  	if err != nil {
   540  		return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
   541  	}
   542  	rq.Header.Set("Content-Type", contentType)
   543  
   544  	if len(c.AuthToken) > 0 {
   545  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   546  	}
   547  
   548  	rp, err := c.HttpClient.Do(rq)
   549  	if err != nil || rp == nil {
   550  		return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
   551  	}
   552  	defer closeBody(rp)
   553  
   554  	if rp.StatusCode >= 300 {
   555  		return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
   556  	}
   557  
   558  	return EmojiFromJson(rp.Body), BuildResponse(rp)
   559  }
   560  
   561  func (c *Client4) DoUploadImportTeam(url string, data []byte, contentType string) (map[string]string, *Response) {
   562  	rq, err := http.NewRequest("POST", c.ApiUrl+url, bytes.NewReader(data))
   563  	if err != nil {
   564  		return nil, &Response{Error: NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
   565  	}
   566  	rq.Header.Set("Content-Type", contentType)
   567  
   568  	if len(c.AuthToken) > 0 {
   569  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   570  	}
   571  
   572  	rp, err := c.HttpClient.Do(rq)
   573  	if err != nil || rp == nil {
   574  		return nil, BuildErrorResponse(rp, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0))
   575  	}
   576  	defer closeBody(rp)
   577  
   578  	if rp.StatusCode >= 300 {
   579  		return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
   580  	}
   581  
   582  	return MapFromJson(rp.Body), BuildResponse(rp)
   583  }
   584  
   585  // CheckStatusOK is a convenience function for checking the standard OK response
   586  // from the web service.
   587  func CheckStatusOK(r *http.Response) bool {
   588  	m := MapFromJson(r.Body)
   589  	defer closeBody(r)
   590  
   591  	if m != nil && m[STATUS] == STATUS_OK {
   592  		return true
   593  	}
   594  
   595  	return false
   596  }
   597  
   598  // Authentication Section
   599  
   600  // LoginById authenticates a user by user id and password.
   601  func (c *Client4) LoginById(id string, password string) (*User, *Response) {
   602  	m := make(map[string]string)
   603  	m["id"] = id
   604  	m["password"] = password
   605  	return c.login(m)
   606  }
   607  
   608  // Login authenticates a user by login id, which can be username, email or some sort
   609  // of SSO identifier based on server configuration, and a password.
   610  func (c *Client4) Login(loginId string, password string) (*User, *Response) {
   611  	m := make(map[string]string)
   612  	m["login_id"] = loginId
   613  	m["password"] = password
   614  	return c.login(m)
   615  }
   616  
   617  // LoginByLdap authenticates a user by LDAP id and password.
   618  func (c *Client4) LoginByLdap(loginId string, password string) (*User, *Response) {
   619  	m := make(map[string]string)
   620  	m["login_id"] = loginId
   621  	m["password"] = password
   622  	m["ldap_only"] = "true"
   623  	return c.login(m)
   624  }
   625  
   626  // LoginWithDevice authenticates a user by login id (username, email or some sort
   627  // of SSO identifier based on configuration), password and attaches a device id to
   628  // the session.
   629  func (c *Client4) LoginWithDevice(loginId string, password string, deviceId string) (*User, *Response) {
   630  	m := make(map[string]string)
   631  	m["login_id"] = loginId
   632  	m["password"] = password
   633  	m["device_id"] = deviceId
   634  	return c.login(m)
   635  }
   636  
   637  // LoginWithMFA logs a user in with a MFA token
   638  func (c *Client4) LoginWithMFA(loginId, password, mfaToken string) (*User, *Response) {
   639  	m := make(map[string]string)
   640  	m["login_id"] = loginId
   641  	m["password"] = password
   642  	m["token"] = mfaToken
   643  	return c.login(m)
   644  }
   645  
   646  func (c *Client4) login(m map[string]string) (*User, *Response) {
   647  	r, err := c.DoApiPost("/users/login", MapToJson(m))
   648  	if err != nil {
   649  		return nil, BuildErrorResponse(r, err)
   650  	}
   651  	defer closeBody(r)
   652  	c.AuthToken = r.Header.Get(HEADER_TOKEN)
   653  	c.AuthType = HEADER_BEARER
   654  	return UserFromJson(r.Body), BuildResponse(r)
   655  }
   656  
   657  // Logout terminates the current user's session.
   658  func (c *Client4) Logout() (bool, *Response) {
   659  	r, err := c.DoApiPost("/users/logout", "")
   660  	if err != nil {
   661  		return false, BuildErrorResponse(r, err)
   662  	}
   663  	defer closeBody(r)
   664  	c.AuthToken = ""
   665  	c.AuthType = HEADER_BEARER
   666  	return CheckStatusOK(r), BuildResponse(r)
   667  }
   668  
   669  // SwitchAccountType changes a user's login type from one type to another.
   670  func (c *Client4) SwitchAccountType(switchRequest *SwitchRequest) (string, *Response) {
   671  	r, err := c.DoApiPost(c.GetUsersRoute()+"/login/switch", switchRequest.ToJson())
   672  	if err != nil {
   673  		return "", BuildErrorResponse(r, err)
   674  	}
   675  	defer closeBody(r)
   676  	return MapFromJson(r.Body)["follow_link"], BuildResponse(r)
   677  }
   678  
   679  // User Section
   680  
   681  // CreateUser creates a user in the system based on the provided user struct.
   682  func (c *Client4) CreateUser(user *User) (*User, *Response) {
   683  	r, err := c.DoApiPost(c.GetUsersRoute(), user.ToJson())
   684  	if err != nil {
   685  		return nil, BuildErrorResponse(r, err)
   686  	}
   687  	defer closeBody(r)
   688  	return UserFromJson(r.Body), BuildResponse(r)
   689  }
   690  
   691  // CreateUserWithToken creates a user in the system based on the provided tokenId.
   692  func (c *Client4) CreateUserWithToken(user *User, tokenId string) (*User, *Response) {
   693  	if tokenId == "" {
   694  		err := NewAppError("MissingHashOrData", "api.user.create_user.missing_token.app_error", nil, "", http.StatusBadRequest)
   695  		return nil, &Response{StatusCode: err.StatusCode, Error: err}
   696  	}
   697  
   698  	query := fmt.Sprintf("?t=%v", tokenId)
   699  	r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson())
   700  	if err != nil {
   701  		return nil, BuildErrorResponse(r, err)
   702  	}
   703  	defer closeBody(r)
   704  
   705  	return UserFromJson(r.Body), BuildResponse(r)
   706  }
   707  
   708  // CreateUserWithInviteId creates a user in the system based on the provided invited id.
   709  func (c *Client4) CreateUserWithInviteId(user *User, inviteId string) (*User, *Response) {
   710  	if inviteId == "" {
   711  		err := NewAppError("MissingInviteId", "api.user.create_user.missing_invite_id.app_error", nil, "", http.StatusBadRequest)
   712  		return nil, &Response{StatusCode: err.StatusCode, Error: err}
   713  	}
   714  
   715  	query := fmt.Sprintf("?iid=%v", url.QueryEscape(inviteId))
   716  	r, err := c.DoApiPost(c.GetUsersRoute()+query, user.ToJson())
   717  	if err != nil {
   718  		return nil, BuildErrorResponse(r, err)
   719  	}
   720  	defer closeBody(r)
   721  
   722  	return UserFromJson(r.Body), BuildResponse(r)
   723  }
   724  
   725  // GetMe returns the logged in user.
   726  func (c *Client4) GetMe(etag string) (*User, *Response) {
   727  	r, err := c.DoApiGet(c.GetUserRoute(ME), etag)
   728  	if err != nil {
   729  		return nil, BuildErrorResponse(r, err)
   730  	}
   731  	defer closeBody(r)
   732  	return UserFromJson(r.Body), BuildResponse(r)
   733  }
   734  
   735  // GetUser returns a user based on the provided user id string.
   736  func (c *Client4) GetUser(userId, etag string) (*User, *Response) {
   737  	r, err := c.DoApiGet(c.GetUserRoute(userId), etag)
   738  	if err != nil {
   739  		return nil, BuildErrorResponse(r, err)
   740  	}
   741  	defer closeBody(r)
   742  	return UserFromJson(r.Body), BuildResponse(r)
   743  }
   744  
   745  // GetUserByUsername returns a user based on the provided user name string.
   746  func (c *Client4) GetUserByUsername(userName, etag string) (*User, *Response) {
   747  	r, err := c.DoApiGet(c.GetUserByUsernameRoute(userName), etag)
   748  	if err != nil {
   749  		return nil, BuildErrorResponse(r, err)
   750  	}
   751  	defer closeBody(r)
   752  	return UserFromJson(r.Body), BuildResponse(r)
   753  }
   754  
   755  // GetUserByEmail returns a user based on the provided user email string.
   756  func (c *Client4) GetUserByEmail(email, etag string) (*User, *Response) {
   757  	r, err := c.DoApiGet(c.GetUserByEmailRoute(email), etag)
   758  	if err != nil {
   759  		return nil, BuildErrorResponse(r, err)
   760  	}
   761  	defer closeBody(r)
   762  	return UserFromJson(r.Body), BuildResponse(r)
   763  }
   764  
   765  // AutocompleteUsersInTeam returns the users on a team based on search term.
   766  func (c *Client4) AutocompleteUsersInTeam(teamId string, username string, limit int, etag string) (*UserAutocomplete, *Response) {
   767  	query := fmt.Sprintf("?in_team=%v&name=%v&limit=%d", teamId, username, limit)
   768  	r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag)
   769  	if err != nil {
   770  		return nil, BuildErrorResponse(r, err)
   771  	}
   772  	defer closeBody(r)
   773  	return UserAutocompleteFromJson(r.Body), BuildResponse(r)
   774  }
   775  
   776  // AutocompleteUsersInChannel returns the users in a channel based on search term.
   777  func (c *Client4) AutocompleteUsersInChannel(teamId string, channelId string, username string, limit int, etag string) (*UserAutocomplete, *Response) {
   778  	query := fmt.Sprintf("?in_team=%v&in_channel=%v&name=%v&limit=%d", teamId, channelId, username, limit)
   779  	r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag)
   780  	if err != nil {
   781  		return nil, BuildErrorResponse(r, err)
   782  	}
   783  	defer closeBody(r)
   784  	return UserAutocompleteFromJson(r.Body), BuildResponse(r)
   785  }
   786  
   787  // AutocompleteUsers returns the users in the system based on search term.
   788  func (c *Client4) AutocompleteUsers(username string, limit int, etag string) (*UserAutocomplete, *Response) {
   789  	query := fmt.Sprintf("?name=%v&limit=%d", username, limit)
   790  	r, err := c.DoApiGet(c.GetUsersRoute()+"/autocomplete"+query, etag)
   791  	if err != nil {
   792  		return nil, BuildErrorResponse(r, err)
   793  	}
   794  	defer closeBody(r)
   795  	return UserAutocompleteFromJson(r.Body), BuildResponse(r)
   796  }
   797  
   798  // GetDefaultProfileImage gets the default user's profile image. Must be logged in.
   799  func (c *Client4) GetDefaultProfileImage(userId string) ([]byte, *Response) {
   800  	r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image/default", "")
   801  	if appErr != nil {
   802  		return nil, BuildErrorResponse(r, appErr)
   803  	}
   804  	defer closeBody(r)
   805  
   806  	data, err := ioutil.ReadAll(r.Body)
   807  	if err != nil {
   808  		return nil, BuildErrorResponse(r, NewAppError("GetDefaultProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
   809  	}
   810  
   811  	return data, BuildResponse(r)
   812  }
   813  
   814  // GetProfileImage gets user's profile image. Must be logged in.
   815  func (c *Client4) GetProfileImage(userId, etag string) ([]byte, *Response) {
   816  	r, appErr := c.DoApiGet(c.GetUserRoute(userId)+"/image", etag)
   817  	if appErr != nil {
   818  		return nil, BuildErrorResponse(r, appErr)
   819  	}
   820  	defer closeBody(r)
   821  
   822  	data, err := ioutil.ReadAll(r.Body)
   823  	if err != nil {
   824  		return nil, BuildErrorResponse(r, NewAppError("GetProfileImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
   825  	}
   826  	return data, BuildResponse(r)
   827  }
   828  
   829  // GetUsers returns a page of users on the system. Page counting starts at 0.
   830  func (c *Client4) GetUsers(page int, perPage int, etag string) ([]*User, *Response) {
   831  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
   832  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   833  	if err != nil {
   834  		return nil, BuildErrorResponse(r, err)
   835  	}
   836  	defer closeBody(r)
   837  	return UserListFromJson(r.Body), BuildResponse(r)
   838  }
   839  
   840  // GetUsersInTeam returns a page of users on a team. Page counting starts at 0.
   841  func (c *Client4) GetUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   842  	query := fmt.Sprintf("?in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   843  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   844  	if err != nil {
   845  		return nil, BuildErrorResponse(r, err)
   846  	}
   847  	defer closeBody(r)
   848  	return UserListFromJson(r.Body), BuildResponse(r)
   849  }
   850  
   851  // GetNewUsersInTeam returns a page of users on a team. Page counting starts at 0.
   852  func (c *Client4) GetNewUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   853  	query := fmt.Sprintf("?sort=create_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   854  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   855  	if err != nil {
   856  		return nil, BuildErrorResponse(r, err)
   857  	}
   858  	defer closeBody(r)
   859  	return UserListFromJson(r.Body), BuildResponse(r)
   860  }
   861  
   862  // GetRecentlyActiveUsersInTeam returns a page of users on a team. Page counting starts at 0.
   863  func (c *Client4) GetRecentlyActiveUsersInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   864  	query := fmt.Sprintf("?sort=last_activity_at&in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   865  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   866  	if err != nil {
   867  		return nil, BuildErrorResponse(r, err)
   868  	}
   869  	defer closeBody(r)
   870  	return UserListFromJson(r.Body), BuildResponse(r)
   871  }
   872  
   873  // GetUsersNotInTeam returns a page of users who are not in a team. Page counting starts at 0.
   874  func (c *Client4) GetUsersNotInTeam(teamId string, page int, perPage int, etag string) ([]*User, *Response) {
   875  	query := fmt.Sprintf("?not_in_team=%v&page=%v&per_page=%v", teamId, page, perPage)
   876  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   877  	if err != nil {
   878  		return nil, BuildErrorResponse(r, err)
   879  	}
   880  	defer closeBody(r)
   881  	return UserListFromJson(r.Body), BuildResponse(r)
   882  }
   883  
   884  // GetUsersInChannel returns a page of users in a channel. Page counting starts at 0.
   885  func (c *Client4) GetUsersInChannel(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
   886  	query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v", channelId, page, perPage)
   887  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   888  	if err != nil {
   889  		return nil, BuildErrorResponse(r, err)
   890  	}
   891  	defer closeBody(r)
   892  	return UserListFromJson(r.Body), BuildResponse(r)
   893  }
   894  
   895  // GetUsersInChannelByStatus returns a page of users in a channel. Page counting starts at 0. Sorted by Status
   896  func (c *Client4) GetUsersInChannelByStatus(channelId string, page int, perPage int, etag string) ([]*User, *Response) {
   897  	query := fmt.Sprintf("?in_channel=%v&page=%v&per_page=%v&sort=status", channelId, page, perPage)
   898  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   899  	if err != nil {
   900  		return nil, BuildErrorResponse(r, err)
   901  	}
   902  	defer closeBody(r)
   903  	return UserListFromJson(r.Body), BuildResponse(r)
   904  }
   905  
   906  // GetUsersNotInChannel returns a page of users not in a channel. Page counting starts at 0.
   907  func (c *Client4) GetUsersNotInChannel(teamId, channelId string, page int, perPage int, etag string) ([]*User, *Response) {
   908  	query := fmt.Sprintf("?in_team=%v&not_in_channel=%v&page=%v&per_page=%v", teamId, channelId, page, perPage)
   909  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   910  	if err != nil {
   911  		return nil, BuildErrorResponse(r, err)
   912  	}
   913  	defer closeBody(r)
   914  	return UserListFromJson(r.Body), BuildResponse(r)
   915  }
   916  
   917  // GetUsersWithoutTeam returns a page of users on the system that aren't on any teams. Page counting starts at 0.
   918  func (c *Client4) GetUsersWithoutTeam(page int, perPage int, etag string) ([]*User, *Response) {
   919  	query := fmt.Sprintf("?without_team=1&page=%v&per_page=%v", page, perPage)
   920  	r, err := c.DoApiGet(c.GetUsersRoute()+query, etag)
   921  	if err != nil {
   922  		return nil, BuildErrorResponse(r, err)
   923  	}
   924  	defer closeBody(r)
   925  	return UserListFromJson(r.Body), BuildResponse(r)
   926  }
   927  
   928  // GetUsersByIds returns a list of users based on the provided user ids.
   929  func (c *Client4) GetUsersByIds(userIds []string) ([]*User, *Response) {
   930  	r, err := c.DoApiPost(c.GetUsersRoute()+"/ids", ArrayToJson(userIds))
   931  	if err != nil {
   932  		return nil, BuildErrorResponse(r, err)
   933  	}
   934  	defer closeBody(r)
   935  	return UserListFromJson(r.Body), BuildResponse(r)
   936  }
   937  
   938  // GetUsersByUsernames returns a list of users based on the provided usernames.
   939  func (c *Client4) GetUsersByUsernames(usernames []string) ([]*User, *Response) {
   940  	r, err := c.DoApiPost(c.GetUsersRoute()+"/usernames", ArrayToJson(usernames))
   941  	if err != nil {
   942  		return nil, BuildErrorResponse(r, err)
   943  	}
   944  	defer closeBody(r)
   945  	return UserListFromJson(r.Body), BuildResponse(r)
   946  }
   947  
   948  // SearchUsers returns a list of users based on some search criteria.
   949  func (c *Client4) SearchUsers(search *UserSearch) ([]*User, *Response) {
   950  	r, err := c.doApiPostBytes(c.GetUsersRoute()+"/search", search.ToJson())
   951  	if err != nil {
   952  		return nil, BuildErrorResponse(r, err)
   953  	}
   954  	defer closeBody(r)
   955  	return UserListFromJson(r.Body), BuildResponse(r)
   956  }
   957  
   958  // UpdateUser updates a user in the system based on the provided user struct.
   959  func (c *Client4) UpdateUser(user *User) (*User, *Response) {
   960  	r, err := c.DoApiPut(c.GetUserRoute(user.Id), user.ToJson())
   961  	if err != nil {
   962  		return nil, BuildErrorResponse(r, err)
   963  	}
   964  	defer closeBody(r)
   965  	return UserFromJson(r.Body), BuildResponse(r)
   966  }
   967  
   968  // PatchUser partially updates a user in the system. Any missing fields are not updated.
   969  func (c *Client4) PatchUser(userId string, patch *UserPatch) (*User, *Response) {
   970  	r, err := c.DoApiPut(c.GetUserRoute(userId)+"/patch", patch.ToJson())
   971  	if err != nil {
   972  		return nil, BuildErrorResponse(r, err)
   973  	}
   974  	defer closeBody(r)
   975  	return UserFromJson(r.Body), BuildResponse(r)
   976  }
   977  
   978  // UpdateUserAuth updates a user AuthData (uthData, authService and password) in the system.
   979  func (c *Client4) UpdateUserAuth(userId string, userAuth *UserAuth) (*UserAuth, *Response) {
   980  	r, err := c.DoApiPut(c.GetUserRoute(userId)+"/auth", userAuth.ToJson())
   981  	if err != nil {
   982  		return nil, BuildErrorResponse(r, err)
   983  	}
   984  	defer closeBody(r)
   985  	return UserAuthFromJson(r.Body), BuildResponse(r)
   986  }
   987  
   988  // UpdateUserMfa activates multi-factor authentication for a user if activate
   989  // is true and a valid code is provided. If activate is false, then code is not
   990  // required and multi-factor authentication is disabled for the user.
   991  func (c *Client4) UpdateUserMfa(userId, code string, activate bool) (bool, *Response) {
   992  	requestBody := make(map[string]interface{})
   993  	requestBody["activate"] = activate
   994  	requestBody["code"] = code
   995  
   996  	r, err := c.DoApiPut(c.GetUserRoute(userId)+"/mfa", StringInterfaceToJson(requestBody))
   997  	if err != nil {
   998  		return false, BuildErrorResponse(r, err)
   999  	}
  1000  	defer closeBody(r)
  1001  	return CheckStatusOK(r), BuildResponse(r)
  1002  }
  1003  
  1004  // CheckUserMfa checks whether a user has MFA active on their account or not based on the
  1005  // provided login id.
  1006  // Deprecated: Clients should use Login method and check for MFA Error
  1007  func (c *Client4) CheckUserMfa(loginId string) (bool, *Response) {
  1008  	requestBody := make(map[string]interface{})
  1009  	requestBody["login_id"] = loginId
  1010  	r, err := c.DoApiPost(c.GetUsersRoute()+"/mfa", StringInterfaceToJson(requestBody))
  1011  	if err != nil {
  1012  		return false, BuildErrorResponse(r, err)
  1013  	}
  1014  	defer closeBody(r)
  1015  
  1016  	data := StringInterfaceFromJson(r.Body)
  1017  	mfaRequired, ok := data["mfa_required"].(bool)
  1018  	if !ok {
  1019  		return false, BuildResponse(r)
  1020  	}
  1021  	return mfaRequired, BuildResponse(r)
  1022  }
  1023  
  1024  // GenerateMfaSecret will generate a new MFA secret for a user and return it as a string and
  1025  // as a base64 encoded image QR code.
  1026  func (c *Client4) GenerateMfaSecret(userId string) (*MfaSecret, *Response) {
  1027  	r, err := c.DoApiPost(c.GetUserRoute(userId)+"/mfa/generate", "")
  1028  	if err != nil {
  1029  		return nil, BuildErrorResponse(r, err)
  1030  	}
  1031  	defer closeBody(r)
  1032  	return MfaSecretFromJson(r.Body), BuildResponse(r)
  1033  }
  1034  
  1035  // UpdateUserPassword updates a user's password. Must be logged in as the user or be a system administrator.
  1036  func (c *Client4) UpdateUserPassword(userId, currentPassword, newPassword string) (bool, *Response) {
  1037  	requestBody := map[string]string{"current_password": currentPassword, "new_password": newPassword}
  1038  	r, err := c.DoApiPut(c.GetUserRoute(userId)+"/password", MapToJson(requestBody))
  1039  	if err != nil {
  1040  		return false, BuildErrorResponse(r, err)
  1041  	}
  1042  	defer closeBody(r)
  1043  	return CheckStatusOK(r), BuildResponse(r)
  1044  }
  1045  
  1046  // UpdateUserRoles updates a user's roles in the system. A user can have "system_user" and "system_admin" roles.
  1047  func (c *Client4) UpdateUserRoles(userId, roles string) (bool, *Response) {
  1048  	requestBody := map[string]string{"roles": roles}
  1049  	r, err := c.DoApiPut(c.GetUserRoute(userId)+"/roles", MapToJson(requestBody))
  1050  	if err != nil {
  1051  		return false, BuildErrorResponse(r, err)
  1052  	}
  1053  	defer closeBody(r)
  1054  	return CheckStatusOK(r), BuildResponse(r)
  1055  }
  1056  
  1057  // UpdateUserActive updates status of a user whether active or not.
  1058  func (c *Client4) UpdateUserActive(userId string, active bool) (bool, *Response) {
  1059  	requestBody := make(map[string]interface{})
  1060  	requestBody["active"] = active
  1061  	r, err := c.DoApiPut(c.GetUserRoute(userId)+"/active", StringInterfaceToJson(requestBody))
  1062  	if err != nil {
  1063  		return false, BuildErrorResponse(r, err)
  1064  	}
  1065  	defer closeBody(r)
  1066  
  1067  	return CheckStatusOK(r), BuildResponse(r)
  1068  }
  1069  
  1070  // DeleteUser deactivates a user in the system based on the provided user id string.
  1071  func (c *Client4) DeleteUser(userId string) (bool, *Response) {
  1072  	r, err := c.DoApiDelete(c.GetUserRoute(userId))
  1073  	if err != nil {
  1074  		return false, BuildErrorResponse(r, err)
  1075  	}
  1076  	defer closeBody(r)
  1077  	return CheckStatusOK(r), BuildResponse(r)
  1078  }
  1079  
  1080  // SendPasswordResetEmail will send a link for password resetting to a user with the
  1081  // provided email.
  1082  func (c *Client4) SendPasswordResetEmail(email string) (bool, *Response) {
  1083  	requestBody := map[string]string{"email": email}
  1084  	r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset/send", MapToJson(requestBody))
  1085  	if err != nil {
  1086  		return false, BuildErrorResponse(r, err)
  1087  	}
  1088  	defer closeBody(r)
  1089  	return CheckStatusOK(r), BuildResponse(r)
  1090  }
  1091  
  1092  // ResetPassword uses a recovery code to update reset a user's password.
  1093  func (c *Client4) ResetPassword(token, newPassword string) (bool, *Response) {
  1094  	requestBody := map[string]string{"token": token, "new_password": newPassword}
  1095  	r, err := c.DoApiPost(c.GetUsersRoute()+"/password/reset", MapToJson(requestBody))
  1096  	if err != nil {
  1097  		return false, BuildErrorResponse(r, err)
  1098  	}
  1099  	defer closeBody(r)
  1100  	return CheckStatusOK(r), BuildResponse(r)
  1101  }
  1102  
  1103  // GetSessions returns a list of sessions based on the provided user id string.
  1104  func (c *Client4) GetSessions(userId, etag string) ([]*Session, *Response) {
  1105  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/sessions", etag)
  1106  	if err != nil {
  1107  		return nil, BuildErrorResponse(r, err)
  1108  	}
  1109  	defer closeBody(r)
  1110  	return SessionsFromJson(r.Body), BuildResponse(r)
  1111  }
  1112  
  1113  // RevokeSession revokes a user session based on the provided user id and session id strings.
  1114  func (c *Client4) RevokeSession(userId, sessionId string) (bool, *Response) {
  1115  	requestBody := map[string]string{"session_id": sessionId}
  1116  	r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke", MapToJson(requestBody))
  1117  	if err != nil {
  1118  		return false, BuildErrorResponse(r, err)
  1119  	}
  1120  	defer closeBody(r)
  1121  	return CheckStatusOK(r), BuildResponse(r)
  1122  }
  1123  
  1124  // RevokeAllSessions revokes all sessions for the provided user id string.
  1125  func (c *Client4) RevokeAllSessions(userId string) (bool, *Response) {
  1126  	r, err := c.DoApiPost(c.GetUserRoute(userId)+"/sessions/revoke/all", "")
  1127  	if err != nil {
  1128  		return false, BuildErrorResponse(r, err)
  1129  	}
  1130  	defer closeBody(r)
  1131  	return CheckStatusOK(r), BuildResponse(r)
  1132  }
  1133  
  1134  // AttachDeviceId attaches a mobile device ID to the current session.
  1135  func (c *Client4) AttachDeviceId(deviceId string) (bool, *Response) {
  1136  	requestBody := map[string]string{"device_id": deviceId}
  1137  	r, err := c.DoApiPut(c.GetUsersRoute()+"/sessions/device", MapToJson(requestBody))
  1138  	if err != nil {
  1139  		return false, BuildErrorResponse(r, err)
  1140  	}
  1141  	defer closeBody(r)
  1142  	return CheckStatusOK(r), BuildResponse(r)
  1143  }
  1144  
  1145  // GetTeamsUnreadForUser will return an array with TeamUnread objects that contain the amount
  1146  // of unread messages and mentions the current user has for the teams it belongs to.
  1147  // An optional team ID can be set to exclude that team from the results. Must be authenticated.
  1148  func (c *Client4) GetTeamsUnreadForUser(userId, teamIdToExclude string) ([]*TeamUnread, *Response) {
  1149  	var optional string
  1150  	if teamIdToExclude != "" {
  1151  		optional += fmt.Sprintf("?exclude_team=%s", url.QueryEscape(teamIdToExclude))
  1152  	}
  1153  
  1154  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/unread"+optional, "")
  1155  	if err != nil {
  1156  		return nil, BuildErrorResponse(r, err)
  1157  	}
  1158  	defer closeBody(r)
  1159  	return TeamsUnreadFromJson(r.Body), BuildResponse(r)
  1160  }
  1161  
  1162  // GetUserAudits returns a list of audit based on the provided user id string.
  1163  func (c *Client4) GetUserAudits(userId string, page int, perPage int, etag string) (Audits, *Response) {
  1164  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1165  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/audits"+query, etag)
  1166  	if err != nil {
  1167  		return nil, BuildErrorResponse(r, err)
  1168  	}
  1169  	defer closeBody(r)
  1170  	return AuditsFromJson(r.Body), BuildResponse(r)
  1171  }
  1172  
  1173  // VerifyUserEmail will verify a user's email using the supplied token.
  1174  func (c *Client4) VerifyUserEmail(token string) (bool, *Response) {
  1175  	requestBody := map[string]string{"token": token}
  1176  	r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify", MapToJson(requestBody))
  1177  	if err != nil {
  1178  		return false, BuildErrorResponse(r, err)
  1179  	}
  1180  	defer closeBody(r)
  1181  	return CheckStatusOK(r), BuildResponse(r)
  1182  }
  1183  
  1184  // SendVerificationEmail will send an email to the user with the provided email address, if
  1185  // that user exists. The email will contain a link that can be used to verify the user's
  1186  // email address.
  1187  func (c *Client4) SendVerificationEmail(email string) (bool, *Response) {
  1188  	requestBody := map[string]string{"email": email}
  1189  	r, err := c.DoApiPost(c.GetUsersRoute()+"/email/verify/send", MapToJson(requestBody))
  1190  	if err != nil {
  1191  		return false, BuildErrorResponse(r, err)
  1192  	}
  1193  	defer closeBody(r)
  1194  	return CheckStatusOK(r), BuildResponse(r)
  1195  }
  1196  
  1197  // SetDefaultProfileImage resets the profile image to a default generated one.
  1198  func (c *Client4) SetDefaultProfileImage(userId string) (bool, *Response) {
  1199  	r, err := c.DoApiDelete(c.GetUserRoute(userId) + "/image")
  1200  	if err != nil {
  1201  		return false, BuildErrorResponse(r, err)
  1202  	}
  1203  	return CheckStatusOK(r), BuildResponse(r)
  1204  }
  1205  
  1206  // SetProfileImage sets profile image of the user.
  1207  func (c *Client4) SetProfileImage(userId string, data []byte) (bool, *Response) {
  1208  	body := &bytes.Buffer{}
  1209  	writer := multipart.NewWriter(body)
  1210  
  1211  	part, err := writer.CreateFormFile("image", "profile.png")
  1212  	if err != nil {
  1213  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1214  	}
  1215  
  1216  	if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1217  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1218  	}
  1219  
  1220  	if err = writer.Close(); err != nil {
  1221  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1222  	}
  1223  
  1224  	rq, err := http.NewRequest("POST", c.ApiUrl+c.GetUserRoute(userId)+"/image", bytes.NewReader(body.Bytes()))
  1225  	if err != nil {
  1226  		return false, &Response{Error: NewAppError("SetProfileImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  1227  	}
  1228  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  1229  
  1230  	if len(c.AuthToken) > 0 {
  1231  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  1232  	}
  1233  
  1234  	rp, err := c.HttpClient.Do(rq)
  1235  	if err != nil || rp == nil {
  1236  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetUserRoute(userId)+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  1237  	}
  1238  	defer closeBody(rp)
  1239  
  1240  	if rp.StatusCode >= 300 {
  1241  		return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  1242  	}
  1243  
  1244  	return CheckStatusOK(rp), BuildResponse(rp)
  1245  }
  1246  
  1247  // CreateUserAccessToken will generate a user access token that can be used in place
  1248  // of a session token to access the REST API. Must have the 'create_user_access_token'
  1249  // permission and if generating for another user, must have the 'edit_other_users'
  1250  // permission. A non-blank description is required.
  1251  func (c *Client4) CreateUserAccessToken(userId, description string) (*UserAccessToken, *Response) {
  1252  	requestBody := map[string]string{"description": description}
  1253  	r, err := c.DoApiPost(c.GetUserRoute(userId)+"/tokens", MapToJson(requestBody))
  1254  	if err != nil {
  1255  		return nil, BuildErrorResponse(r, err)
  1256  	}
  1257  	defer closeBody(r)
  1258  	return UserAccessTokenFromJson(r.Body), BuildResponse(r)
  1259  }
  1260  
  1261  // GetUserAccessTokens will get a page of access tokens' id, description, is_active
  1262  // and the user_id in the system. The actual token will not be returned. Must have
  1263  // the 'manage_system' permission.
  1264  func (c *Client4) GetUserAccessTokens(page int, perPage int) ([]*UserAccessToken, *Response) {
  1265  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1266  	r, err := c.DoApiGet(c.GetUserAccessTokensRoute()+query, "")
  1267  	if err != nil {
  1268  		return nil, BuildErrorResponse(r, err)
  1269  	}
  1270  	defer closeBody(r)
  1271  	return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
  1272  }
  1273  
  1274  // GetUserAccessToken will get a user access tokens' id, description, is_active
  1275  // and the user_id of the user it is for. The actual token will not be returned.
  1276  // Must have the 'read_user_access_token' permission and if getting for another
  1277  // user, must have the 'edit_other_users' permission.
  1278  func (c *Client4) GetUserAccessToken(tokenId string) (*UserAccessToken, *Response) {
  1279  	r, err := c.DoApiGet(c.GetUserAccessTokenRoute(tokenId), "")
  1280  	if err != nil {
  1281  		return nil, BuildErrorResponse(r, err)
  1282  	}
  1283  	defer closeBody(r)
  1284  	return UserAccessTokenFromJson(r.Body), BuildResponse(r)
  1285  }
  1286  
  1287  // GetUserAccessTokensForUser will get a paged list of user access tokens showing id,
  1288  // description and user_id for each. The actual tokens will not be returned. Must have
  1289  // the 'read_user_access_token' permission and if getting for another user, must have the
  1290  // 'edit_other_users' permission.
  1291  func (c *Client4) GetUserAccessTokensForUser(userId string, page, perPage int) ([]*UserAccessToken, *Response) {
  1292  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1293  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/tokens"+query, "")
  1294  	if err != nil {
  1295  		return nil, BuildErrorResponse(r, err)
  1296  	}
  1297  	defer closeBody(r)
  1298  	return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
  1299  }
  1300  
  1301  // RevokeUserAccessToken will revoke a user access token by id. Must have the
  1302  // 'revoke_user_access_token' permission and if revoking for another user, must have the
  1303  // 'edit_other_users' permission.
  1304  func (c *Client4) RevokeUserAccessToken(tokenId string) (bool, *Response) {
  1305  	requestBody := map[string]string{"token_id": tokenId}
  1306  	r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/revoke", MapToJson(requestBody))
  1307  	if err != nil {
  1308  		return false, BuildErrorResponse(r, err)
  1309  	}
  1310  	defer closeBody(r)
  1311  	return CheckStatusOK(r), BuildResponse(r)
  1312  }
  1313  
  1314  // SearchUserAccessTokens returns user access tokens matching the provided search term.
  1315  func (c *Client4) SearchUserAccessTokens(search *UserAccessTokenSearch) ([]*UserAccessToken, *Response) {
  1316  	r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/search", search.ToJson())
  1317  	if err != nil {
  1318  		return nil, BuildErrorResponse(r, err)
  1319  	}
  1320  	defer closeBody(r)
  1321  	return UserAccessTokenListFromJson(r.Body), BuildResponse(r)
  1322  }
  1323  
  1324  // DisableUserAccessToken will disable a user access token by id. Must have the
  1325  // 'revoke_user_access_token' permission and if disabling for another user, must have the
  1326  // 'edit_other_users' permission.
  1327  func (c *Client4) DisableUserAccessToken(tokenId string) (bool, *Response) {
  1328  	requestBody := map[string]string{"token_id": tokenId}
  1329  	r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/disable", MapToJson(requestBody))
  1330  	if err != nil {
  1331  		return false, BuildErrorResponse(r, err)
  1332  	}
  1333  	defer closeBody(r)
  1334  	return CheckStatusOK(r), BuildResponse(r)
  1335  }
  1336  
  1337  // EnableUserAccessToken will enable a user access token by id. Must have the
  1338  // 'create_user_access_token' permission and if enabling for another user, must have the
  1339  // 'edit_other_users' permission.
  1340  func (c *Client4) EnableUserAccessToken(tokenId string) (bool, *Response) {
  1341  	requestBody := map[string]string{"token_id": tokenId}
  1342  	r, err := c.DoApiPost(c.GetUsersRoute()+"/tokens/enable", MapToJson(requestBody))
  1343  	if err != nil {
  1344  		return false, BuildErrorResponse(r, err)
  1345  	}
  1346  	defer closeBody(r)
  1347  	return CheckStatusOK(r), BuildResponse(r)
  1348  }
  1349  
  1350  // Bots section
  1351  
  1352  // CreateBot creates a bot in the system based on the provided bot struct.
  1353  func (c *Client4) CreateBot(bot *Bot) (*Bot, *Response) {
  1354  	r, err := c.doApiPostBytes(c.GetBotsRoute(), bot.ToJson())
  1355  	if err != nil {
  1356  		return nil, BuildErrorResponse(r, err)
  1357  	}
  1358  	defer closeBody(r)
  1359  	return BotFromJson(r.Body), BuildResponse(r)
  1360  }
  1361  
  1362  // PatchBot partially updates a bot. Any missing fields are not updated.
  1363  func (c *Client4) PatchBot(userId string, patch *BotPatch) (*Bot, *Response) {
  1364  	r, err := c.doApiPutBytes(c.GetBotRoute(userId), patch.ToJson())
  1365  	if err != nil {
  1366  		return nil, BuildErrorResponse(r, err)
  1367  	}
  1368  	defer closeBody(r)
  1369  	return BotFromJson(r.Body), BuildResponse(r)
  1370  }
  1371  
  1372  // GetBot fetches the given, undeleted bot.
  1373  func (c *Client4) GetBot(userId string, etag string) (*Bot, *Response) {
  1374  	r, err := c.DoApiGet(c.GetBotRoute(userId), etag)
  1375  	if err != nil {
  1376  		return nil, BuildErrorResponse(r, err)
  1377  	}
  1378  	defer closeBody(r)
  1379  	return BotFromJson(r.Body), BuildResponse(r)
  1380  }
  1381  
  1382  // GetBot fetches the given bot, even if it is deleted.
  1383  func (c *Client4) GetBotIncludeDeleted(userId string, etag string) (*Bot, *Response) {
  1384  	r, err := c.DoApiGet(c.GetBotRoute(userId)+"?include_deleted=true", etag)
  1385  	if err != nil {
  1386  		return nil, BuildErrorResponse(r, err)
  1387  	}
  1388  	defer closeBody(r)
  1389  	return BotFromJson(r.Body), BuildResponse(r)
  1390  }
  1391  
  1392  // GetBots fetches the given page of bots, excluding deleted.
  1393  func (c *Client4) GetBots(page, perPage int, etag string) ([]*Bot, *Response) {
  1394  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1395  	r, err := c.DoApiGet(c.GetBotsRoute()+query, etag)
  1396  	if err != nil {
  1397  		return nil, BuildErrorResponse(r, err)
  1398  	}
  1399  	defer closeBody(r)
  1400  	return BotListFromJson(r.Body), BuildResponse(r)
  1401  }
  1402  
  1403  // GetBotsIncludeDeleted fetches the given page of bots, including deleted.
  1404  func (c *Client4) GetBotsIncludeDeleted(page, perPage int, etag string) ([]*Bot, *Response) {
  1405  	query := fmt.Sprintf("?page=%v&per_page=%v&include_deleted=true", page, perPage)
  1406  	r, err := c.DoApiGet(c.GetBotsRoute()+query, etag)
  1407  	if err != nil {
  1408  		return nil, BuildErrorResponse(r, err)
  1409  	}
  1410  	defer closeBody(r)
  1411  	return BotListFromJson(r.Body), BuildResponse(r)
  1412  }
  1413  
  1414  // GetBotsOrphaned fetches the given page of bots, only including orphanded bots.
  1415  func (c *Client4) GetBotsOrphaned(page, perPage int, etag string) ([]*Bot, *Response) {
  1416  	query := fmt.Sprintf("?page=%v&per_page=%v&only_orphaned=true", page, perPage)
  1417  	r, err := c.DoApiGet(c.GetBotsRoute()+query, etag)
  1418  	if err != nil {
  1419  		return nil, BuildErrorResponse(r, err)
  1420  	}
  1421  	defer closeBody(r)
  1422  	return BotListFromJson(r.Body), BuildResponse(r)
  1423  }
  1424  
  1425  // DisableBot disables the given bot in the system.
  1426  func (c *Client4) DisableBot(botUserId string) (*Bot, *Response) {
  1427  	r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/disable", nil)
  1428  	if err != nil {
  1429  		return nil, BuildErrorResponse(r, err)
  1430  	}
  1431  	defer closeBody(r)
  1432  	return BotFromJson(r.Body), BuildResponse(r)
  1433  }
  1434  
  1435  // EnableBot disables the given bot in the system.
  1436  func (c *Client4) EnableBot(botUserId string) (*Bot, *Response) {
  1437  	r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/enable", nil)
  1438  	if err != nil {
  1439  		return nil, BuildErrorResponse(r, err)
  1440  	}
  1441  	defer closeBody(r)
  1442  	return BotFromJson(r.Body), BuildResponse(r)
  1443  }
  1444  
  1445  // AssignBot assigns the given bot to the given user
  1446  func (c *Client4) AssignBot(botUserId, newOwnerId string) (*Bot, *Response) {
  1447  	r, err := c.doApiPostBytes(c.GetBotRoute(botUserId)+"/assign/"+newOwnerId, nil)
  1448  	if err != nil {
  1449  		return nil, BuildErrorResponse(r, err)
  1450  	}
  1451  	defer closeBody(r)
  1452  	return BotFromJson(r.Body), BuildResponse(r)
  1453  }
  1454  
  1455  // Team Section
  1456  
  1457  // CreateTeam creates a team in the system based on the provided team struct.
  1458  func (c *Client4) CreateTeam(team *Team) (*Team, *Response) {
  1459  	r, err := c.DoApiPost(c.GetTeamsRoute(), team.ToJson())
  1460  	if err != nil {
  1461  		return nil, BuildErrorResponse(r, err)
  1462  	}
  1463  	defer closeBody(r)
  1464  	return TeamFromJson(r.Body), BuildResponse(r)
  1465  }
  1466  
  1467  // GetTeam returns a team based on the provided team id string.
  1468  func (c *Client4) GetTeam(teamId, etag string) (*Team, *Response) {
  1469  	r, err := c.DoApiGet(c.GetTeamRoute(teamId), etag)
  1470  	if err != nil {
  1471  		return nil, BuildErrorResponse(r, err)
  1472  	}
  1473  	defer closeBody(r)
  1474  	return TeamFromJson(r.Body), BuildResponse(r)
  1475  }
  1476  
  1477  // GetAllTeams returns all teams based on permissions.
  1478  func (c *Client4) GetAllTeams(etag string, page int, perPage int) ([]*Team, *Response) {
  1479  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1480  	r, err := c.DoApiGet(c.GetTeamsRoute()+query, etag)
  1481  	if err != nil {
  1482  		return nil, BuildErrorResponse(r, err)
  1483  	}
  1484  	defer closeBody(r)
  1485  	return TeamListFromJson(r.Body), BuildResponse(r)
  1486  }
  1487  
  1488  // GetTeamByName returns a team based on the provided team name string.
  1489  func (c *Client4) GetTeamByName(name, etag string) (*Team, *Response) {
  1490  	r, err := c.DoApiGet(c.GetTeamByNameRoute(name), etag)
  1491  	if err != nil {
  1492  		return nil, BuildErrorResponse(r, err)
  1493  	}
  1494  	defer closeBody(r)
  1495  	return TeamFromJson(r.Body), BuildResponse(r)
  1496  }
  1497  
  1498  // SearchTeams returns teams matching the provided search term.
  1499  func (c *Client4) SearchTeams(search *TeamSearch) ([]*Team, *Response) {
  1500  	r, err := c.DoApiPost(c.GetTeamsRoute()+"/search", search.ToJson())
  1501  	if err != nil {
  1502  		return nil, BuildErrorResponse(r, err)
  1503  	}
  1504  	defer closeBody(r)
  1505  	return TeamListFromJson(r.Body), BuildResponse(r)
  1506  }
  1507  
  1508  // TeamExists returns true or false if the team exist or not.
  1509  func (c *Client4) TeamExists(name, etag string) (bool, *Response) {
  1510  	r, err := c.DoApiGet(c.GetTeamByNameRoute(name)+"/exists", etag)
  1511  	if err != nil {
  1512  		return false, BuildErrorResponse(r, err)
  1513  	}
  1514  	defer closeBody(r)
  1515  	return MapBoolFromJson(r.Body)["exists"], BuildResponse(r)
  1516  }
  1517  
  1518  // GetTeamsForUser returns a list of teams a user is on. Must be logged in as the user
  1519  // or be a system administrator.
  1520  func (c *Client4) GetTeamsForUser(userId, etag string) ([]*Team, *Response) {
  1521  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams", etag)
  1522  	if err != nil {
  1523  		return nil, BuildErrorResponse(r, err)
  1524  	}
  1525  	defer closeBody(r)
  1526  	return TeamListFromJson(r.Body), BuildResponse(r)
  1527  }
  1528  
  1529  // GetTeamMember returns a team member based on the provided team and user id strings.
  1530  func (c *Client4) GetTeamMember(teamId, userId, etag string) (*TeamMember, *Response) {
  1531  	r, err := c.DoApiGet(c.GetTeamMemberRoute(teamId, userId), etag)
  1532  	if err != nil {
  1533  		return nil, BuildErrorResponse(r, err)
  1534  	}
  1535  	defer closeBody(r)
  1536  	return TeamMemberFromJson(r.Body), BuildResponse(r)
  1537  }
  1538  
  1539  // UpdateTeamMemberRoles will update the roles on a team for a user.
  1540  func (c *Client4) UpdateTeamMemberRoles(teamId, userId, newRoles string) (bool, *Response) {
  1541  	requestBody := map[string]string{"roles": newRoles}
  1542  	r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/roles", MapToJson(requestBody))
  1543  	if err != nil {
  1544  		return false, BuildErrorResponse(r, err)
  1545  	}
  1546  	defer closeBody(r)
  1547  	return CheckStatusOK(r), BuildResponse(r)
  1548  }
  1549  
  1550  // UpdateTeamMemberSchemeRoles will update the scheme-derived roles on a team for a user.
  1551  func (c *Client4) UpdateTeamMemberSchemeRoles(teamId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) {
  1552  	r, err := c.DoApiPut(c.GetTeamMemberRoute(teamId, userId)+"/schemeRoles", schemeRoles.ToJson())
  1553  	if err != nil {
  1554  		return false, BuildErrorResponse(r, err)
  1555  	}
  1556  	defer closeBody(r)
  1557  	return CheckStatusOK(r), BuildResponse(r)
  1558  }
  1559  
  1560  // UpdateTeam will update a team.
  1561  func (c *Client4) UpdateTeam(team *Team) (*Team, *Response) {
  1562  	r, err := c.DoApiPut(c.GetTeamRoute(team.Id), team.ToJson())
  1563  	if err != nil {
  1564  		return nil, BuildErrorResponse(r, err)
  1565  	}
  1566  	defer closeBody(r)
  1567  	return TeamFromJson(r.Body), BuildResponse(r)
  1568  }
  1569  
  1570  // PatchTeam partially updates a team. Any missing fields are not updated.
  1571  func (c *Client4) PatchTeam(teamId string, patch *TeamPatch) (*Team, *Response) {
  1572  	r, err := c.DoApiPut(c.GetTeamRoute(teamId)+"/patch", patch.ToJson())
  1573  	if err != nil {
  1574  		return nil, BuildErrorResponse(r, err)
  1575  	}
  1576  	defer closeBody(r)
  1577  	return TeamFromJson(r.Body), BuildResponse(r)
  1578  }
  1579  
  1580  // RegenerateTeamInviteId requests a new invite ID to be generated.
  1581  func (c *Client4) RegenerateTeamInviteId(teamId string) (*Team, *Response) {
  1582  	r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/regenerate_invite_id", "")
  1583  	if err != nil {
  1584  		return nil, BuildErrorResponse(r, err)
  1585  	}
  1586  	defer closeBody(r)
  1587  	return TeamFromJson(r.Body), BuildResponse(r)
  1588  }
  1589  
  1590  // SoftDeleteTeam deletes the team softly (archive only, not permanent delete).
  1591  func (c *Client4) SoftDeleteTeam(teamId string) (bool, *Response) {
  1592  	r, err := c.DoApiDelete(c.GetTeamRoute(teamId))
  1593  	if err != nil {
  1594  		return false, BuildErrorResponse(r, err)
  1595  	}
  1596  	defer closeBody(r)
  1597  	return CheckStatusOK(r), BuildResponse(r)
  1598  }
  1599  
  1600  // PermanentDeleteTeam deletes the team, should only be used when needed for
  1601  // compliance and the like.
  1602  func (c *Client4) PermanentDeleteTeam(teamId string) (bool, *Response) {
  1603  	r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "?permanent=true")
  1604  	if err != nil {
  1605  		return false, BuildErrorResponse(r, err)
  1606  	}
  1607  	defer closeBody(r)
  1608  	return CheckStatusOK(r), BuildResponse(r)
  1609  }
  1610  
  1611  // GetTeamMembers returns team members based on the provided team id string.
  1612  func (c *Client4) GetTeamMembers(teamId string, page int, perPage int, etag string) ([]*TeamMember, *Response) {
  1613  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1614  	r, err := c.DoApiGet(c.GetTeamMembersRoute(teamId)+query, etag)
  1615  	if err != nil {
  1616  		return nil, BuildErrorResponse(r, err)
  1617  	}
  1618  	defer closeBody(r)
  1619  	return TeamMembersFromJson(r.Body), BuildResponse(r)
  1620  }
  1621  
  1622  // GetTeamMembersForUser returns the team members for a user.
  1623  func (c *Client4) GetTeamMembersForUser(userId string, etag string) ([]*TeamMember, *Response) {
  1624  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/teams/members", etag)
  1625  	if err != nil {
  1626  		return nil, BuildErrorResponse(r, err)
  1627  	}
  1628  	defer closeBody(r)
  1629  	return TeamMembersFromJson(r.Body), BuildResponse(r)
  1630  }
  1631  
  1632  // GetTeamMembersByIds will return an array of team members based on the
  1633  // team id and a list of user ids provided. Must be authenticated.
  1634  func (c *Client4) GetTeamMembersByIds(teamId string, userIds []string) ([]*TeamMember, *Response) {
  1635  	r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds))
  1636  	if err != nil {
  1637  		return nil, BuildErrorResponse(r, err)
  1638  	}
  1639  	defer closeBody(r)
  1640  	return TeamMembersFromJson(r.Body), BuildResponse(r)
  1641  }
  1642  
  1643  // AddTeamMember adds user to a team and return a team member.
  1644  func (c *Client4) AddTeamMember(teamId, userId string) (*TeamMember, *Response) {
  1645  	member := &TeamMember{TeamId: teamId, UserId: userId}
  1646  	r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId), member.ToJson())
  1647  	if err != nil {
  1648  		return nil, BuildErrorResponse(r, err)
  1649  	}
  1650  	defer closeBody(r)
  1651  	return TeamMemberFromJson(r.Body), BuildResponse(r)
  1652  }
  1653  
  1654  // AddTeamMemberFromInvite adds a user to a team and return a team member using an invite id
  1655  // or an invite token/data pair.
  1656  func (c *Client4) AddTeamMemberFromInvite(token, inviteId string) (*TeamMember, *Response) {
  1657  	var query string
  1658  
  1659  	if inviteId != "" {
  1660  		query += fmt.Sprintf("?invite_id=%v", inviteId)
  1661  	}
  1662  
  1663  	if token != "" {
  1664  		query += fmt.Sprintf("?token=%v", token)
  1665  	}
  1666  
  1667  	r, err := c.DoApiPost(c.GetTeamsRoute()+"/members/invite"+query, "")
  1668  	if err != nil {
  1669  		return nil, BuildErrorResponse(r, err)
  1670  	}
  1671  	defer closeBody(r)
  1672  	return TeamMemberFromJson(r.Body), BuildResponse(r)
  1673  }
  1674  
  1675  // AddTeamMembers adds a number of users to a team and returns the team members.
  1676  func (c *Client4) AddTeamMembers(teamId string, userIds []string) ([]*TeamMember, *Response) {
  1677  	var members []*TeamMember
  1678  	for _, userId := range userIds {
  1679  		member := &TeamMember{TeamId: teamId, UserId: userId}
  1680  		members = append(members, member)
  1681  	}
  1682  
  1683  	r, err := c.DoApiPost(c.GetTeamMembersRoute(teamId)+"/batch", TeamMembersToJson(members))
  1684  	if err != nil {
  1685  		return nil, BuildErrorResponse(r, err)
  1686  	}
  1687  	defer closeBody(r)
  1688  	return TeamMembersFromJson(r.Body), BuildResponse(r)
  1689  }
  1690  
  1691  // RemoveTeamMember will remove a user from a team.
  1692  func (c *Client4) RemoveTeamMember(teamId, userId string) (bool, *Response) {
  1693  	r, err := c.DoApiDelete(c.GetTeamMemberRoute(teamId, userId))
  1694  	if err != nil {
  1695  		return false, BuildErrorResponse(r, err)
  1696  	}
  1697  	defer closeBody(r)
  1698  	return CheckStatusOK(r), BuildResponse(r)
  1699  }
  1700  
  1701  // GetTeamStats returns a team stats based on the team id string.
  1702  // Must be authenticated.
  1703  func (c *Client4) GetTeamStats(teamId, etag string) (*TeamStats, *Response) {
  1704  	r, err := c.DoApiGet(c.GetTeamStatsRoute(teamId), etag)
  1705  	if err != nil {
  1706  		return nil, BuildErrorResponse(r, err)
  1707  	}
  1708  	defer closeBody(r)
  1709  	return TeamStatsFromJson(r.Body), BuildResponse(r)
  1710  }
  1711  
  1712  // GetTotalUsersStats returns a total system user stats.
  1713  // Must be authenticated.
  1714  func (c *Client4) GetTotalUsersStats(etag string) (*UsersStats, *Response) {
  1715  	r, err := c.DoApiGet(c.GetTotalUsersStatsRoute(), etag)
  1716  	if err != nil {
  1717  		return nil, BuildErrorResponse(r, err)
  1718  	}
  1719  	defer closeBody(r)
  1720  	return UsersStatsFromJson(r.Body), BuildResponse(r)
  1721  }
  1722  
  1723  // GetTeamUnread will return a TeamUnread object that contains the amount of
  1724  // unread messages and mentions the user has for the specified team.
  1725  // Must be authenticated.
  1726  func (c *Client4) GetTeamUnread(teamId, userId string) (*TeamUnread, *Response) {
  1727  	r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/unread", "")
  1728  	if err != nil {
  1729  		return nil, BuildErrorResponse(r, err)
  1730  	}
  1731  	defer closeBody(r)
  1732  	return TeamUnreadFromJson(r.Body), BuildResponse(r)
  1733  }
  1734  
  1735  // ImportTeam will import an exported team from other app into a existing team.
  1736  func (c *Client4) ImportTeam(data []byte, filesize int, importFrom, filename, teamId string) (map[string]string, *Response) {
  1737  	body := &bytes.Buffer{}
  1738  	writer := multipart.NewWriter(body)
  1739  
  1740  	part, err := writer.CreateFormFile("file", filename)
  1741  	if err != nil {
  1742  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1743  	}
  1744  
  1745  	if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1746  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1747  	}
  1748  
  1749  	part, err = writer.CreateFormField("filesize")
  1750  	if err != nil {
  1751  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
  1752  	}
  1753  
  1754  	if _, err = io.Copy(part, strings.NewReader(strconv.Itoa(filesize))); err != nil {
  1755  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.file_size.app_error", nil, err.Error(), http.StatusBadRequest)}
  1756  	}
  1757  
  1758  	part, err = writer.CreateFormField("importFrom")
  1759  	if err != nil {
  1760  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
  1761  	}
  1762  
  1763  	if _, err := io.Copy(part, strings.NewReader(importFrom)); err != nil {
  1764  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.import_from.app_error", nil, err.Error(), http.StatusBadRequest)}
  1765  	}
  1766  
  1767  	if err := writer.Close(); err != nil {
  1768  		return nil, &Response{Error: NewAppError("UploadImportTeam", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1769  	}
  1770  
  1771  	return c.DoUploadImportTeam(c.GetTeamImportRoute(teamId), body.Bytes(), writer.FormDataContentType())
  1772  }
  1773  
  1774  // InviteUsersToTeam invite users by email to the team.
  1775  func (c *Client4) InviteUsersToTeam(teamId string, userEmails []string) (bool, *Response) {
  1776  	r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/invite/email", ArrayToJson(userEmails))
  1777  	if err != nil {
  1778  		return false, BuildErrorResponse(r, err)
  1779  	}
  1780  	defer closeBody(r)
  1781  	return CheckStatusOK(r), BuildResponse(r)
  1782  }
  1783  
  1784  // InvalidateEmailInvites will invalidate active email invitations that have not been accepted by the user.
  1785  func (c *Client4) InvalidateEmailInvites() (bool, *Response) {
  1786  	r, err := c.DoApiDelete(c.GetTeamsRoute() + "/invites/email")
  1787  	if err != nil {
  1788  		return false, BuildErrorResponse(r, err)
  1789  	}
  1790  	defer closeBody(r)
  1791  	return CheckStatusOK(r), BuildResponse(r)
  1792  }
  1793  
  1794  // GetTeamInviteInfo returns a team object from an invite id containing sanitized information.
  1795  func (c *Client4) GetTeamInviteInfo(inviteId string) (*Team, *Response) {
  1796  	r, err := c.DoApiGet(c.GetTeamsRoute()+"/invite/"+inviteId, "")
  1797  	if err != nil {
  1798  		return nil, BuildErrorResponse(r, err)
  1799  	}
  1800  	defer closeBody(r)
  1801  	return TeamFromJson(r.Body), BuildResponse(r)
  1802  }
  1803  
  1804  // SetTeamIcon sets team icon of the team.
  1805  func (c *Client4) SetTeamIcon(teamId string, data []byte) (bool, *Response) {
  1806  	body := &bytes.Buffer{}
  1807  	writer := multipart.NewWriter(body)
  1808  
  1809  	part, err := writer.CreateFormFile("image", "teamIcon.png")
  1810  	if err != nil {
  1811  		return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1812  	}
  1813  
  1814  	if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1815  		return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  1816  	}
  1817  
  1818  	if err = writer.Close(); err != nil {
  1819  		return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.set_team_icon.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  1820  	}
  1821  
  1822  	rq, err := http.NewRequest("POST", c.ApiUrl+c.GetTeamRoute(teamId)+"/image", bytes.NewReader(body.Bytes()))
  1823  	if err != nil {
  1824  		return false, &Response{Error: NewAppError("SetTeamIcon", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  1825  	}
  1826  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  1827  
  1828  	if len(c.AuthToken) > 0 {
  1829  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  1830  	}
  1831  
  1832  	rp, err := c.HttpClient.Do(rq)
  1833  	if err != nil || rp == nil {
  1834  		// set to http.StatusForbidden(403)
  1835  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetTeamRoute(teamId)+"/image", "model.client.connecting.app_error", nil, err.Error(), 403)}
  1836  	}
  1837  	defer closeBody(rp)
  1838  
  1839  	if rp.StatusCode >= 300 {
  1840  		return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  1841  	}
  1842  
  1843  	return CheckStatusOK(rp), BuildResponse(rp)
  1844  }
  1845  
  1846  // GetTeamIcon gets the team icon of the team.
  1847  func (c *Client4) GetTeamIcon(teamId, etag string) ([]byte, *Response) {
  1848  	r, appErr := c.DoApiGet(c.GetTeamRoute(teamId)+"/image", etag)
  1849  	if appErr != nil {
  1850  		return nil, BuildErrorResponse(r, appErr)
  1851  	}
  1852  	defer closeBody(r)
  1853  
  1854  	data, err := ioutil.ReadAll(r.Body)
  1855  	if err != nil {
  1856  		return nil, BuildErrorResponse(r, NewAppError("GetTeamIcon", "model.client.get_team_icon.app_error", nil, err.Error(), r.StatusCode))
  1857  	}
  1858  	return data, BuildResponse(r)
  1859  }
  1860  
  1861  // RemoveTeamIcon updates LastTeamIconUpdate to 0 which indicates team icon is removed.
  1862  func (c *Client4) RemoveTeamIcon(teamId string) (bool, *Response) {
  1863  	r, err := c.DoApiDelete(c.GetTeamRoute(teamId) + "/image")
  1864  	if err != nil {
  1865  		return false, BuildErrorResponse(r, err)
  1866  	}
  1867  	defer closeBody(r)
  1868  	return CheckStatusOK(r), BuildResponse(r)
  1869  }
  1870  
  1871  // Channel Section
  1872  
  1873  // GetAllChannels get all the channels. Must be a system administrator.
  1874  func (c *Client4) GetAllChannels(page int, perPage int, etag string) (*ChannelListWithTeamData, *Response) {
  1875  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1876  	r, err := c.DoApiGet(c.GetChannelsRoute()+query, etag)
  1877  	if err != nil {
  1878  		return nil, BuildErrorResponse(r, err)
  1879  	}
  1880  	defer closeBody(r)
  1881  	return ChannelListWithTeamDataFromJson(r.Body), BuildResponse(r)
  1882  }
  1883  
  1884  // CreateChannel creates a channel based on the provided channel struct.
  1885  func (c *Client4) CreateChannel(channel *Channel) (*Channel, *Response) {
  1886  	r, err := c.DoApiPost(c.GetChannelsRoute(), channel.ToJson())
  1887  	if err != nil {
  1888  		return nil, BuildErrorResponse(r, err)
  1889  	}
  1890  	defer closeBody(r)
  1891  	return ChannelFromJson(r.Body), BuildResponse(r)
  1892  }
  1893  
  1894  // UpdateChannel updates a channel based on the provided channel struct.
  1895  func (c *Client4) UpdateChannel(channel *Channel) (*Channel, *Response) {
  1896  	r, err := c.DoApiPut(c.GetChannelRoute(channel.Id), channel.ToJson())
  1897  	if err != nil {
  1898  		return nil, BuildErrorResponse(r, err)
  1899  	}
  1900  	defer closeBody(r)
  1901  	return ChannelFromJson(r.Body), BuildResponse(r)
  1902  }
  1903  
  1904  // PatchChannel partially updates a channel. Any missing fields are not updated.
  1905  func (c *Client4) PatchChannel(channelId string, patch *ChannelPatch) (*Channel, *Response) {
  1906  	r, err := c.DoApiPut(c.GetChannelRoute(channelId)+"/patch", patch.ToJson())
  1907  	if err != nil {
  1908  		return nil, BuildErrorResponse(r, err)
  1909  	}
  1910  	defer closeBody(r)
  1911  	return ChannelFromJson(r.Body), BuildResponse(r)
  1912  }
  1913  
  1914  // ConvertChannelToPrivate converts public to private channel.
  1915  func (c *Client4) ConvertChannelToPrivate(channelId string) (*Channel, *Response) {
  1916  	r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/convert", "")
  1917  	if err != nil {
  1918  		return nil, BuildErrorResponse(r, err)
  1919  	}
  1920  	defer closeBody(r)
  1921  	return ChannelFromJson(r.Body), BuildResponse(r)
  1922  }
  1923  
  1924  // RestoreChannel restores a previously deleted channel. Any missing fields are not updated.
  1925  func (c *Client4) RestoreChannel(channelId string) (*Channel, *Response) {
  1926  	r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/restore", "")
  1927  	if err != nil {
  1928  		return nil, BuildErrorResponse(r, err)
  1929  	}
  1930  	defer closeBody(r)
  1931  	return ChannelFromJson(r.Body), BuildResponse(r)
  1932  }
  1933  
  1934  // CreateDirectChannel creates a direct message channel based on the two user
  1935  // ids provided.
  1936  func (c *Client4) CreateDirectChannel(userId1, userId2 string) (*Channel, *Response) {
  1937  	requestBody := []string{userId1, userId2}
  1938  	r, err := c.DoApiPost(c.GetChannelsRoute()+"/direct", ArrayToJson(requestBody))
  1939  	if err != nil {
  1940  		return nil, BuildErrorResponse(r, err)
  1941  	}
  1942  	defer closeBody(r)
  1943  	return ChannelFromJson(r.Body), BuildResponse(r)
  1944  }
  1945  
  1946  // CreateGroupChannel creates a group message channel based on userIds provided.
  1947  func (c *Client4) CreateGroupChannel(userIds []string) (*Channel, *Response) {
  1948  	r, err := c.DoApiPost(c.GetChannelsRoute()+"/group", ArrayToJson(userIds))
  1949  	if err != nil {
  1950  		return nil, BuildErrorResponse(r, err)
  1951  	}
  1952  	defer closeBody(r)
  1953  	return ChannelFromJson(r.Body), BuildResponse(r)
  1954  }
  1955  
  1956  // GetChannel returns a channel based on the provided channel id string.
  1957  func (c *Client4) GetChannel(channelId, etag string) (*Channel, *Response) {
  1958  	r, err := c.DoApiGet(c.GetChannelRoute(channelId), etag)
  1959  	if err != nil {
  1960  		return nil, BuildErrorResponse(r, err)
  1961  	}
  1962  	defer closeBody(r)
  1963  	return ChannelFromJson(r.Body), BuildResponse(r)
  1964  }
  1965  
  1966  // GetChannelStats returns statistics for a channel.
  1967  func (c *Client4) GetChannelStats(channelId string, etag string) (*ChannelStats, *Response) {
  1968  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/stats", etag)
  1969  	if err != nil {
  1970  		return nil, BuildErrorResponse(r, err)
  1971  	}
  1972  	defer closeBody(r)
  1973  	return ChannelStatsFromJson(r.Body), BuildResponse(r)
  1974  }
  1975  
  1976  // GetChannelMembersTimezones gets a list of timezones for a channel.
  1977  func (c *Client4) GetChannelMembersTimezones(channelId string) ([]string, *Response) {
  1978  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/timezones", "")
  1979  	if err != nil {
  1980  		return nil, BuildErrorResponse(r, err)
  1981  	}
  1982  	defer closeBody(r)
  1983  	return ArrayFromJson(r.Body), BuildResponse(r)
  1984  }
  1985  
  1986  // GetPinnedPosts gets a list of pinned posts.
  1987  func (c *Client4) GetPinnedPosts(channelId string, etag string) (*PostList, *Response) {
  1988  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", etag)
  1989  	if err != nil {
  1990  		return nil, BuildErrorResponse(r, err)
  1991  	}
  1992  	defer closeBody(r)
  1993  	return PostListFromJson(r.Body), BuildResponse(r)
  1994  }
  1995  
  1996  // GetPublicChannelsForTeam returns a list of public channels based on the provided team id string.
  1997  func (c *Client4) GetPublicChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
  1998  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  1999  	r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag)
  2000  	if err != nil {
  2001  		return nil, BuildErrorResponse(r, err)
  2002  	}
  2003  	defer closeBody(r)
  2004  	return ChannelSliceFromJson(r.Body), BuildResponse(r)
  2005  }
  2006  
  2007  // GetDeletedChannelsForTeam returns a list of public channels based on the provided team id string.
  2008  func (c *Client4) GetDeletedChannelsForTeam(teamId string, page int, perPage int, etag string) ([]*Channel, *Response) {
  2009  	query := fmt.Sprintf("/deleted?page=%v&per_page=%v", page, perPage)
  2010  	r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+query, etag)
  2011  	if err != nil {
  2012  		return nil, BuildErrorResponse(r, err)
  2013  	}
  2014  	defer closeBody(r)
  2015  	return ChannelSliceFromJson(r.Body), BuildResponse(r)
  2016  }
  2017  
  2018  // GetPublicChannelsByIdsForTeam returns a list of public channels based on provided team id string.
  2019  func (c *Client4) GetPublicChannelsByIdsForTeam(teamId string, channelIds []string) ([]*Channel, *Response) {
  2020  	r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/ids", ArrayToJson(channelIds))
  2021  	if err != nil {
  2022  		return nil, BuildErrorResponse(r, err)
  2023  	}
  2024  	defer closeBody(r)
  2025  	return ChannelSliceFromJson(r.Body), BuildResponse(r)
  2026  }
  2027  
  2028  // GetChannelsForTeamForUser returns a list channels of on a team for a user.
  2029  func (c *Client4) GetChannelsForTeamForUser(teamId, userId, etag string) ([]*Channel, *Response) {
  2030  	r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetTeamRoute(teamId)+"/channels", etag)
  2031  	if err != nil {
  2032  		return nil, BuildErrorResponse(r, err)
  2033  	}
  2034  	defer closeBody(r)
  2035  	return ChannelSliceFromJson(r.Body), BuildResponse(r)
  2036  }
  2037  
  2038  // SearchChannels returns the channels on a team matching the provided search term.
  2039  func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response) {
  2040  	r, err := c.DoApiPost(c.GetChannelsForTeamRoute(teamId)+"/search", search.ToJson())
  2041  	if err != nil {
  2042  		return nil, BuildErrorResponse(r, err)
  2043  	}
  2044  	defer closeBody(r)
  2045  	return ChannelSliceFromJson(r.Body), BuildResponse(r)
  2046  }
  2047  
  2048  // SearchAllChannels search in all the channels. Must be a system administrator.
  2049  func (c *Client4) SearchAllChannels(search *ChannelSearch) (*ChannelListWithTeamData, *Response) {
  2050  	r, err := c.DoApiPost(c.GetChannelsRoute()+"/search", search.ToJson())
  2051  	if err != nil {
  2052  		return nil, BuildErrorResponse(r, err)
  2053  	}
  2054  	defer closeBody(r)
  2055  	return ChannelListWithTeamDataFromJson(r.Body), BuildResponse(r)
  2056  }
  2057  
  2058  // DeleteChannel deletes channel based on the provided channel id string.
  2059  func (c *Client4) DeleteChannel(channelId string) (bool, *Response) {
  2060  	r, err := c.DoApiDelete(c.GetChannelRoute(channelId))
  2061  	if err != nil {
  2062  		return false, BuildErrorResponse(r, err)
  2063  	}
  2064  	defer closeBody(r)
  2065  	return CheckStatusOK(r), BuildResponse(r)
  2066  }
  2067  
  2068  // GetChannelByName returns a channel based on the provided channel name and team id strings.
  2069  func (c *Client4) GetChannelByName(channelName, teamId string, etag string) (*Channel, *Response) {
  2070  	r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId), etag)
  2071  	if err != nil {
  2072  		return nil, BuildErrorResponse(r, err)
  2073  	}
  2074  	defer closeBody(r)
  2075  	return ChannelFromJson(r.Body), BuildResponse(r)
  2076  }
  2077  
  2078  // GetChannelByNameIncludeDeleted returns a channel based on the provided channel name and team id strings. Other then GetChannelByName it will also return deleted channels.
  2079  func (c *Client4) GetChannelByNameIncludeDeleted(channelName, teamId string, etag string) (*Channel, *Response) {
  2080  	r, err := c.DoApiGet(c.GetChannelByNameRoute(channelName, teamId)+"?include_deleted=true", etag)
  2081  	if err != nil {
  2082  		return nil, BuildErrorResponse(r, err)
  2083  	}
  2084  	defer closeBody(r)
  2085  	return ChannelFromJson(r.Body), BuildResponse(r)
  2086  }
  2087  
  2088  // GetChannelByNameForTeamName returns a channel based on the provided channel name and team name strings.
  2089  func (c *Client4) GetChannelByNameForTeamName(channelName, teamName string, etag string) (*Channel, *Response) {
  2090  	r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName), etag)
  2091  	if err != nil {
  2092  		return nil, BuildErrorResponse(r, err)
  2093  	}
  2094  	defer closeBody(r)
  2095  	return ChannelFromJson(r.Body), BuildResponse(r)
  2096  }
  2097  
  2098  // GetChannelByNameForTeamNameIncludeDeleted returns a channel based on the provided channel name and team name strings. Other then GetChannelByNameForTeamName it will also return deleted channels.
  2099  func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamName string, etag string) (*Channel, *Response) {
  2100  	r, err := c.DoApiGet(c.GetChannelByNameForTeamNameRoute(channelName, teamName)+"?include_deleted=true", etag)
  2101  	if err != nil {
  2102  		return nil, BuildErrorResponse(r, err)
  2103  	}
  2104  	defer closeBody(r)
  2105  	return ChannelFromJson(r.Body), BuildResponse(r)
  2106  }
  2107  
  2108  // GetChannelMembers gets a page of channel members.
  2109  func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (*ChannelMembers, *Response) {
  2110  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2111  	r, err := c.DoApiGet(c.GetChannelMembersRoute(channelId)+query, etag)
  2112  	if err != nil {
  2113  		return nil, BuildErrorResponse(r, err)
  2114  	}
  2115  	defer closeBody(r)
  2116  	return ChannelMembersFromJson(r.Body), BuildResponse(r)
  2117  }
  2118  
  2119  // GetChannelMembersByIds gets the channel members in a channel for a list of user ids.
  2120  func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (*ChannelMembers, *Response) {
  2121  	r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"/ids", ArrayToJson(userIds))
  2122  	if err != nil {
  2123  		return nil, BuildErrorResponse(r, err)
  2124  	}
  2125  	defer closeBody(r)
  2126  	return ChannelMembersFromJson(r.Body), BuildResponse(r)
  2127  }
  2128  
  2129  // GetChannelMember gets a channel member.
  2130  func (c *Client4) GetChannelMember(channelId, userId, etag string) (*ChannelMember, *Response) {
  2131  	r, err := c.DoApiGet(c.GetChannelMemberRoute(channelId, userId), etag)
  2132  	if err != nil {
  2133  		return nil, BuildErrorResponse(r, err)
  2134  	}
  2135  	defer closeBody(r)
  2136  	return ChannelMemberFromJson(r.Body), BuildResponse(r)
  2137  }
  2138  
  2139  // GetChannelMembersForUser gets all the channel members for a user on a team.
  2140  func (c *Client4) GetChannelMembersForUser(userId, teamId, etag string) (*ChannelMembers, *Response) {
  2141  	r, err := c.DoApiGet(fmt.Sprintf(c.GetUserRoute(userId)+"/teams/%v/channels/members", teamId), etag)
  2142  	if err != nil {
  2143  		return nil, BuildErrorResponse(r, err)
  2144  	}
  2145  	defer closeBody(r)
  2146  	return ChannelMembersFromJson(r.Body), BuildResponse(r)
  2147  }
  2148  
  2149  // ViewChannel performs a view action for a user. Synonymous with switching channels or marking channels as read by a user.
  2150  func (c *Client4) ViewChannel(userId string, view *ChannelView) (*ChannelViewResponse, *Response) {
  2151  	url := fmt.Sprintf(c.GetChannelsRoute()+"/members/%v/view", userId)
  2152  	r, err := c.DoApiPost(url, view.ToJson())
  2153  	if err != nil {
  2154  		return nil, BuildErrorResponse(r, err)
  2155  	}
  2156  	defer closeBody(r)
  2157  	return ChannelViewResponseFromJson(r.Body), BuildResponse(r)
  2158  }
  2159  
  2160  // GetChannelUnread will return a ChannelUnread object that contains the number of
  2161  // unread messages and mentions for a user.
  2162  func (c *Client4) GetChannelUnread(channelId, userId string) (*ChannelUnread, *Response) {
  2163  	r, err := c.DoApiGet(c.GetUserRoute(userId)+c.GetChannelRoute(channelId)+"/unread", "")
  2164  	if err != nil {
  2165  		return nil, BuildErrorResponse(r, err)
  2166  	}
  2167  	defer closeBody(r)
  2168  	return ChannelUnreadFromJson(r.Body), BuildResponse(r)
  2169  }
  2170  
  2171  // UpdateChannelRoles will update the roles on a channel for a user.
  2172  func (c *Client4) UpdateChannelRoles(channelId, userId, roles string) (bool, *Response) {
  2173  	requestBody := map[string]string{"roles": roles}
  2174  	r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/roles", MapToJson(requestBody))
  2175  	if err != nil {
  2176  		return false, BuildErrorResponse(r, err)
  2177  	}
  2178  	defer closeBody(r)
  2179  	return CheckStatusOK(r), BuildResponse(r)
  2180  }
  2181  
  2182  // UpdateChannelMemberSchemeRoles will update the scheme-derived roles on a channel for a user.
  2183  func (c *Client4) UpdateChannelMemberSchemeRoles(channelId string, userId string, schemeRoles *SchemeRoles) (bool, *Response) {
  2184  	r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/schemeRoles", schemeRoles.ToJson())
  2185  	if err != nil {
  2186  		return false, BuildErrorResponse(r, err)
  2187  	}
  2188  	defer closeBody(r)
  2189  	return CheckStatusOK(r), BuildResponse(r)
  2190  }
  2191  
  2192  // UpdateChannelNotifyProps will update the notification properties on a channel for a user.
  2193  func (c *Client4) UpdateChannelNotifyProps(channelId, userId string, props map[string]string) (bool, *Response) {
  2194  	r, err := c.DoApiPut(c.GetChannelMemberRoute(channelId, userId)+"/notify_props", MapToJson(props))
  2195  	if err != nil {
  2196  		return false, BuildErrorResponse(r, err)
  2197  	}
  2198  	defer closeBody(r)
  2199  	return CheckStatusOK(r), BuildResponse(r)
  2200  }
  2201  
  2202  // AddChannelMember adds user to channel and return a channel member.
  2203  func (c *Client4) AddChannelMember(channelId, userId string) (*ChannelMember, *Response) {
  2204  	requestBody := map[string]string{"user_id": userId}
  2205  	r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody))
  2206  	if err != nil {
  2207  		return nil, BuildErrorResponse(r, err)
  2208  	}
  2209  	defer closeBody(r)
  2210  	return ChannelMemberFromJson(r.Body), BuildResponse(r)
  2211  }
  2212  
  2213  // AddChannelMemberWithRootId adds user to channel and return a channel member. Post add to channel message has the postRootId.
  2214  func (c *Client4) AddChannelMemberWithRootId(channelId, userId, postRootId string) (*ChannelMember, *Response) {
  2215  	requestBody := map[string]string{"user_id": userId, "post_root_id": postRootId}
  2216  	r, err := c.DoApiPost(c.GetChannelMembersRoute(channelId)+"", MapToJson(requestBody))
  2217  	if err != nil {
  2218  		return nil, BuildErrorResponse(r, err)
  2219  	}
  2220  	defer closeBody(r)
  2221  	return ChannelMemberFromJson(r.Body), BuildResponse(r)
  2222  }
  2223  
  2224  // RemoveUserFromChannel will delete the channel member object for a user, effectively removing the user from a channel.
  2225  func (c *Client4) RemoveUserFromChannel(channelId, userId string) (bool, *Response) {
  2226  	r, err := c.DoApiDelete(c.GetChannelMemberRoute(channelId, userId))
  2227  	if err != nil {
  2228  		return false, BuildErrorResponse(r, err)
  2229  	}
  2230  	defer closeBody(r)
  2231  	return CheckStatusOK(r), BuildResponse(r)
  2232  }
  2233  
  2234  // AutocompleteChannelsForTeam will return an ordered list of channels autocomplete suggestions.
  2235  func (c *Client4) AutocompleteChannelsForTeam(teamId, name string) (*ChannelList, *Response) {
  2236  	query := fmt.Sprintf("?name=%v", name)
  2237  	r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/autocomplete"+query, "")
  2238  	if err != nil {
  2239  		return nil, BuildErrorResponse(r, err)
  2240  	}
  2241  	defer closeBody(r)
  2242  	return ChannelListFromJson(r.Body), BuildResponse(r)
  2243  }
  2244  
  2245  // AutocompleteChannelsForTeamForSearch will return an ordered list of your channels autocomplete suggestions.
  2246  func (c *Client4) AutocompleteChannelsForTeamForSearch(teamId, name string) (*ChannelList, *Response) {
  2247  	query := fmt.Sprintf("?name=%v", name)
  2248  	r, err := c.DoApiGet(c.GetChannelsForTeamRoute(teamId)+"/search_autocomplete"+query, "")
  2249  	if err != nil {
  2250  		return nil, BuildErrorResponse(r, err)
  2251  	}
  2252  	defer closeBody(r)
  2253  	return ChannelListFromJson(r.Body), BuildResponse(r)
  2254  }
  2255  
  2256  // Post Section
  2257  
  2258  // CreatePost creates a post based on the provided post struct.
  2259  func (c *Client4) CreatePost(post *Post) (*Post, *Response) {
  2260  	r, err := c.DoApiPost(c.GetPostsRoute(), post.ToUnsanitizedJson())
  2261  	if err != nil {
  2262  		return nil, BuildErrorResponse(r, err)
  2263  	}
  2264  	defer closeBody(r)
  2265  	return PostFromJson(r.Body), BuildResponse(r)
  2266  }
  2267  
  2268  // CreatePostEphemeral creates a ephemeral post based on the provided post struct which is send to the given user id.
  2269  func (c *Client4) CreatePostEphemeral(post *PostEphemeral) (*Post, *Response) {
  2270  	r, err := c.DoApiPost(c.GetPostsEphemeralRoute(), post.ToUnsanitizedJson())
  2271  	if err != nil {
  2272  		return nil, BuildErrorResponse(r, err)
  2273  	}
  2274  	defer closeBody(r)
  2275  	return PostFromJson(r.Body), BuildResponse(r)
  2276  }
  2277  
  2278  // UpdatePost updates a post based on the provided post struct.
  2279  func (c *Client4) UpdatePost(postId string, post *Post) (*Post, *Response) {
  2280  	r, err := c.DoApiPut(c.GetPostRoute(postId), post.ToUnsanitizedJson())
  2281  	if err != nil {
  2282  		return nil, BuildErrorResponse(r, err)
  2283  	}
  2284  	defer closeBody(r)
  2285  	return PostFromJson(r.Body), BuildResponse(r)
  2286  }
  2287  
  2288  // PatchPost partially updates a post. Any missing fields are not updated.
  2289  func (c *Client4) PatchPost(postId string, patch *PostPatch) (*Post, *Response) {
  2290  	r, err := c.DoApiPut(c.GetPostRoute(postId)+"/patch", patch.ToJson())
  2291  	if err != nil {
  2292  		return nil, BuildErrorResponse(r, err)
  2293  	}
  2294  	defer closeBody(r)
  2295  	return PostFromJson(r.Body), BuildResponse(r)
  2296  }
  2297  
  2298  // PinPost pin a post based on provided post id string.
  2299  func (c *Client4) PinPost(postId string) (bool, *Response) {
  2300  	r, err := c.DoApiPost(c.GetPostRoute(postId)+"/pin", "")
  2301  	if err != nil {
  2302  		return false, BuildErrorResponse(r, err)
  2303  	}
  2304  	defer closeBody(r)
  2305  	return CheckStatusOK(r), BuildResponse(r)
  2306  }
  2307  
  2308  // UnpinPost unpin a post based on provided post id string.
  2309  func (c *Client4) UnpinPost(postId string) (bool, *Response) {
  2310  	r, err := c.DoApiPost(c.GetPostRoute(postId)+"/unpin", "")
  2311  	if err != nil {
  2312  		return false, BuildErrorResponse(r, err)
  2313  	}
  2314  	defer closeBody(r)
  2315  	return CheckStatusOK(r), BuildResponse(r)
  2316  }
  2317  
  2318  // GetPost gets a single post.
  2319  func (c *Client4) GetPost(postId string, etag string) (*Post, *Response) {
  2320  	r, err := c.DoApiGet(c.GetPostRoute(postId), etag)
  2321  	if err != nil {
  2322  		return nil, BuildErrorResponse(r, err)
  2323  	}
  2324  	defer closeBody(r)
  2325  	return PostFromJson(r.Body), BuildResponse(r)
  2326  }
  2327  
  2328  // DeletePost deletes a post from the provided post id string.
  2329  func (c *Client4) DeletePost(postId string) (bool, *Response) {
  2330  	r, err := c.DoApiDelete(c.GetPostRoute(postId))
  2331  	if err != nil {
  2332  		return false, BuildErrorResponse(r, err)
  2333  	}
  2334  	defer closeBody(r)
  2335  	return CheckStatusOK(r), BuildResponse(r)
  2336  }
  2337  
  2338  // GetPostThread gets a post with all the other posts in the same thread.
  2339  func (c *Client4) GetPostThread(postId string, etag string) (*PostList, *Response) {
  2340  	r, err := c.DoApiGet(c.GetPostRoute(postId)+"/thread", etag)
  2341  	if err != nil {
  2342  		return nil, BuildErrorResponse(r, err)
  2343  	}
  2344  	defer closeBody(r)
  2345  	return PostListFromJson(r.Body), BuildResponse(r)
  2346  }
  2347  
  2348  // GetPostsForChannel gets a page of posts with an array for ordering for a channel.
  2349  func (c *Client4) GetPostsForChannel(channelId string, page, perPage int, etag string) (*PostList, *Response) {
  2350  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2351  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag)
  2352  	if err != nil {
  2353  		return nil, BuildErrorResponse(r, err)
  2354  	}
  2355  	defer closeBody(r)
  2356  	return PostListFromJson(r.Body), BuildResponse(r)
  2357  }
  2358  
  2359  // GetFlaggedPostsForUser returns flagged posts of a user based on user id string.
  2360  func (c *Client4) GetFlaggedPostsForUser(userId string, page int, perPage int) (*PostList, *Response) {
  2361  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2362  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "")
  2363  	if err != nil {
  2364  		return nil, BuildErrorResponse(r, err)
  2365  	}
  2366  	defer closeBody(r)
  2367  	return PostListFromJson(r.Body), BuildResponse(r)
  2368  }
  2369  
  2370  // GetFlaggedPostsForUserInTeam returns flagged posts in team of a user based on user id string.
  2371  func (c *Client4) GetFlaggedPostsForUserInTeam(userId string, teamId string, page int, perPage int) (*PostList, *Response) {
  2372  	if len(teamId) == 0 || len(teamId) != 26 {
  2373  		return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInTeam", "model.client.get_flagged_posts_in_team.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
  2374  	}
  2375  
  2376  	query := fmt.Sprintf("?team_id=%v&page=%v&per_page=%v", teamId, page, perPage)
  2377  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "")
  2378  	if err != nil {
  2379  		return nil, BuildErrorResponse(r, err)
  2380  	}
  2381  	defer closeBody(r)
  2382  	return PostListFromJson(r.Body), BuildResponse(r)
  2383  }
  2384  
  2385  // GetFlaggedPostsForUserInChannel returns flagged posts in channel of a user based on user id string.
  2386  func (c *Client4) GetFlaggedPostsForUserInChannel(userId string, channelId string, page int, perPage int) (*PostList, *Response) {
  2387  	if len(channelId) == 0 || len(channelId) != 26 {
  2388  		return nil, &Response{StatusCode: http.StatusBadRequest, Error: NewAppError("GetFlaggedPostsForUserInChannel", "model.client.get_flagged_posts_in_channel.missing_parameter.app_error", nil, "", http.StatusBadRequest)}
  2389  	}
  2390  
  2391  	query := fmt.Sprintf("?channel_id=%v&page=%v&per_page=%v", channelId, page, perPage)
  2392  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/posts/flagged"+query, "")
  2393  	if err != nil {
  2394  		return nil, BuildErrorResponse(r, err)
  2395  	}
  2396  	defer closeBody(r)
  2397  	return PostListFromJson(r.Body), BuildResponse(r)
  2398  }
  2399  
  2400  // GetPostsSince gets posts created after a specified time as Unix time in milliseconds.
  2401  func (c *Client4) GetPostsSince(channelId string, time int64) (*PostList, *Response) {
  2402  	query := fmt.Sprintf("?since=%v", time)
  2403  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, "")
  2404  	if err != nil {
  2405  		return nil, BuildErrorResponse(r, err)
  2406  	}
  2407  	defer closeBody(r)
  2408  	return PostListFromJson(r.Body), BuildResponse(r)
  2409  }
  2410  
  2411  // GetPostsAfter gets a page of posts that were posted after the post provided.
  2412  func (c *Client4) GetPostsAfter(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
  2413  	query := fmt.Sprintf("?page=%v&per_page=%v&after=%v", page, perPage, postId)
  2414  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag)
  2415  	if err != nil {
  2416  		return nil, BuildErrorResponse(r, err)
  2417  	}
  2418  	defer closeBody(r)
  2419  	return PostListFromJson(r.Body), BuildResponse(r)
  2420  }
  2421  
  2422  // GetPostsBefore gets a page of posts that were posted before the post provided.
  2423  func (c *Client4) GetPostsBefore(channelId, postId string, page, perPage int, etag string) (*PostList, *Response) {
  2424  	query := fmt.Sprintf("?page=%v&per_page=%v&before=%v", page, perPage, postId)
  2425  	r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/posts"+query, etag)
  2426  	if err != nil {
  2427  		return nil, BuildErrorResponse(r, err)
  2428  	}
  2429  	defer closeBody(r)
  2430  	return PostListFromJson(r.Body), BuildResponse(r)
  2431  }
  2432  
  2433  // SearchPosts returns any posts with matching terms string.
  2434  func (c *Client4) SearchPosts(teamId string, terms string, isOrSearch bool) (*PostList, *Response) {
  2435  	params := SearchParameter{
  2436  		Terms:      &terms,
  2437  		IsOrSearch: &isOrSearch,
  2438  	}
  2439  	return c.SearchPostsWithParams(teamId, &params)
  2440  }
  2441  
  2442  // SearchPostsWithParams returns any posts with matching terms string.
  2443  func (c *Client4) SearchPostsWithParams(teamId string, params *SearchParameter) (*PostList, *Response) {
  2444  	r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", params.SearchParameterToJson())
  2445  	if err != nil {
  2446  		return nil, BuildErrorResponse(r, err)
  2447  	}
  2448  	defer closeBody(r)
  2449  	return PostListFromJson(r.Body), BuildResponse(r)
  2450  }
  2451  
  2452  // SearchPostsWithMatches returns any posts with matching terms string, including.
  2453  func (c *Client4) SearchPostsWithMatches(teamId string, terms string, isOrSearch bool) (*PostSearchResults, *Response) {
  2454  	requestBody := map[string]interface{}{"terms": terms, "is_or_search": isOrSearch}
  2455  	r, err := c.DoApiPost(c.GetTeamRoute(teamId)+"/posts/search", StringInterfaceToJson(requestBody))
  2456  	if err != nil {
  2457  		return nil, BuildErrorResponse(r, err)
  2458  	}
  2459  	defer closeBody(r)
  2460  	return PostSearchResultsFromJson(r.Body), BuildResponse(r)
  2461  }
  2462  
  2463  // DoPostAction performs a post action.
  2464  func (c *Client4) DoPostAction(postId, actionId string) (bool, *Response) {
  2465  	r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, "")
  2466  	if err != nil {
  2467  		return false, BuildErrorResponse(r, err)
  2468  	}
  2469  	defer closeBody(r)
  2470  	return CheckStatusOK(r), BuildResponse(r)
  2471  }
  2472  
  2473  // DoPostActionWithCookie performs a post action with extra arguments
  2474  func (c *Client4) DoPostActionWithCookie(postId, actionId, selected, cookieStr string) (bool, *Response) {
  2475  	var body []byte
  2476  	if selected != "" || cookieStr != "" {
  2477  		body, _ = json.Marshal(DoPostActionRequest{
  2478  			SelectedOption: selected,
  2479  			Cookie:         cookieStr,
  2480  		})
  2481  	}
  2482  	r, err := c.DoApiPost(c.GetPostRoute(postId)+"/actions/"+actionId, string(body))
  2483  	if err != nil {
  2484  		return false, BuildErrorResponse(r, err)
  2485  	}
  2486  	defer closeBody(r)
  2487  	return CheckStatusOK(r), BuildResponse(r)
  2488  }
  2489  
  2490  // OpenInteractiveDialog sends a WebSocket event to a user's clients to
  2491  // open interactive dialogs, based on the provided trigger ID and other
  2492  // provided data. Used with interactive message buttons, menus and
  2493  // slash commands.
  2494  func (c *Client4) OpenInteractiveDialog(request OpenDialogRequest) (bool, *Response) {
  2495  	b, _ := json.Marshal(request)
  2496  	r, err := c.DoApiPost("/actions/dialogs/open", string(b))
  2497  	if err != nil {
  2498  		return false, BuildErrorResponse(r, err)
  2499  	}
  2500  	defer closeBody(r)
  2501  	return CheckStatusOK(r), BuildResponse(r)
  2502  }
  2503  
  2504  // SubmitInteractiveDialog will submit the provided dialog data to the integration
  2505  // configured by the URL. Used with the interactive dialogs integration feature.
  2506  func (c *Client4) SubmitInteractiveDialog(request SubmitDialogRequest) (*SubmitDialogResponse, *Response) {
  2507  	b, _ := json.Marshal(request)
  2508  	r, err := c.DoApiPost("/actions/dialogs/submit", string(b))
  2509  	if err != nil {
  2510  		return nil, BuildErrorResponse(r, err)
  2511  	}
  2512  	defer closeBody(r)
  2513  
  2514  	var resp SubmitDialogResponse
  2515  	json.NewDecoder(r.Body).Decode(&resp)
  2516  	return &resp, BuildResponse(r)
  2517  }
  2518  
  2519  // UploadFile will upload a file to a channel using a multipart request, to be later attached to a post.
  2520  // This method is functionally equivalent to Client4.UploadFileAsRequestBody.
  2521  func (c *Client4) UploadFile(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
  2522  	body := &bytes.Buffer{}
  2523  	writer := multipart.NewWriter(body)
  2524  
  2525  	part, err := writer.CreateFormField("channel_id")
  2526  	if err != nil {
  2527  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
  2528  	}
  2529  
  2530  	_, err = io.Copy(part, strings.NewReader(channelId))
  2531  	if err != nil {
  2532  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), http.StatusBadRequest)}
  2533  	}
  2534  
  2535  	part, err = writer.CreateFormFile("files", filename)
  2536  	if err != nil {
  2537  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2538  	}
  2539  	_, err = io.Copy(part, bytes.NewBuffer(data))
  2540  	if err != nil {
  2541  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2542  	}
  2543  
  2544  	err = writer.Close()
  2545  	if err != nil {
  2546  		return nil, &Response{Error: NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  2547  	}
  2548  
  2549  	return c.DoUploadFile(c.GetFilesRoute(), body.Bytes(), writer.FormDataContentType())
  2550  }
  2551  
  2552  // UploadFileAsRequestBody will upload a file to a channel as the body of a request, to be later attached
  2553  // to a post. This method is functionally equivalent to Client4.UploadFile.
  2554  func (c *Client4) UploadFileAsRequestBody(data []byte, channelId string, filename string) (*FileUploadResponse, *Response) {
  2555  	return c.DoUploadFile(c.GetFilesRoute()+fmt.Sprintf("?channel_id=%v&filename=%v", url.QueryEscape(channelId), url.QueryEscape(filename)), data, http.DetectContentType(data))
  2556  }
  2557  
  2558  // GetFile gets the bytes for a file by id.
  2559  func (c *Client4) GetFile(fileId string) ([]byte, *Response) {
  2560  	r, appErr := c.DoApiGet(c.GetFileRoute(fileId), "")
  2561  	if appErr != nil {
  2562  		return nil, BuildErrorResponse(r, appErr)
  2563  	}
  2564  	defer closeBody(r)
  2565  
  2566  	data, err := ioutil.ReadAll(r.Body)
  2567  	if err != nil {
  2568  		return nil, BuildErrorResponse(r, NewAppError("GetFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2569  	}
  2570  	return data, BuildResponse(r)
  2571  }
  2572  
  2573  // DownloadFile gets the bytes for a file by id, optionally adding headers to force the browser to download it.
  2574  func (c *Client4) DownloadFile(fileId string, download bool) ([]byte, *Response) {
  2575  	r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("?download=%v", download), "")
  2576  	if appErr != nil {
  2577  		return nil, BuildErrorResponse(r, appErr)
  2578  	}
  2579  	defer closeBody(r)
  2580  
  2581  	data, err := ioutil.ReadAll(r.Body)
  2582  	if err != nil {
  2583  		return nil, BuildErrorResponse(r, NewAppError("DownloadFile", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2584  	}
  2585  	return data, BuildResponse(r)
  2586  }
  2587  
  2588  // GetFileThumbnail gets the bytes for a file by id.
  2589  func (c *Client4) GetFileThumbnail(fileId string) ([]byte, *Response) {
  2590  	r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/thumbnail", "")
  2591  	if appErr != nil {
  2592  		return nil, BuildErrorResponse(r, appErr)
  2593  	}
  2594  	defer closeBody(r)
  2595  
  2596  	data, err := ioutil.ReadAll(r.Body)
  2597  	if err != nil {
  2598  		return nil, BuildErrorResponse(r, NewAppError("GetFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2599  	}
  2600  	return data, BuildResponse(r)
  2601  }
  2602  
  2603  // DownloadFileThumbnail gets the bytes for a file by id, optionally adding headers to force the browser to download it.
  2604  func (c *Client4) DownloadFileThumbnail(fileId string, download bool) ([]byte, *Response) {
  2605  	r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/thumbnail?download=%v", download), "")
  2606  	if appErr != nil {
  2607  		return nil, BuildErrorResponse(r, appErr)
  2608  	}
  2609  	defer closeBody(r)
  2610  
  2611  	data, err := ioutil.ReadAll(r.Body)
  2612  	if err != nil {
  2613  		return nil, BuildErrorResponse(r, NewAppError("DownloadFileThumbnail", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2614  	}
  2615  	return data, BuildResponse(r)
  2616  }
  2617  
  2618  // GetFileLink gets the public link of a file by id.
  2619  func (c *Client4) GetFileLink(fileId string) (string, *Response) {
  2620  	r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/link", "")
  2621  	if err != nil {
  2622  		return "", BuildErrorResponse(r, err)
  2623  	}
  2624  	defer closeBody(r)
  2625  	return MapFromJson(r.Body)["link"], BuildResponse(r)
  2626  }
  2627  
  2628  // GetFilePreview gets the bytes for a file by id.
  2629  func (c *Client4) GetFilePreview(fileId string) ([]byte, *Response) {
  2630  	r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+"/preview", "")
  2631  	if appErr != nil {
  2632  		return nil, BuildErrorResponse(r, appErr)
  2633  	}
  2634  	defer closeBody(r)
  2635  
  2636  	data, err := ioutil.ReadAll(r.Body)
  2637  	if err != nil {
  2638  		return nil, BuildErrorResponse(r, NewAppError("GetFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2639  	}
  2640  	return data, BuildResponse(r)
  2641  }
  2642  
  2643  // DownloadFilePreview gets the bytes for a file by id.
  2644  func (c *Client4) DownloadFilePreview(fileId string, download bool) ([]byte, *Response) {
  2645  	r, appErr := c.DoApiGet(c.GetFileRoute(fileId)+fmt.Sprintf("/preview?download=%v", download), "")
  2646  	if appErr != nil {
  2647  		return nil, BuildErrorResponse(r, appErr)
  2648  	}
  2649  	defer closeBody(r)
  2650  
  2651  	data, err := ioutil.ReadAll(r.Body)
  2652  	if err != nil {
  2653  		return nil, BuildErrorResponse(r, NewAppError("DownloadFilePreview", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  2654  	}
  2655  	return data, BuildResponse(r)
  2656  }
  2657  
  2658  // GetFileInfo gets all the file info objects.
  2659  func (c *Client4) GetFileInfo(fileId string) (*FileInfo, *Response) {
  2660  	r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/info", "")
  2661  	if err != nil {
  2662  		return nil, BuildErrorResponse(r, err)
  2663  	}
  2664  	defer closeBody(r)
  2665  	return FileInfoFromJson(r.Body), BuildResponse(r)
  2666  }
  2667  
  2668  // GetFileInfosForPost gets all the file info objects attached to a post.
  2669  func (c *Client4) GetFileInfosForPost(postId string, etag string) ([]*FileInfo, *Response) {
  2670  	r, err := c.DoApiGet(c.GetPostRoute(postId)+"/files/info", etag)
  2671  	if err != nil {
  2672  		return nil, BuildErrorResponse(r, err)
  2673  	}
  2674  	defer closeBody(r)
  2675  	return FileInfosFromJson(r.Body), BuildResponse(r)
  2676  }
  2677  
  2678  // General/System Section
  2679  
  2680  // GetPing will return ok if the running goRoutines are below the threshold and unhealthy for above.
  2681  func (c *Client4) GetPing() (string, *Response) {
  2682  	r, err := c.DoApiGet(c.GetSystemRoute()+"/ping", "")
  2683  	if r != nil && r.StatusCode == 500 {
  2684  		defer r.Body.Close()
  2685  		return "unhealthy", BuildErrorResponse(r, err)
  2686  	}
  2687  	if err != nil {
  2688  		return "", BuildErrorResponse(r, err)
  2689  	}
  2690  	defer closeBody(r)
  2691  	return MapFromJson(r.Body)["status"], BuildResponse(r)
  2692  }
  2693  
  2694  // TestEmail will attempt to connect to the configured SMTP server.
  2695  func (c *Client4) TestEmail(config *Config) (bool, *Response) {
  2696  	r, err := c.DoApiPost(c.GetTestEmailRoute(), config.ToJson())
  2697  	if err != nil {
  2698  		return false, BuildErrorResponse(r, err)
  2699  	}
  2700  	defer closeBody(r)
  2701  	return CheckStatusOK(r), BuildResponse(r)
  2702  }
  2703  
  2704  // TestS3Connection will attempt to connect to the AWS S3.
  2705  func (c *Client4) TestS3Connection(config *Config) (bool, *Response) {
  2706  	r, err := c.DoApiPost(c.GetTestS3Route(), config.ToJson())
  2707  	if err != nil {
  2708  		return false, BuildErrorResponse(r, err)
  2709  	}
  2710  	defer closeBody(r)
  2711  	return CheckStatusOK(r), BuildResponse(r)
  2712  }
  2713  
  2714  // GetConfig will retrieve the server config with some sanitized items.
  2715  func (c *Client4) GetConfig() (*Config, *Response) {
  2716  	r, err := c.DoApiGet(c.GetConfigRoute(), "")
  2717  	if err != nil {
  2718  		return nil, BuildErrorResponse(r, err)
  2719  	}
  2720  	defer closeBody(r)
  2721  	return ConfigFromJson(r.Body), BuildResponse(r)
  2722  }
  2723  
  2724  // ReloadConfig will reload the server configuration.
  2725  func (c *Client4) ReloadConfig() (bool, *Response) {
  2726  	r, err := c.DoApiPost(c.GetConfigRoute()+"/reload", "")
  2727  	if err != nil {
  2728  		return false, BuildErrorResponse(r, err)
  2729  	}
  2730  	defer closeBody(r)
  2731  	return CheckStatusOK(r), BuildResponse(r)
  2732  }
  2733  
  2734  // GetOldClientConfig will retrieve the parts of the server configuration needed by the
  2735  // client, formatted in the old format.
  2736  func (c *Client4) GetOldClientConfig(etag string) (map[string]string, *Response) {
  2737  	r, err := c.DoApiGet(c.GetConfigRoute()+"/client?format=old", etag)
  2738  	if err != nil {
  2739  		return nil, BuildErrorResponse(r, err)
  2740  	}
  2741  	defer closeBody(r)
  2742  	return MapFromJson(r.Body), BuildResponse(r)
  2743  }
  2744  
  2745  // GetEnvironmentConfig will retrieve a map mirroring the server configuration where fields
  2746  // are set to true if the corresponding config setting is set through an environment variable.
  2747  // Settings that haven't been set through environment variables will be missing from the map.
  2748  func (c *Client4) GetEnvironmentConfig() (map[string]interface{}, *Response) {
  2749  	r, err := c.DoApiGet(c.GetConfigRoute()+"/environment", "")
  2750  	if err != nil {
  2751  		return nil, BuildErrorResponse(r, err)
  2752  	}
  2753  	defer closeBody(r)
  2754  	return StringInterfaceFromJson(r.Body), BuildResponse(r)
  2755  }
  2756  
  2757  // GetOldClientLicense will retrieve the parts of the server license needed by the
  2758  // client, formatted in the old format.
  2759  func (c *Client4) GetOldClientLicense(etag string) (map[string]string, *Response) {
  2760  	r, err := c.DoApiGet(c.GetLicenseRoute()+"/client?format=old", etag)
  2761  	if err != nil {
  2762  		return nil, BuildErrorResponse(r, err)
  2763  	}
  2764  	defer closeBody(r)
  2765  	return MapFromJson(r.Body), BuildResponse(r)
  2766  }
  2767  
  2768  // DatabaseRecycle will recycle the connections. Discard current connection and get new one.
  2769  func (c *Client4) DatabaseRecycle() (bool, *Response) {
  2770  	r, err := c.DoApiPost(c.GetDatabaseRoute()+"/recycle", "")
  2771  	if err != nil {
  2772  		return false, BuildErrorResponse(r, err)
  2773  	}
  2774  	defer closeBody(r)
  2775  	return CheckStatusOK(r), BuildResponse(r)
  2776  }
  2777  
  2778  // InvalidateCaches will purge the cache and can affect the performance while is cleaning.
  2779  func (c *Client4) InvalidateCaches() (bool, *Response) {
  2780  	r, err := c.DoApiPost(c.GetCacheRoute()+"/invalidate", "")
  2781  	if err != nil {
  2782  		return false, BuildErrorResponse(r, err)
  2783  	}
  2784  	defer closeBody(r)
  2785  	return CheckStatusOK(r), BuildResponse(r)
  2786  }
  2787  
  2788  // UpdateConfig will update the server configuration.
  2789  func (c *Client4) UpdateConfig(config *Config) (*Config, *Response) {
  2790  	r, err := c.DoApiPut(c.GetConfigRoute(), config.ToJson())
  2791  	if err != nil {
  2792  		return nil, BuildErrorResponse(r, err)
  2793  	}
  2794  	defer closeBody(r)
  2795  	return ConfigFromJson(r.Body), BuildResponse(r)
  2796  }
  2797  
  2798  // UploadLicenseFile will add a license file to the system.
  2799  func (c *Client4) UploadLicenseFile(data []byte) (bool, *Response) {
  2800  	body := &bytes.Buffer{}
  2801  	writer := multipart.NewWriter(body)
  2802  
  2803  	part, err := writer.CreateFormFile("license", "test-license.mattermost-license")
  2804  	if err != nil {
  2805  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2806  	}
  2807  
  2808  	if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  2809  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  2810  	}
  2811  
  2812  	if err = writer.Close(); err != nil {
  2813  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  2814  	}
  2815  
  2816  	rq, err := http.NewRequest("POST", c.ApiUrl+c.GetLicenseRoute(), bytes.NewReader(body.Bytes()))
  2817  	if err != nil {
  2818  		return false, &Response{Error: NewAppError("UploadLicenseFile", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  2819  	}
  2820  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  2821  
  2822  	if len(c.AuthToken) > 0 {
  2823  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  2824  	}
  2825  
  2826  	rp, err := c.HttpClient.Do(rq)
  2827  	if err != nil || rp == nil {
  2828  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetLicenseRoute(), "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  2829  	}
  2830  	defer closeBody(rp)
  2831  
  2832  	if rp.StatusCode >= 300 {
  2833  		return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  2834  	}
  2835  
  2836  	return CheckStatusOK(rp), BuildResponse(rp)
  2837  }
  2838  
  2839  // RemoveLicenseFile will remove the server license it exists. Note that this will
  2840  // disable all enterprise features.
  2841  func (c *Client4) RemoveLicenseFile() (bool, *Response) {
  2842  	r, err := c.DoApiDelete(c.GetLicenseRoute())
  2843  	if err != nil {
  2844  		return false, BuildErrorResponse(r, err)
  2845  	}
  2846  	defer closeBody(r)
  2847  	return CheckStatusOK(r), BuildResponse(r)
  2848  }
  2849  
  2850  // GetAnalyticsOld will retrieve analytics using the old format. New format is not
  2851  // available but the "/analytics" endpoint is reserved for it. The "name" argument is optional
  2852  // and defaults to "standard". The "teamId" argument is optional and will limit results
  2853  // to a specific team.
  2854  func (c *Client4) GetAnalyticsOld(name, teamId string) (AnalyticsRows, *Response) {
  2855  	query := fmt.Sprintf("?name=%v&team_id=%v", name, teamId)
  2856  	r, err := c.DoApiGet(c.GetAnalyticsRoute()+"/old"+query, "")
  2857  	if err != nil {
  2858  		return nil, BuildErrorResponse(r, err)
  2859  	}
  2860  	defer closeBody(r)
  2861  	return AnalyticsRowsFromJson(r.Body), BuildResponse(r)
  2862  }
  2863  
  2864  // Webhooks Section
  2865  
  2866  // CreateIncomingWebhook creates an incoming webhook for a channel.
  2867  func (c *Client4) CreateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
  2868  	r, err := c.DoApiPost(c.GetIncomingWebhooksRoute(), hook.ToJson())
  2869  	if err != nil {
  2870  		return nil, BuildErrorResponse(r, err)
  2871  	}
  2872  	defer closeBody(r)
  2873  	return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2874  }
  2875  
  2876  // UpdateIncomingWebhook updates an incoming webhook for a channel.
  2877  func (c *Client4) UpdateIncomingWebhook(hook *IncomingWebhook) (*IncomingWebhook, *Response) {
  2878  	r, err := c.DoApiPut(c.GetIncomingWebhookRoute(hook.Id), hook.ToJson())
  2879  	if err != nil {
  2880  		return nil, BuildErrorResponse(r, err)
  2881  	}
  2882  	defer closeBody(r)
  2883  	return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2884  }
  2885  
  2886  // GetIncomingWebhooks returns a page of incoming webhooks on the system. Page counting starts at 0.
  2887  func (c *Client4) GetIncomingWebhooks(page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
  2888  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2889  	r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag)
  2890  	if err != nil {
  2891  		return nil, BuildErrorResponse(r, err)
  2892  	}
  2893  	defer closeBody(r)
  2894  	return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
  2895  }
  2896  
  2897  // GetIncomingWebhooksForTeam returns a page of incoming webhooks for a team. Page counting starts at 0.
  2898  func (c *Client4) GetIncomingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*IncomingWebhook, *Response) {
  2899  	query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
  2900  	r, err := c.DoApiGet(c.GetIncomingWebhooksRoute()+query, etag)
  2901  	if err != nil {
  2902  		return nil, BuildErrorResponse(r, err)
  2903  	}
  2904  	defer closeBody(r)
  2905  	return IncomingWebhookListFromJson(r.Body), BuildResponse(r)
  2906  }
  2907  
  2908  // GetIncomingWebhook returns an Incoming webhook given the hook ID.
  2909  func (c *Client4) GetIncomingWebhook(hookID string, etag string) (*IncomingWebhook, *Response) {
  2910  	r, err := c.DoApiGet(c.GetIncomingWebhookRoute(hookID), etag)
  2911  	if err != nil {
  2912  		return nil, BuildErrorResponse(r, err)
  2913  	}
  2914  	defer closeBody(r)
  2915  	return IncomingWebhookFromJson(r.Body), BuildResponse(r)
  2916  }
  2917  
  2918  // DeleteIncomingWebhook deletes and Incoming Webhook given the hook ID.
  2919  func (c *Client4) DeleteIncomingWebhook(hookID string) (bool, *Response) {
  2920  	r, err := c.DoApiDelete(c.GetIncomingWebhookRoute(hookID))
  2921  	if err != nil {
  2922  		return false, BuildErrorResponse(r, err)
  2923  	}
  2924  	defer closeBody(r)
  2925  	return CheckStatusOK(r), BuildResponse(r)
  2926  }
  2927  
  2928  // CreateOutgoingWebhook creates an outgoing webhook for a team or channel.
  2929  func (c *Client4) CreateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
  2930  	r, err := c.DoApiPost(c.GetOutgoingWebhooksRoute(), hook.ToJson())
  2931  	if err != nil {
  2932  		return nil, BuildErrorResponse(r, err)
  2933  	}
  2934  	defer closeBody(r)
  2935  	return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2936  }
  2937  
  2938  // UpdateOutgoingWebhook creates an outgoing webhook for a team or channel.
  2939  func (c *Client4) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*OutgoingWebhook, *Response) {
  2940  	r, err := c.DoApiPut(c.GetOutgoingWebhookRoute(hook.Id), hook.ToJson())
  2941  	if err != nil {
  2942  		return nil, BuildErrorResponse(r, err)
  2943  	}
  2944  	defer closeBody(r)
  2945  	return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2946  }
  2947  
  2948  // GetOutgoingWebhooks returns a page of outgoing webhooks on the system. Page counting starts at 0.
  2949  func (c *Client4) GetOutgoingWebhooks(page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2950  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  2951  	r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag)
  2952  	if err != nil {
  2953  		return nil, BuildErrorResponse(r, err)
  2954  	}
  2955  	defer closeBody(r)
  2956  	return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2957  }
  2958  
  2959  // GetOutgoingWebhook outgoing webhooks on the system requested by Hook Id.
  2960  func (c *Client4) GetOutgoingWebhook(hookId string) (*OutgoingWebhook, *Response) {
  2961  	r, err := c.DoApiGet(c.GetOutgoingWebhookRoute(hookId), "")
  2962  	if err != nil {
  2963  		return nil, BuildErrorResponse(r, err)
  2964  	}
  2965  	defer closeBody(r)
  2966  	return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2967  }
  2968  
  2969  // GetOutgoingWebhooksForChannel returns a page of outgoing webhooks for a channel. Page counting starts at 0.
  2970  func (c *Client4) GetOutgoingWebhooksForChannel(channelId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2971  	query := fmt.Sprintf("?page=%v&per_page=%v&channel_id=%v", page, perPage, channelId)
  2972  	r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag)
  2973  	if err != nil {
  2974  		return nil, BuildErrorResponse(r, err)
  2975  	}
  2976  	defer closeBody(r)
  2977  	return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2978  }
  2979  
  2980  // GetOutgoingWebhooksForTeam returns a page of outgoing webhooks for a team. Page counting starts at 0.
  2981  func (c *Client4) GetOutgoingWebhooksForTeam(teamId string, page int, perPage int, etag string) ([]*OutgoingWebhook, *Response) {
  2982  	query := fmt.Sprintf("?page=%v&per_page=%v&team_id=%v", page, perPage, teamId)
  2983  	r, err := c.DoApiGet(c.GetOutgoingWebhooksRoute()+query, etag)
  2984  	if err != nil {
  2985  		return nil, BuildErrorResponse(r, err)
  2986  	}
  2987  	defer closeBody(r)
  2988  	return OutgoingWebhookListFromJson(r.Body), BuildResponse(r)
  2989  }
  2990  
  2991  // RegenOutgoingHookToken regenerate the outgoing webhook token.
  2992  func (c *Client4) RegenOutgoingHookToken(hookId string) (*OutgoingWebhook, *Response) {
  2993  	r, err := c.DoApiPost(c.GetOutgoingWebhookRoute(hookId)+"/regen_token", "")
  2994  	if err != nil {
  2995  		return nil, BuildErrorResponse(r, err)
  2996  	}
  2997  	defer closeBody(r)
  2998  	return OutgoingWebhookFromJson(r.Body), BuildResponse(r)
  2999  }
  3000  
  3001  // DeleteOutgoingWebhook delete the outgoing webhook on the system requested by Hook Id.
  3002  func (c *Client4) DeleteOutgoingWebhook(hookId string) (bool, *Response) {
  3003  	r, err := c.DoApiDelete(c.GetOutgoingWebhookRoute(hookId))
  3004  	if err != nil {
  3005  		return false, BuildErrorResponse(r, err)
  3006  	}
  3007  	defer closeBody(r)
  3008  	return CheckStatusOK(r), BuildResponse(r)
  3009  }
  3010  
  3011  // Preferences Section
  3012  
  3013  // GetPreferences returns the user's preferences.
  3014  func (c *Client4) GetPreferences(userId string) (Preferences, *Response) {
  3015  	r, err := c.DoApiGet(c.GetPreferencesRoute(userId), "")
  3016  	if err != nil {
  3017  		return nil, BuildErrorResponse(r, err)
  3018  	}
  3019  	defer closeBody(r)
  3020  	preferences, _ := PreferencesFromJson(r.Body)
  3021  	return preferences, BuildResponse(r)
  3022  }
  3023  
  3024  // UpdatePreferences saves the user's preferences.
  3025  func (c *Client4) UpdatePreferences(userId string, preferences *Preferences) (bool, *Response) {
  3026  	r, err := c.DoApiPut(c.GetPreferencesRoute(userId), preferences.ToJson())
  3027  	if err != nil {
  3028  		return false, BuildErrorResponse(r, err)
  3029  	}
  3030  	defer closeBody(r)
  3031  	return true, BuildResponse(r)
  3032  }
  3033  
  3034  // DeletePreferences deletes the user's preferences.
  3035  func (c *Client4) DeletePreferences(userId string, preferences *Preferences) (bool, *Response) {
  3036  	r, err := c.DoApiPost(c.GetPreferencesRoute(userId)+"/delete", preferences.ToJson())
  3037  	if err != nil {
  3038  		return false, BuildErrorResponse(r, err)
  3039  	}
  3040  	defer closeBody(r)
  3041  	return true, BuildResponse(r)
  3042  }
  3043  
  3044  // GetPreferencesByCategory returns the user's preferences from the provided category string.
  3045  func (c *Client4) GetPreferencesByCategory(userId string, category string) (Preferences, *Response) {
  3046  	url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s", category)
  3047  	r, err := c.DoApiGet(url, "")
  3048  	if err != nil {
  3049  		return nil, BuildErrorResponse(r, err)
  3050  	}
  3051  	defer closeBody(r)
  3052  	preferences, _ := PreferencesFromJson(r.Body)
  3053  	return preferences, BuildResponse(r)
  3054  }
  3055  
  3056  // GetPreferenceByCategoryAndName returns the user's preferences from the provided category and preference name string.
  3057  func (c *Client4) GetPreferenceByCategoryAndName(userId string, category string, preferenceName string) (*Preference, *Response) {
  3058  	url := fmt.Sprintf(c.GetPreferencesRoute(userId)+"/%s/name/%v", category, preferenceName)
  3059  	r, err := c.DoApiGet(url, "")
  3060  	if err != nil {
  3061  		return nil, BuildErrorResponse(r, err)
  3062  	}
  3063  	defer closeBody(r)
  3064  	return PreferenceFromJson(r.Body), BuildResponse(r)
  3065  }
  3066  
  3067  // SAML Section
  3068  
  3069  // GetSamlMetadata returns metadata for the SAML configuration.
  3070  func (c *Client4) GetSamlMetadata() (string, *Response) {
  3071  	r, err := c.DoApiGet(c.GetSamlRoute()+"/metadata", "")
  3072  	if err != nil {
  3073  		return "", BuildErrorResponse(r, err)
  3074  	}
  3075  	defer closeBody(r)
  3076  	buf := new(bytes.Buffer)
  3077  	_, _ = buf.ReadFrom(r.Body)
  3078  	return buf.String(), BuildResponse(r)
  3079  }
  3080  
  3081  func samlFileToMultipart(data []byte, filename string) ([]byte, *multipart.Writer, error) {
  3082  	body := &bytes.Buffer{}
  3083  	writer := multipart.NewWriter(body)
  3084  
  3085  	part, err := writer.CreateFormFile("certificate", filename)
  3086  	if err != nil {
  3087  		return nil, nil, err
  3088  	}
  3089  
  3090  	if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  3091  		return nil, nil, err
  3092  	}
  3093  
  3094  	if err := writer.Close(); err != nil {
  3095  		return nil, nil, err
  3096  	}
  3097  
  3098  	return body.Bytes(), writer, nil
  3099  }
  3100  
  3101  // UploadSamlIdpCertificate will upload an IDP certificate for SAML and set the config to use it.
  3102  // The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
  3103  func (c *Client4) UploadSamlIdpCertificate(data []byte, filename string) (bool, *Response) {
  3104  	body, writer, err := samlFileToMultipart(data, filename)
  3105  	if err != nil {
  3106  		return false, &Response{Error: NewAppError("UploadSamlIdpCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  3107  	}
  3108  
  3109  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/idp", body, writer.FormDataContentType())
  3110  	return resp.Error == nil, resp
  3111  }
  3112  
  3113  // UploadSamlPublicCertificate will upload a public certificate for SAML and set the config to use it.
  3114  // The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
  3115  func (c *Client4) UploadSamlPublicCertificate(data []byte, filename string) (bool, *Response) {
  3116  	body, writer, err := samlFileToMultipart(data, filename)
  3117  	if err != nil {
  3118  		return false, &Response{Error: NewAppError("UploadSamlPublicCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  3119  	}
  3120  
  3121  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/public", body, writer.FormDataContentType())
  3122  	return resp.Error == nil, resp
  3123  }
  3124  
  3125  // UploadSamlPrivateCertificate will upload a private key for SAML and set the config to use it.
  3126  // The filename parameter is deprecated and ignored: the server will pick a hard-coded filename when writing to disk.
  3127  func (c *Client4) UploadSamlPrivateCertificate(data []byte, filename string) (bool, *Response) {
  3128  	body, writer, err := samlFileToMultipart(data, filename)
  3129  	if err != nil {
  3130  		return false, &Response{Error: NewAppError("UploadSamlPrivateCertificate", "model.client.upload_saml_cert.app_error", nil, err.Error(), http.StatusBadRequest)}
  3131  	}
  3132  
  3133  	_, resp := c.DoUploadFile(c.GetSamlRoute()+"/certificate/private", body, writer.FormDataContentType())
  3134  	return resp.Error == nil, resp
  3135  }
  3136  
  3137  // DeleteSamlIdpCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  3138  func (c *Client4) DeleteSamlIdpCertificate() (bool, *Response) {
  3139  	r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/idp")
  3140  	if err != nil {
  3141  		return false, BuildErrorResponse(r, err)
  3142  	}
  3143  	defer closeBody(r)
  3144  	return CheckStatusOK(r), BuildResponse(r)
  3145  }
  3146  
  3147  // DeleteSamlPublicCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  3148  func (c *Client4) DeleteSamlPublicCertificate() (bool, *Response) {
  3149  	r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/public")
  3150  	if err != nil {
  3151  		return false, BuildErrorResponse(r, err)
  3152  	}
  3153  	defer closeBody(r)
  3154  	return CheckStatusOK(r), BuildResponse(r)
  3155  }
  3156  
  3157  // DeleteSamlPrivateCertificate deletes the SAML IDP certificate from the server and updates the config to not use it and disable SAML.
  3158  func (c *Client4) DeleteSamlPrivateCertificate() (bool, *Response) {
  3159  	r, err := c.DoApiDelete(c.GetSamlRoute() + "/certificate/private")
  3160  	if err != nil {
  3161  		return false, BuildErrorResponse(r, err)
  3162  	}
  3163  	defer closeBody(r)
  3164  	return CheckStatusOK(r), BuildResponse(r)
  3165  }
  3166  
  3167  // GetSamlCertificateStatus returns metadata for the SAML configuration.
  3168  func (c *Client4) GetSamlCertificateStatus() (*SamlCertificateStatus, *Response) {
  3169  	r, err := c.DoApiGet(c.GetSamlRoute()+"/certificate/status", "")
  3170  	if err != nil {
  3171  		return nil, BuildErrorResponse(r, err)
  3172  	}
  3173  	defer closeBody(r)
  3174  	return SamlCertificateStatusFromJson(r.Body), BuildResponse(r)
  3175  }
  3176  
  3177  // Compliance Section
  3178  
  3179  // CreateComplianceReport creates an incoming webhook for a channel.
  3180  func (c *Client4) CreateComplianceReport(report *Compliance) (*Compliance, *Response) {
  3181  	r, err := c.DoApiPost(c.GetComplianceReportsRoute(), report.ToJson())
  3182  	if err != nil {
  3183  		return nil, BuildErrorResponse(r, err)
  3184  	}
  3185  	defer closeBody(r)
  3186  	return ComplianceFromJson(r.Body), BuildResponse(r)
  3187  }
  3188  
  3189  // GetComplianceReports returns list of compliance reports.
  3190  func (c *Client4) GetComplianceReports(page, perPage int) (Compliances, *Response) {
  3191  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3192  	r, err := c.DoApiGet(c.GetComplianceReportsRoute()+query, "")
  3193  	if err != nil {
  3194  		return nil, BuildErrorResponse(r, err)
  3195  	}
  3196  	defer closeBody(r)
  3197  	return CompliancesFromJson(r.Body), BuildResponse(r)
  3198  }
  3199  
  3200  // GetComplianceReport returns a compliance report.
  3201  func (c *Client4) GetComplianceReport(reportId string) (*Compliance, *Response) {
  3202  	r, err := c.DoApiGet(c.GetComplianceReportRoute(reportId), "")
  3203  	if err != nil {
  3204  		return nil, BuildErrorResponse(r, err)
  3205  	}
  3206  	defer closeBody(r)
  3207  	return ComplianceFromJson(r.Body), BuildResponse(r)
  3208  }
  3209  
  3210  // DownloadComplianceReport returns a full compliance report as a file.
  3211  func (c *Client4) DownloadComplianceReport(reportId string) ([]byte, *Response) {
  3212  	rq, err := http.NewRequest("GET", c.ApiUrl+c.GetComplianceReportRoute(reportId), nil)
  3213  	if err != nil {
  3214  		return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  3215  	}
  3216  
  3217  	if len(c.AuthToken) > 0 {
  3218  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  3219  	}
  3220  
  3221  	rp, err := c.HttpClient.Do(rq)
  3222  	if err != nil || rp == nil {
  3223  		return nil, &Response{Error: NewAppError("DownloadComplianceReport", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  3224  	}
  3225  	defer closeBody(rp)
  3226  
  3227  	if rp.StatusCode >= 300 {
  3228  		return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  3229  	}
  3230  
  3231  	data, err := ioutil.ReadAll(rp.Body)
  3232  	if err != nil {
  3233  		return nil, BuildErrorResponse(rp, NewAppError("DownloadComplianceReport", "model.client.read_file.app_error", nil, err.Error(), rp.StatusCode))
  3234  	}
  3235  
  3236  	return data, BuildResponse(rp)
  3237  }
  3238  
  3239  // Cluster Section
  3240  
  3241  // GetClusterStatus returns the status of all the configured cluster nodes.
  3242  func (c *Client4) GetClusterStatus() ([]*ClusterInfo, *Response) {
  3243  	r, err := c.DoApiGet(c.GetClusterRoute()+"/status", "")
  3244  	if err != nil {
  3245  		return nil, BuildErrorResponse(r, err)
  3246  	}
  3247  	defer closeBody(r)
  3248  	return ClusterInfosFromJson(r.Body), BuildResponse(r)
  3249  }
  3250  
  3251  // LDAP Section
  3252  
  3253  // SyncLdap will force a sync with the configured LDAP server.
  3254  func (c *Client4) SyncLdap() (bool, *Response) {
  3255  	r, err := c.DoApiPost(c.GetLdapRoute()+"/sync", "")
  3256  	if err != nil {
  3257  		return false, BuildErrorResponse(r, err)
  3258  	}
  3259  	defer closeBody(r)
  3260  	return CheckStatusOK(r), BuildResponse(r)
  3261  }
  3262  
  3263  // TestLdap will attempt to connect to the configured LDAP server and return OK if configured
  3264  // correctly.
  3265  func (c *Client4) TestLdap() (bool, *Response) {
  3266  	r, err := c.DoApiPost(c.GetLdapRoute()+"/test", "")
  3267  	if err != nil {
  3268  		return false, BuildErrorResponse(r, err)
  3269  	}
  3270  	defer closeBody(r)
  3271  	return CheckStatusOK(r), BuildResponse(r)
  3272  }
  3273  
  3274  // GetLdapGroups retrieves the immediate child groups of the given parent group.
  3275  func (c *Client4) GetLdapGroups() ([]*Group, *Response) {
  3276  	path := fmt.Sprintf("%s/groups", c.GetLdapRoute())
  3277  
  3278  	r, appErr := c.DoApiGet(path, "")
  3279  	if appErr != nil {
  3280  		return nil, BuildErrorResponse(r, appErr)
  3281  	}
  3282  	defer closeBody(r)
  3283  
  3284  	return GroupsFromJson(r.Body), BuildResponse(r)
  3285  }
  3286  
  3287  // LinkLdapGroup creates or undeletes a Mattermost group and associates it to the given LDAP group DN.
  3288  func (c *Client4) LinkLdapGroup(dn string) (*Group, *Response) {
  3289  	path := fmt.Sprintf("%s/groups/%s/link", c.GetLdapRoute(), dn)
  3290  
  3291  	r, appErr := c.DoApiPost(path, "")
  3292  	if appErr != nil {
  3293  		return nil, BuildErrorResponse(r, appErr)
  3294  	}
  3295  	defer closeBody(r)
  3296  
  3297  	return GroupFromJson(r.Body), BuildResponse(r)
  3298  }
  3299  
  3300  // UnlinkLdapGroup deletes the Mattermost group associated with the given LDAP group DN.
  3301  func (c *Client4) UnlinkLdapGroup(dn string) (*Group, *Response) {
  3302  	path := fmt.Sprintf("%s/groups/%s/link", c.GetLdapRoute(), dn)
  3303  
  3304  	r, appErr := c.DoApiDelete(path)
  3305  	if appErr != nil {
  3306  		return nil, BuildErrorResponse(r, appErr)
  3307  	}
  3308  	defer closeBody(r)
  3309  
  3310  	return GroupFromJson(r.Body), BuildResponse(r)
  3311  }
  3312  
  3313  // Audits Section
  3314  
  3315  // GetAudits returns a list of audits for the whole system.
  3316  func (c *Client4) GetAudits(page int, perPage int, etag string) (Audits, *Response) {
  3317  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3318  	r, err := c.DoApiGet("/audits"+query, etag)
  3319  	if err != nil {
  3320  		return nil, BuildErrorResponse(r, err)
  3321  	}
  3322  	defer closeBody(r)
  3323  	return AuditsFromJson(r.Body), BuildResponse(r)
  3324  }
  3325  
  3326  // Brand Section
  3327  
  3328  // GetBrandImage retrieves the previously uploaded brand image.
  3329  func (c *Client4) GetBrandImage() ([]byte, *Response) {
  3330  	r, appErr := c.DoApiGet(c.GetBrandRoute()+"/image", "")
  3331  	if appErr != nil {
  3332  		return nil, BuildErrorResponse(r, appErr)
  3333  	}
  3334  	defer closeBody(r)
  3335  
  3336  	if r.StatusCode >= 300 {
  3337  		return nil, BuildErrorResponse(r, AppErrorFromJson(r.Body))
  3338  	}
  3339  
  3340  	data, err := ioutil.ReadAll(r.Body)
  3341  	if err != nil {
  3342  		return nil, BuildErrorResponse(r, NewAppError("GetBrandImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  3343  	}
  3344  
  3345  	return data, BuildResponse(r)
  3346  }
  3347  
  3348  // DeleteBrandImage delets the brand image for the system.
  3349  func (c *Client4) DeleteBrandImage() *Response {
  3350  	r, err := c.DoApiDelete(c.GetBrandRoute() + "/image")
  3351  	if err != nil {
  3352  		return BuildErrorResponse(r, err)
  3353  	}
  3354  	return BuildResponse(r)
  3355  }
  3356  
  3357  // UploadBrandImage sets the brand image for the system.
  3358  func (c *Client4) UploadBrandImage(data []byte) (bool, *Response) {
  3359  	body := &bytes.Buffer{}
  3360  	writer := multipart.NewWriter(body)
  3361  
  3362  	part, err := writer.CreateFormFile("image", "brand.png")
  3363  	if err != nil {
  3364  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  3365  	}
  3366  
  3367  	if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  3368  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.no_file.app_error", nil, err.Error(), http.StatusBadRequest)}
  3369  	}
  3370  
  3371  	if err = writer.Close(); err != nil {
  3372  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.set_profile_user.writer.app_error", nil, err.Error(), http.StatusBadRequest)}
  3373  	}
  3374  
  3375  	rq, err := http.NewRequest("POST", c.ApiUrl+c.GetBrandRoute()+"/image", bytes.NewReader(body.Bytes()))
  3376  	if err != nil {
  3377  		return false, &Response{Error: NewAppError("UploadBrandImage", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  3378  	}
  3379  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  3380  
  3381  	if len(c.AuthToken) > 0 {
  3382  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  3383  	}
  3384  
  3385  	rp, err := c.HttpClient.Do(rq)
  3386  	if err != nil || rp == nil {
  3387  		return false, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.GetBrandRoute()+"/image", "model.client.connecting.app_error", nil, err.Error(), http.StatusForbidden)}
  3388  	}
  3389  	defer closeBody(rp)
  3390  
  3391  	if rp.StatusCode >= 300 {
  3392  		return false, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  3393  	}
  3394  
  3395  	return CheckStatusOK(rp), BuildResponse(rp)
  3396  }
  3397  
  3398  // Logs Section
  3399  
  3400  // GetLogs page of logs as a string array.
  3401  func (c *Client4) GetLogs(page, perPage int) ([]string, *Response) {
  3402  	query := fmt.Sprintf("?page=%v&logs_per_page=%v", page, perPage)
  3403  	r, err := c.DoApiGet("/logs"+query, "")
  3404  	if err != nil {
  3405  		return nil, BuildErrorResponse(r, err)
  3406  	}
  3407  	defer closeBody(r)
  3408  	return ArrayFromJson(r.Body), BuildResponse(r)
  3409  }
  3410  
  3411  // PostLog is a convenience Web Service call so clients can log messages into
  3412  // the server-side logs. For example we typically log javascript error messages
  3413  // into the server-side. It returns the log message if the logging was successful.
  3414  func (c *Client4) PostLog(message map[string]string) (map[string]string, *Response) {
  3415  	r, err := c.DoApiPost("/logs", MapToJson(message))
  3416  	if err != nil {
  3417  		return nil, BuildErrorResponse(r, err)
  3418  	}
  3419  	defer closeBody(r)
  3420  	return MapFromJson(r.Body), BuildResponse(r)
  3421  }
  3422  
  3423  // OAuth Section
  3424  
  3425  // CreateOAuthApp will register a new OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  3426  func (c *Client4) CreateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
  3427  	r, err := c.DoApiPost(c.GetOAuthAppsRoute(), app.ToJson())
  3428  	if err != nil {
  3429  		return nil, BuildErrorResponse(r, err)
  3430  	}
  3431  	defer closeBody(r)
  3432  	return OAuthAppFromJson(r.Body), BuildResponse(r)
  3433  }
  3434  
  3435  // UpdateOAuthApp updates a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
  3436  func (c *Client4) UpdateOAuthApp(app *OAuthApp) (*OAuthApp, *Response) {
  3437  	r, err := c.DoApiPut(c.GetOAuthAppRoute(app.Id), app.ToJson())
  3438  	if err != nil {
  3439  		return nil, BuildErrorResponse(r, err)
  3440  	}
  3441  	defer closeBody(r)
  3442  	return OAuthAppFromJson(r.Body), BuildResponse(r)
  3443  }
  3444  
  3445  // GetOAuthApps gets a page of registered OAuth 2.0 client applications with Mattermost acting as an OAuth 2.0 service provider.
  3446  func (c *Client4) GetOAuthApps(page, perPage int) ([]*OAuthApp, *Response) {
  3447  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3448  	r, err := c.DoApiGet(c.GetOAuthAppsRoute()+query, "")
  3449  	if err != nil {
  3450  		return nil, BuildErrorResponse(r, err)
  3451  	}
  3452  	defer closeBody(r)
  3453  	return OAuthAppListFromJson(r.Body), BuildResponse(r)
  3454  }
  3455  
  3456  // GetOAuthApp gets a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  3457  func (c *Client4) GetOAuthApp(appId string) (*OAuthApp, *Response) {
  3458  	r, err := c.DoApiGet(c.GetOAuthAppRoute(appId), "")
  3459  	if err != nil {
  3460  		return nil, BuildErrorResponse(r, err)
  3461  	}
  3462  	defer closeBody(r)
  3463  	return OAuthAppFromJson(r.Body), BuildResponse(r)
  3464  }
  3465  
  3466  // GetOAuthAppInfo gets a sanitized version of a registered OAuth 2.0 client application with Mattermost acting as an OAuth 2.0 service provider.
  3467  func (c *Client4) GetOAuthAppInfo(appId string) (*OAuthApp, *Response) {
  3468  	r, err := c.DoApiGet(c.GetOAuthAppRoute(appId)+"/info", "")
  3469  	if err != nil {
  3470  		return nil, BuildErrorResponse(r, err)
  3471  	}
  3472  	defer closeBody(r)
  3473  	return OAuthAppFromJson(r.Body), BuildResponse(r)
  3474  }
  3475  
  3476  // DeleteOAuthApp deletes a registered OAuth 2.0 client application.
  3477  func (c *Client4) DeleteOAuthApp(appId string) (bool, *Response) {
  3478  	r, err := c.DoApiDelete(c.GetOAuthAppRoute(appId))
  3479  	if err != nil {
  3480  		return false, BuildErrorResponse(r, err)
  3481  	}
  3482  	defer closeBody(r)
  3483  	return CheckStatusOK(r), BuildResponse(r)
  3484  }
  3485  
  3486  // RegenerateOAuthAppSecret regenerates the client secret for a registered OAuth 2.0 client application.
  3487  func (c *Client4) RegenerateOAuthAppSecret(appId string) (*OAuthApp, *Response) {
  3488  	r, err := c.DoApiPost(c.GetOAuthAppRoute(appId)+"/regen_secret", "")
  3489  	if err != nil {
  3490  		return nil, BuildErrorResponse(r, err)
  3491  	}
  3492  	defer closeBody(r)
  3493  	return OAuthAppFromJson(r.Body), BuildResponse(r)
  3494  }
  3495  
  3496  // GetAuthorizedOAuthAppsForUser gets a page of OAuth 2.0 client applications the user has authorized to use access their account.
  3497  func (c *Client4) GetAuthorizedOAuthAppsForUser(userId string, page, perPage int) ([]*OAuthApp, *Response) {
  3498  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3499  	r, err := c.DoApiGet(c.GetUserRoute(userId)+"/oauth/apps/authorized"+query, "")
  3500  	if err != nil {
  3501  		return nil, BuildErrorResponse(r, err)
  3502  	}
  3503  	defer closeBody(r)
  3504  	return OAuthAppListFromJson(r.Body), BuildResponse(r)
  3505  }
  3506  
  3507  // AuthorizeOAuthApp will authorize an OAuth 2.0 client application to access a user's account and provide a redirect link to follow.
  3508  func (c *Client4) AuthorizeOAuthApp(authRequest *AuthorizeRequest) (string, *Response) {
  3509  	r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/authorize", authRequest.ToJson(), "")
  3510  	if err != nil {
  3511  		return "", BuildErrorResponse(r, err)
  3512  	}
  3513  	defer closeBody(r)
  3514  	return MapFromJson(r.Body)["redirect"], BuildResponse(r)
  3515  }
  3516  
  3517  // DeauthorizeOAuthApp will deauthorize an OAuth 2.0 client application from accessing a user's account.
  3518  func (c *Client4) DeauthorizeOAuthApp(appId string) (bool, *Response) {
  3519  	requestData := map[string]string{"client_id": appId}
  3520  	r, err := c.DoApiRequest(http.MethodPost, c.Url+"/oauth/deauthorize", MapToJson(requestData), "")
  3521  	if err != nil {
  3522  		return false, BuildErrorResponse(r, err)
  3523  	}
  3524  	defer closeBody(r)
  3525  	return CheckStatusOK(r), BuildResponse(r)
  3526  }
  3527  
  3528  // GetOAuthAccessToken is a test helper function for the OAuth access token endpoint.
  3529  func (c *Client4) GetOAuthAccessToken(data url.Values) (*AccessResponse, *Response) {
  3530  	rq, err := http.NewRequest(http.MethodPost, c.Url+"/oauth/access_token", strings.NewReader(data.Encode()))
  3531  	if err != nil {
  3532  		return nil, &Response{Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  3533  	}
  3534  	rq.Header.Set("Content-Type", "application/x-www-form-urlencoded")
  3535  
  3536  	if len(c.AuthToken) > 0 {
  3537  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  3538  	}
  3539  
  3540  	rp, err := c.HttpClient.Do(rq)
  3541  	if err != nil || rp == nil {
  3542  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError(c.Url+"/oauth/access_token", "model.client.connecting.app_error", nil, err.Error(), 403)}
  3543  	}
  3544  	defer closeBody(rp)
  3545  
  3546  	if rp.StatusCode >= 300 {
  3547  		return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  3548  	}
  3549  
  3550  	return AccessResponseFromJson(rp.Body), BuildResponse(rp)
  3551  }
  3552  
  3553  // Elasticsearch Section
  3554  
  3555  // TestElasticsearch will attempt to connect to the configured Elasticsearch server and return OK if configured.
  3556  // correctly.
  3557  func (c *Client4) TestElasticsearch() (bool, *Response) {
  3558  	r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/test", "")
  3559  	if err != nil {
  3560  		return false, BuildErrorResponse(r, err)
  3561  	}
  3562  	defer closeBody(r)
  3563  	return CheckStatusOK(r), BuildResponse(r)
  3564  }
  3565  
  3566  // PurgeElasticsearchIndexes immediately deletes all Elasticsearch indexes.
  3567  func (c *Client4) PurgeElasticsearchIndexes() (bool, *Response) {
  3568  	r, err := c.DoApiPost(c.GetElasticsearchRoute()+"/purge_indexes", "")
  3569  	if err != nil {
  3570  		return false, BuildErrorResponse(r, err)
  3571  	}
  3572  	defer closeBody(r)
  3573  	return CheckStatusOK(r), BuildResponse(r)
  3574  }
  3575  
  3576  // Data Retention Section
  3577  
  3578  // GetDataRetentionPolicy will get the current server data retention policy details.
  3579  func (c *Client4) GetDataRetentionPolicy() (*DataRetentionPolicy, *Response) {
  3580  	r, err := c.DoApiGet(c.GetDataRetentionRoute()+"/policy", "")
  3581  	if err != nil {
  3582  		return nil, BuildErrorResponse(r, err)
  3583  	}
  3584  	defer closeBody(r)
  3585  	return DataRetentionPolicyFromJson(r.Body), BuildResponse(r)
  3586  }
  3587  
  3588  // Commands Section
  3589  
  3590  // CreateCommand will create a new command if the user have the right permissions.
  3591  func (c *Client4) CreateCommand(cmd *Command) (*Command, *Response) {
  3592  	r, err := c.DoApiPost(c.GetCommandsRoute(), cmd.ToJson())
  3593  	if err != nil {
  3594  		return nil, BuildErrorResponse(r, err)
  3595  	}
  3596  	defer closeBody(r)
  3597  	return CommandFromJson(r.Body), BuildResponse(r)
  3598  }
  3599  
  3600  // UpdateCommand updates a command based on the provided Command struct.
  3601  func (c *Client4) UpdateCommand(cmd *Command) (*Command, *Response) {
  3602  	r, err := c.DoApiPut(c.GetCommandRoute(cmd.Id), cmd.ToJson())
  3603  	if err != nil {
  3604  		return nil, BuildErrorResponse(r, err)
  3605  	}
  3606  	defer closeBody(r)
  3607  	return CommandFromJson(r.Body), BuildResponse(r)
  3608  }
  3609  
  3610  // DeleteCommand deletes a command based on the provided command id string.
  3611  func (c *Client4) DeleteCommand(commandId string) (bool, *Response) {
  3612  	r, err := c.DoApiDelete(c.GetCommandRoute(commandId))
  3613  	if err != nil {
  3614  		return false, BuildErrorResponse(r, err)
  3615  	}
  3616  	defer closeBody(r)
  3617  	return CheckStatusOK(r), BuildResponse(r)
  3618  }
  3619  
  3620  // ListCommands will retrieve a list of commands available in the team.
  3621  func (c *Client4) ListCommands(teamId string, customOnly bool) ([]*Command, *Response) {
  3622  	query := fmt.Sprintf("?team_id=%v&custom_only=%v", teamId, customOnly)
  3623  	r, err := c.DoApiGet(c.GetCommandsRoute()+query, "")
  3624  	if err != nil {
  3625  		return nil, BuildErrorResponse(r, err)
  3626  	}
  3627  	defer closeBody(r)
  3628  	return CommandListFromJson(r.Body), BuildResponse(r)
  3629  }
  3630  
  3631  // ExecuteCommand executes a given slash command.
  3632  func (c *Client4) ExecuteCommand(channelId, command string) (*CommandResponse, *Response) {
  3633  	commandArgs := &CommandArgs{
  3634  		ChannelId: channelId,
  3635  		Command:   command,
  3636  	}
  3637  	r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson())
  3638  	if err != nil {
  3639  		return nil, BuildErrorResponse(r, err)
  3640  	}
  3641  	defer closeBody(r)
  3642  
  3643  	response, _ := CommandResponseFromJson(r.Body)
  3644  	return response, BuildResponse(r)
  3645  }
  3646  
  3647  // ExecuteCommandWithTeam executes a given slash command against the specified team.
  3648  // Use this when executing slash commands in a DM/GM, since the team id cannot be inferred in that case.
  3649  func (c *Client4) ExecuteCommandWithTeam(channelId, teamId, command string) (*CommandResponse, *Response) {
  3650  	commandArgs := &CommandArgs{
  3651  		ChannelId: channelId,
  3652  		TeamId:    teamId,
  3653  		Command:   command,
  3654  	}
  3655  	r, err := c.DoApiPost(c.GetCommandsRoute()+"/execute", commandArgs.ToJson())
  3656  	if err != nil {
  3657  		return nil, BuildErrorResponse(r, err)
  3658  	}
  3659  	defer closeBody(r)
  3660  
  3661  	response, _ := CommandResponseFromJson(r.Body)
  3662  	return response, BuildResponse(r)
  3663  }
  3664  
  3665  // ListAutocompleteCommands will retrieve a list of commands available in the team.
  3666  func (c *Client4) ListAutocompleteCommands(teamId string) ([]*Command, *Response) {
  3667  	r, err := c.DoApiGet(c.GetTeamAutoCompleteCommandsRoute(teamId), "")
  3668  	if err != nil {
  3669  		return nil, BuildErrorResponse(r, err)
  3670  	}
  3671  	defer closeBody(r)
  3672  	return CommandListFromJson(r.Body), BuildResponse(r)
  3673  }
  3674  
  3675  // RegenCommandToken will create a new token if the user have the right permissions.
  3676  func (c *Client4) RegenCommandToken(commandId string) (string, *Response) {
  3677  	r, err := c.DoApiPut(c.GetCommandRoute(commandId)+"/regen_token", "")
  3678  	if err != nil {
  3679  		return "", BuildErrorResponse(r, err)
  3680  	}
  3681  	defer closeBody(r)
  3682  	return MapFromJson(r.Body)["token"], BuildResponse(r)
  3683  }
  3684  
  3685  // Status Section
  3686  
  3687  // GetUserStatus returns a user based on the provided user id string.
  3688  func (c *Client4) GetUserStatus(userId, etag string) (*Status, *Response) {
  3689  	r, err := c.DoApiGet(c.GetUserStatusRoute(userId), etag)
  3690  	if err != nil {
  3691  		return nil, BuildErrorResponse(r, err)
  3692  	}
  3693  	defer closeBody(r)
  3694  	return StatusFromJson(r.Body), BuildResponse(r)
  3695  }
  3696  
  3697  // GetUsersStatusesByIds returns a list of users status based on the provided user ids.
  3698  func (c *Client4) GetUsersStatusesByIds(userIds []string) ([]*Status, *Response) {
  3699  	r, err := c.DoApiPost(c.GetUserStatusesRoute()+"/ids", ArrayToJson(userIds))
  3700  	if err != nil {
  3701  		return nil, BuildErrorResponse(r, err)
  3702  	}
  3703  	defer closeBody(r)
  3704  	return StatusListFromJson(r.Body), BuildResponse(r)
  3705  }
  3706  
  3707  // UpdateUserStatus sets a user's status based on the provided user id string.
  3708  func (c *Client4) UpdateUserStatus(userId string, userStatus *Status) (*Status, *Response) {
  3709  	r, err := c.DoApiPut(c.GetUserStatusRoute(userId), userStatus.ToJson())
  3710  	if err != nil {
  3711  		return nil, BuildErrorResponse(r, err)
  3712  	}
  3713  	defer closeBody(r)
  3714  	return StatusFromJson(r.Body), BuildResponse(r)
  3715  }
  3716  
  3717  // Emoji Section
  3718  
  3719  // CreateEmoji will save an emoji to the server if the current user has permission
  3720  // to do so. If successful, the provided emoji will be returned with its Id field
  3721  // filled in. Otherwise, an error will be returned.
  3722  func (c *Client4) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *Response) {
  3723  	body := &bytes.Buffer{}
  3724  	writer := multipart.NewWriter(body)
  3725  
  3726  	part, err := writer.CreateFormFile("image", filename)
  3727  	if err != nil {
  3728  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
  3729  	}
  3730  
  3731  	if _, err := io.Copy(part, bytes.NewBuffer(image)); err != nil {
  3732  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)}
  3733  	}
  3734  
  3735  	if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
  3736  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)}
  3737  	}
  3738  
  3739  	if err := writer.Close(); err != nil {
  3740  		return nil, &Response{StatusCode: http.StatusForbidden, Error: NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)}
  3741  	}
  3742  
  3743  	return c.DoEmojiUploadFile(c.GetEmojisRoute(), body.Bytes(), writer.FormDataContentType())
  3744  }
  3745  
  3746  // GetEmojiList returns a page of custom emoji on the system.
  3747  func (c *Client4) GetEmojiList(page, perPage int) ([]*Emoji, *Response) {
  3748  	query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
  3749  	r, err := c.DoApiGet(c.GetEmojisRoute()+query, "")
  3750  	if err != nil {
  3751  		return nil, BuildErrorResponse(r, err)
  3752  	}
  3753  	defer closeBody(r)
  3754  	return EmojiListFromJson(r.Body), BuildResponse(r)
  3755  }
  3756  
  3757  // GetSortedEmojiList returns a page of custom emoji on the system sorted based on the sort
  3758  // parameter, blank for no sorting and "name" to sort by emoji names.
  3759  func (c *Client4) GetSortedEmojiList(page, perPage int, sort string) ([]*Emoji, *Response) {
  3760  	query := fmt.Sprintf("?page=%v&per_page=%v&sort=%v", page, perPage, sort)
  3761  	r, err := c.DoApiGet(c.GetEmojisRoute()+query, "")
  3762  	if err != nil {
  3763  		return nil, BuildErrorResponse(r, err)
  3764  	}
  3765  	defer closeBody(r)
  3766  	return EmojiListFromJson(r.Body), BuildResponse(r)
  3767  }
  3768  
  3769  // DeleteEmoji delete an custom emoji on the provided emoji id string.
  3770  func (c *Client4) DeleteEmoji(emojiId string) (bool, *Response) {
  3771  	r, err := c.DoApiDelete(c.GetEmojiRoute(emojiId))
  3772  	if err != nil {
  3773  		return false, BuildErrorResponse(r, err)
  3774  	}
  3775  	defer closeBody(r)
  3776  	return CheckStatusOK(r), BuildResponse(r)
  3777  }
  3778  
  3779  // GetEmoji returns a custom emoji based on the emojiId string.
  3780  func (c *Client4) GetEmoji(emojiId string) (*Emoji, *Response) {
  3781  	r, err := c.DoApiGet(c.GetEmojiRoute(emojiId), "")
  3782  	if err != nil {
  3783  		return nil, BuildErrorResponse(r, err)
  3784  	}
  3785  	defer closeBody(r)
  3786  	return EmojiFromJson(r.Body), BuildResponse(r)
  3787  }
  3788  
  3789  // GetEmojiByName returns a custom emoji based on the name string.
  3790  func (c *Client4) GetEmojiByName(name string) (*Emoji, *Response) {
  3791  	r, err := c.DoApiGet(c.GetEmojiByNameRoute(name), "")
  3792  	if err != nil {
  3793  		return nil, BuildErrorResponse(r, err)
  3794  	}
  3795  	defer closeBody(r)
  3796  	return EmojiFromJson(r.Body), BuildResponse(r)
  3797  }
  3798  
  3799  // GetEmojiImage returns the emoji image.
  3800  func (c *Client4) GetEmojiImage(emojiId string) ([]byte, *Response) {
  3801  	r, apErr := c.DoApiGet(c.GetEmojiRoute(emojiId)+"/image", "")
  3802  	if apErr != nil {
  3803  		return nil, BuildErrorResponse(r, apErr)
  3804  	}
  3805  	defer closeBody(r)
  3806  
  3807  	data, err := ioutil.ReadAll(r.Body)
  3808  	if err != nil {
  3809  		return nil, BuildErrorResponse(r, NewAppError("GetEmojiImage", "model.client.read_file.app_error", nil, err.Error(), r.StatusCode))
  3810  	}
  3811  
  3812  	return data, BuildResponse(r)
  3813  }
  3814  
  3815  // SearchEmoji returns a list of emoji matching some search criteria.
  3816  func (c *Client4) SearchEmoji(search *EmojiSearch) ([]*Emoji, *Response) {
  3817  	r, err := c.DoApiPost(c.GetEmojisRoute()+"/search", search.ToJson())
  3818  	if err != nil {
  3819  		return nil, BuildErrorResponse(r, err)
  3820  	}
  3821  	defer closeBody(r)
  3822  	return EmojiListFromJson(r.Body), BuildResponse(r)
  3823  }
  3824  
  3825  // AutocompleteEmoji returns a list of emoji starting with or matching name.
  3826  func (c *Client4) AutocompleteEmoji(name string, etag string) ([]*Emoji, *Response) {
  3827  	query := fmt.Sprintf("?name=%v", name)
  3828  	r, err := c.DoApiGet(c.GetEmojisRoute()+"/autocomplete"+query, "")
  3829  	if err != nil {
  3830  		return nil, BuildErrorResponse(r, err)
  3831  	}
  3832  	defer closeBody(r)
  3833  	return EmojiListFromJson(r.Body), BuildResponse(r)
  3834  }
  3835  
  3836  // Reaction Section
  3837  
  3838  // SaveReaction saves an emoji reaction for a post. Returns the saved reaction if successful, otherwise an error will be returned.
  3839  func (c *Client4) SaveReaction(reaction *Reaction) (*Reaction, *Response) {
  3840  	r, err := c.DoApiPost(c.GetReactionsRoute(), reaction.ToJson())
  3841  	if err != nil {
  3842  		return nil, BuildErrorResponse(r, err)
  3843  	}
  3844  	defer closeBody(r)
  3845  	return ReactionFromJson(r.Body), BuildResponse(r)
  3846  }
  3847  
  3848  // GetReactions returns a list of reactions to a post.
  3849  func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) {
  3850  	r, err := c.DoApiGet(c.GetPostRoute(postId)+"/reactions", "")
  3851  	if err != nil {
  3852  		return nil, BuildErrorResponse(r, err)
  3853  	}
  3854  	defer closeBody(r)
  3855  	return ReactionsFromJson(r.Body), BuildResponse(r)
  3856  }
  3857  
  3858  // DeleteReaction deletes reaction of a user in a post.
  3859  func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) {
  3860  	r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName))
  3861  	if err != nil {
  3862  		return false, BuildErrorResponse(r, err)
  3863  	}
  3864  	defer closeBody(r)
  3865  	return CheckStatusOK(r), BuildResponse(r)
  3866  }
  3867  
  3868  // FetchBulkReactions returns a map of postIds and corresponding reactions
  3869  func (c *Client4) GetBulkReactions(postIds []string) (map[string][]*Reaction, *Response) {
  3870  	r, err := c.DoApiPost(c.GetPostsRoute()+"/ids/reactions", ArrayToJson(postIds))
  3871  	if err != nil {
  3872  		return nil, BuildErrorResponse(r, err)
  3873  	}
  3874  	defer closeBody(r)
  3875  	return MapPostIdToReactionsFromJson(r.Body), BuildResponse(r)
  3876  }
  3877  
  3878  // Timezone Section
  3879  
  3880  // GetSupportedTimezone returns a page of supported timezones on the system.
  3881  func (c *Client4) GetSupportedTimezone() ([]string, *Response) {
  3882  	r, err := c.DoApiGet(c.GetTimezonesRoute(), "")
  3883  	if err != nil {
  3884  		return nil, BuildErrorResponse(r, err)
  3885  	}
  3886  	defer closeBody(r)
  3887  	var timezones []string
  3888  	json.NewDecoder(r.Body).Decode(&timezones)
  3889  	return timezones, BuildResponse(r)
  3890  }
  3891  
  3892  // Open Graph Metadata Section
  3893  
  3894  // OpenGraph return the open graph metadata for a particular url if the site have the metadata.
  3895  func (c *Client4) OpenGraph(url string) (map[string]string, *Response) {
  3896  	requestBody := make(map[string]string)
  3897  	requestBody["url"] = url
  3898  
  3899  	r, err := c.DoApiPost(c.GetOpenGraphRoute(), MapToJson(requestBody))
  3900  	if err != nil {
  3901  		return nil, BuildErrorResponse(r, err)
  3902  	}
  3903  	defer closeBody(r)
  3904  	return MapFromJson(r.Body), BuildResponse(r)
  3905  }
  3906  
  3907  // Jobs Section
  3908  
  3909  // GetJob gets a single job.
  3910  func (c *Client4) GetJob(id string) (*Job, *Response) {
  3911  	r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/%v", id), "")
  3912  	if err != nil {
  3913  		return nil, BuildErrorResponse(r, err)
  3914  	}
  3915  	defer closeBody(r)
  3916  	return JobFromJson(r.Body), BuildResponse(r)
  3917  }
  3918  
  3919  // GetJobs gets all jobs, sorted with the job that was created most recently first.
  3920  func (c *Client4) GetJobs(page int, perPage int) ([]*Job, *Response) {
  3921  	r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("?page=%v&per_page=%v", page, perPage), "")
  3922  	if err != nil {
  3923  		return nil, BuildErrorResponse(r, err)
  3924  	}
  3925  	defer closeBody(r)
  3926  	return JobsFromJson(r.Body), BuildResponse(r)
  3927  }
  3928  
  3929  // GetJobsByType gets all jobs of a given type, sorted with the job that was created most recently first.
  3930  func (c *Client4) GetJobsByType(jobType string, page int, perPage int) ([]*Job, *Response) {
  3931  	r, err := c.DoApiGet(c.GetJobsRoute()+fmt.Sprintf("/type/%v?page=%v&per_page=%v", jobType, page, perPage), "")
  3932  	if err != nil {
  3933  		return nil, BuildErrorResponse(r, err)
  3934  	}
  3935  	defer closeBody(r)
  3936  	return JobsFromJson(r.Body), BuildResponse(r)
  3937  }
  3938  
  3939  // CreateJob creates a job based on the provided job struct.
  3940  func (c *Client4) CreateJob(job *Job) (*Job, *Response) {
  3941  	r, err := c.DoApiPost(c.GetJobsRoute(), job.ToJson())
  3942  	if err != nil {
  3943  		return nil, BuildErrorResponse(r, err)
  3944  	}
  3945  	defer closeBody(r)
  3946  	return JobFromJson(r.Body), BuildResponse(r)
  3947  }
  3948  
  3949  // CancelJob requests the cancellation of the job with the provided Id.
  3950  func (c *Client4) CancelJob(jobId string) (bool, *Response) {
  3951  	r, err := c.DoApiPost(c.GetJobsRoute()+fmt.Sprintf("/%v/cancel", jobId), "")
  3952  	if err != nil {
  3953  		return false, BuildErrorResponse(r, err)
  3954  	}
  3955  	defer closeBody(r)
  3956  	return CheckStatusOK(r), BuildResponse(r)
  3957  }
  3958  
  3959  // Roles Section
  3960  
  3961  // GetRole gets a single role by ID.
  3962  func (c *Client4) GetRole(id string) (*Role, *Response) {
  3963  	r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/%v", id), "")
  3964  	if err != nil {
  3965  		return nil, BuildErrorResponse(r, err)
  3966  	}
  3967  	defer closeBody(r)
  3968  	return RoleFromJson(r.Body), BuildResponse(r)
  3969  }
  3970  
  3971  // GetRoleByName gets a single role by Name.
  3972  func (c *Client4) GetRoleByName(name string) (*Role, *Response) {
  3973  	r, err := c.DoApiGet(c.GetRolesRoute()+fmt.Sprintf("/name/%v", name), "")
  3974  	if err != nil {
  3975  		return nil, BuildErrorResponse(r, err)
  3976  	}
  3977  	defer closeBody(r)
  3978  	return RoleFromJson(r.Body), BuildResponse(r)
  3979  }
  3980  
  3981  // GetRolesByNames returns a list of roles based on the provided role names.
  3982  func (c *Client4) GetRolesByNames(roleNames []string) ([]*Role, *Response) {
  3983  	r, err := c.DoApiPost(c.GetRolesRoute()+"/names", ArrayToJson(roleNames))
  3984  	if err != nil {
  3985  		return nil, BuildErrorResponse(r, err)
  3986  	}
  3987  	defer closeBody(r)
  3988  	return RoleListFromJson(r.Body), BuildResponse(r)
  3989  }
  3990  
  3991  // PatchRole partially updates a role in the system. Any missing fields are not updated.
  3992  func (c *Client4) PatchRole(roleId string, patch *RolePatch) (*Role, *Response) {
  3993  	r, err := c.DoApiPut(c.GetRolesRoute()+fmt.Sprintf("/%v/patch", roleId), patch.ToJson())
  3994  	if err != nil {
  3995  		return nil, BuildErrorResponse(r, err)
  3996  	}
  3997  	defer closeBody(r)
  3998  	return RoleFromJson(r.Body), BuildResponse(r)
  3999  }
  4000  
  4001  // Schemes Section
  4002  
  4003  // CreateScheme creates a new Scheme.
  4004  func (c *Client4) CreateScheme(scheme *Scheme) (*Scheme, *Response) {
  4005  	r, err := c.DoApiPost(c.GetSchemesRoute(), scheme.ToJson())
  4006  	if err != nil {
  4007  		return nil, BuildErrorResponse(r, err)
  4008  	}
  4009  	defer closeBody(r)
  4010  	return SchemeFromJson(r.Body), BuildResponse(r)
  4011  }
  4012  
  4013  // GetScheme gets a single scheme by ID.
  4014  func (c *Client4) GetScheme(id string) (*Scheme, *Response) {
  4015  	r, err := c.DoApiGet(c.GetSchemeRoute(id), "")
  4016  	if err != nil {
  4017  		return nil, BuildErrorResponse(r, err)
  4018  	}
  4019  	defer closeBody(r)
  4020  	return SchemeFromJson(r.Body), BuildResponse(r)
  4021  }
  4022  
  4023  // GetSchemes gets all schemes, sorted with the most recently created first, optionally filtered by scope.
  4024  func (c *Client4) GetSchemes(scope string, page int, perPage int) ([]*Scheme, *Response) {
  4025  	r, err := c.DoApiGet(c.GetSchemesRoute()+fmt.Sprintf("?scope=%v&page=%v&per_page=%v", scope, page, perPage), "")
  4026  	if err != nil {
  4027  		return nil, BuildErrorResponse(r, err)
  4028  	}
  4029  	defer closeBody(r)
  4030  	return SchemesFromJson(r.Body), BuildResponse(r)
  4031  }
  4032  
  4033  // DeleteScheme deletes a single scheme by ID.
  4034  func (c *Client4) DeleteScheme(id string) (bool, *Response) {
  4035  	r, err := c.DoApiDelete(c.GetSchemeRoute(id))
  4036  	if err != nil {
  4037  		return false, BuildErrorResponse(r, err)
  4038  	}
  4039  	defer closeBody(r)
  4040  	return CheckStatusOK(r), BuildResponse(r)
  4041  }
  4042  
  4043  // PatchScheme partially updates a scheme in the system. Any missing fields are not updated.
  4044  func (c *Client4) PatchScheme(id string, patch *SchemePatch) (*Scheme, *Response) {
  4045  	r, err := c.DoApiPut(c.GetSchemeRoute(id)+"/patch", patch.ToJson())
  4046  	if err != nil {
  4047  		return nil, BuildErrorResponse(r, err)
  4048  	}
  4049  	defer closeBody(r)
  4050  	return SchemeFromJson(r.Body), BuildResponse(r)
  4051  }
  4052  
  4053  // GetTeamsForScheme gets the teams using this scheme, sorted alphabetically by display name.
  4054  func (c *Client4) GetTeamsForScheme(schemeId string, page int, perPage int) ([]*Team, *Response) {
  4055  	r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/teams?page=%v&per_page=%v", page, perPage), "")
  4056  	if err != nil {
  4057  		return nil, BuildErrorResponse(r, err)
  4058  	}
  4059  	defer closeBody(r)
  4060  	return TeamListFromJson(r.Body), BuildResponse(r)
  4061  }
  4062  
  4063  // GetChannelsForScheme gets the channels using this scheme, sorted alphabetically by display name.
  4064  func (c *Client4) GetChannelsForScheme(schemeId string, page int, perPage int) (ChannelList, *Response) {
  4065  	r, err := c.DoApiGet(c.GetSchemeRoute(schemeId)+fmt.Sprintf("/channels?page=%v&per_page=%v", page, perPage), "")
  4066  	if err != nil {
  4067  		return nil, BuildErrorResponse(r, err)
  4068  	}
  4069  	defer closeBody(r)
  4070  	return *ChannelListFromJson(r.Body), BuildResponse(r)
  4071  }
  4072  
  4073  // Plugin Section
  4074  
  4075  // UploadPlugin takes an io.Reader stream pointing to the contents of a .tar.gz plugin.
  4076  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4077  func (c *Client4) UploadPlugin(file io.Reader) (*Manifest, *Response) {
  4078  	return c.uploadPlugin(file, false)
  4079  }
  4080  
  4081  func (c *Client4) UploadPluginForced(file io.Reader) (*Manifest, *Response) {
  4082  	return c.uploadPlugin(file, true)
  4083  }
  4084  
  4085  func (c *Client4) uploadPlugin(file io.Reader, force bool) (*Manifest, *Response) {
  4086  	body := new(bytes.Buffer)
  4087  	writer := multipart.NewWriter(body)
  4088  
  4089  	if force {
  4090  		err := writer.WriteField("force", "true")
  4091  		if err != nil {
  4092  			return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  4093  		}
  4094  	}
  4095  
  4096  	part, err := writer.CreateFormFile("plugin", "plugin.tar.gz")
  4097  	if err != nil {
  4098  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  4099  	}
  4100  
  4101  	if _, err = io.Copy(part, file); err != nil {
  4102  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  4103  	}
  4104  
  4105  	if err = writer.Close(); err != nil {
  4106  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.writer.app_error", nil, err.Error(), 0)}
  4107  	}
  4108  
  4109  	rq, err := http.NewRequest("POST", c.ApiUrl+c.GetPluginsRoute(), body)
  4110  	if err != nil {
  4111  		return nil, &Response{Error: NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), http.StatusBadRequest)}
  4112  	}
  4113  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  4114  
  4115  	if len(c.AuthToken) > 0 {
  4116  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
  4117  	}
  4118  
  4119  	rp, err := c.HttpClient.Do(rq)
  4120  	if err != nil || rp == nil {
  4121  		return nil, BuildErrorResponse(rp, NewAppError("UploadPlugin", "model.client.connecting.app_error", nil, err.Error(), 0))
  4122  	}
  4123  	defer closeBody(rp)
  4124  
  4125  	if rp.StatusCode >= 300 {
  4126  		return nil, BuildErrorResponse(rp, AppErrorFromJson(rp.Body))
  4127  	}
  4128  
  4129  	return ManifestFromJson(rp.Body), BuildResponse(rp)
  4130  }
  4131  
  4132  // GetPlugins will return a list of plugin manifests for currently active plugins.
  4133  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4134  func (c *Client4) GetPlugins() (*PluginsResponse, *Response) {
  4135  	r, err := c.DoApiGet(c.GetPluginsRoute(), "")
  4136  	if err != nil {
  4137  		return nil, BuildErrorResponse(r, err)
  4138  	}
  4139  	defer closeBody(r)
  4140  	return PluginsResponseFromJson(r.Body), BuildResponse(r)
  4141  }
  4142  
  4143  // GetPluginStatuses will return the plugins installed on any server in the cluster, for reporting
  4144  // to the administrator via the system console.
  4145  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4146  func (c *Client4) GetPluginStatuses() (PluginStatuses, *Response) {
  4147  	r, err := c.DoApiGet(c.GetPluginsRoute(), "/statuses")
  4148  	if err != nil {
  4149  		return nil, BuildErrorResponse(r, err)
  4150  	}
  4151  	defer closeBody(r)
  4152  	return PluginStatusesFromJson(r.Body), BuildResponse(r)
  4153  }
  4154  
  4155  // RemovePlugin will disable and delete a plugin.
  4156  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4157  func (c *Client4) RemovePlugin(id string) (bool, *Response) {
  4158  	r, err := c.DoApiDelete(c.GetPluginRoute(id))
  4159  	if err != nil {
  4160  		return false, BuildErrorResponse(r, err)
  4161  	}
  4162  	defer closeBody(r)
  4163  	return CheckStatusOK(r), BuildResponse(r)
  4164  }
  4165  
  4166  // GetWebappPlugins will return a list of plugins that the webapp should download.
  4167  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4168  func (c *Client4) GetWebappPlugins() ([]*Manifest, *Response) {
  4169  	r, err := c.DoApiGet(c.GetPluginsRoute()+"/webapp", "")
  4170  	if err != nil {
  4171  		return nil, BuildErrorResponse(r, err)
  4172  	}
  4173  	defer closeBody(r)
  4174  	return ManifestListFromJson(r.Body), BuildResponse(r)
  4175  }
  4176  
  4177  // EnablePlugin will enable an plugin installed.
  4178  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4179  func (c *Client4) EnablePlugin(id string) (bool, *Response) {
  4180  	r, err := c.DoApiPost(c.GetPluginRoute(id)+"/enable", "")
  4181  	if err != nil {
  4182  		return false, BuildErrorResponse(r, err)
  4183  	}
  4184  	defer closeBody(r)
  4185  	return CheckStatusOK(r), BuildResponse(r)
  4186  }
  4187  
  4188  // DisablePlugin will disable an enabled plugin.
  4189  // WARNING: PLUGINS ARE STILL EXPERIMENTAL. THIS FUNCTION IS SUBJECT TO CHANGE.
  4190  func (c *Client4) DisablePlugin(id string) (bool, *Response) {
  4191  	r, err := c.DoApiPost(c.GetPluginRoute(id)+"/disable", "")
  4192  	if err != nil {
  4193  		return false, BuildErrorResponse(r, err)
  4194  	}
  4195  	defer closeBody(r)
  4196  	return CheckStatusOK(r), BuildResponse(r)
  4197  }
  4198  
  4199  // UpdateChannelScheme will update a channel's scheme.
  4200  func (c *Client4) UpdateChannelScheme(channelId, schemeId string) (bool, *Response) {
  4201  	sip := &SchemeIDPatch{SchemeID: &schemeId}
  4202  	r, err := c.DoApiPut(c.GetChannelSchemeRoute(channelId), sip.ToJson())
  4203  	if err != nil {
  4204  		return false, BuildErrorResponse(r, err)
  4205  	}
  4206  	defer closeBody(r)
  4207  	return CheckStatusOK(r), BuildResponse(r)
  4208  }
  4209  
  4210  // UpdateTeamScheme will update a team's scheme.
  4211  func (c *Client4) UpdateTeamScheme(teamId, schemeId string) (bool, *Response) {
  4212  	sip := &SchemeIDPatch{SchemeID: &schemeId}
  4213  	r, err := c.DoApiPut(c.GetTeamSchemeRoute(teamId), sip.ToJson())
  4214  	if err != nil {
  4215  		return false, BuildErrorResponse(r, err)
  4216  	}
  4217  	defer closeBody(r)
  4218  	return CheckStatusOK(r), BuildResponse(r)
  4219  }
  4220  
  4221  // GetRedirectLocation retrieves the value of the 'Location' header of an HTTP response for a given URL.
  4222  func (c *Client4) GetRedirectLocation(urlParam, etag string) (string, *Response) {
  4223  	url := fmt.Sprintf("%s?url=%s", c.GetRedirectLocationRoute(), url.QueryEscape(urlParam))
  4224  	r, err := c.DoApiGet(url, etag)
  4225  	if err != nil {
  4226  		return "", BuildErrorResponse(r, err)
  4227  	}
  4228  	defer closeBody(r)
  4229  	return MapFromJson(r.Body)["location"], BuildResponse(r)
  4230  }
  4231  
  4232  // RegisterTermsOfServiceAction saves action performed by a user against a specific terms of service.
  4233  func (c *Client4) RegisterTermsOfServiceAction(userId, termsOfServiceId string, accepted bool) (*bool, *Response) {
  4234  	url := c.GetUserTermsOfServiceRoute(userId)
  4235  	data := map[string]interface{}{"termsOfServiceId": termsOfServiceId, "accepted": accepted}
  4236  	r, err := c.DoApiPost(url, StringInterfaceToJson(data))
  4237  	if err != nil {
  4238  		return nil, BuildErrorResponse(r, err)
  4239  	}
  4240  	defer closeBody(r)
  4241  	return NewBool(CheckStatusOK(r)), BuildResponse(r)
  4242  }
  4243  
  4244  // GetTermsOfService fetches the latest terms of service
  4245  func (c *Client4) GetTermsOfService(etag string) (*TermsOfService, *Response) {
  4246  	url := c.GetTermsOfServiceRoute()
  4247  	r, err := c.DoApiGet(url, etag)
  4248  	if err != nil {
  4249  		return nil, BuildErrorResponse(r, err)
  4250  	}
  4251  	defer closeBody(r)
  4252  	return TermsOfServiceFromJson(r.Body), BuildResponse(r)
  4253  }
  4254  
  4255  // GetUserTermsOfService fetches user's latest terms of service action if the latest action was for acceptance.
  4256  func (c *Client4) GetUserTermsOfService(userId, etag string) (*UserTermsOfService, *Response) {
  4257  	url := c.GetUserTermsOfServiceRoute(userId)
  4258  	r, err := c.DoApiGet(url, etag)
  4259  	if err != nil {
  4260  		return nil, BuildErrorResponse(r, err)
  4261  	}
  4262  	defer closeBody(r)
  4263  	return UserTermsOfServiceFromJson(r.Body), BuildResponse(r)
  4264  }
  4265  
  4266  // CreateTermsOfService creates new terms of service.
  4267  func (c *Client4) CreateTermsOfService(text, userId string) (*TermsOfService, *Response) {
  4268  	url := c.GetTermsOfServiceRoute()
  4269  	data := map[string]interface{}{"text": text}
  4270  	r, err := c.DoApiPost(url, StringInterfaceToJson(data))
  4271  	if err != nil {
  4272  		return nil, BuildErrorResponse(r, err)
  4273  	}
  4274  	defer closeBody(r)
  4275  	return TermsOfServiceFromJson(r.Body), BuildResponse(r)
  4276  }
  4277  
  4278  func (c *Client4) GetGroup(groupID, etag string) (*Group, *Response) {
  4279  	r, appErr := c.DoApiGet(c.GetGroupRoute(groupID), etag)
  4280  	if appErr != nil {
  4281  		return nil, BuildErrorResponse(r, appErr)
  4282  	}
  4283  	defer closeBody(r)
  4284  	return GroupFromJson(r.Body), BuildResponse(r)
  4285  }
  4286  
  4287  func (c *Client4) PatchGroup(groupID string, patch *GroupPatch) (*Group, *Response) {
  4288  	payload, _ := json.Marshal(patch)
  4289  	r, appErr := c.DoApiPut(c.GetGroupRoute(groupID)+"/patch", string(payload))
  4290  	if appErr != nil {
  4291  		return nil, BuildErrorResponse(r, appErr)
  4292  	}
  4293  	defer closeBody(r)
  4294  	return GroupFromJson(r.Body), BuildResponse(r)
  4295  }
  4296  
  4297  func (c *Client4) LinkGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, patch *GroupSyncablePatch) (*GroupSyncable, *Response) {
  4298  	payload, _ := json.Marshal(patch)
  4299  	url := fmt.Sprintf("%s/link", c.GetGroupSyncableRoute(groupID, syncableID, syncableType))
  4300  	r, appErr := c.DoApiPost(url, string(payload))
  4301  	if appErr != nil {
  4302  		return nil, BuildErrorResponse(r, appErr)
  4303  	}
  4304  	defer closeBody(r)
  4305  	return GroupSyncableFromJson(r.Body), BuildResponse(r)
  4306  }
  4307  
  4308  func (c *Client4) UnlinkGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType) *Response {
  4309  	url := fmt.Sprintf("%s/link", c.GetGroupSyncableRoute(groupID, syncableID, syncableType))
  4310  	r, appErr := c.DoApiDelete(url)
  4311  	if appErr != nil {
  4312  		return BuildErrorResponse(r, appErr)
  4313  	}
  4314  	defer closeBody(r)
  4315  	return BuildResponse(r)
  4316  }
  4317  
  4318  func (c *Client4) GetGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, etag string) (*GroupSyncable, *Response) {
  4319  	r, appErr := c.DoApiGet(c.GetGroupSyncableRoute(groupID, syncableID, syncableType), etag)
  4320  	if appErr != nil {
  4321  		return nil, BuildErrorResponse(r, appErr)
  4322  	}
  4323  	defer closeBody(r)
  4324  	return GroupSyncableFromJson(r.Body), BuildResponse(r)
  4325  }
  4326  
  4327  func (c *Client4) GetGroupSyncables(groupID string, syncableType GroupSyncableType, etag string) ([]*GroupSyncable, *Response) {
  4328  	r, appErr := c.DoApiGet(c.GetGroupSyncablesRoute(groupID, syncableType), etag)
  4329  	if appErr != nil {
  4330  		return nil, BuildErrorResponse(r, appErr)
  4331  	}
  4332  	defer closeBody(r)
  4333  	return GroupSyncablesFromJson(r.Body), BuildResponse(r)
  4334  }
  4335  
  4336  func (c *Client4) PatchGroupSyncable(groupID, syncableID string, syncableType GroupSyncableType, patch *GroupSyncablePatch) (*GroupSyncable, *Response) {
  4337  	payload, _ := json.Marshal(patch)
  4338  	r, appErr := c.DoApiPut(c.GetGroupSyncableRoute(groupID, syncableID, syncableType)+"/patch", string(payload))
  4339  	if appErr != nil {
  4340  		return nil, BuildErrorResponse(r, appErr)
  4341  	}
  4342  	defer closeBody(r)
  4343  	return GroupSyncableFromJson(r.Body), BuildResponse(r)
  4344  }