github.com/gigforks/mattermost-server@v4.9.1-0.20180619094218-800d97fa55d0+incompatible/model/client4.go (about)

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