github.com/turgay/mattermost-server@v5.3.2-0.20181002173352-2945e8a2b0ce+incompatible/model/client4.go (about)

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