github.com/wgh-/mattermost-server@v4.8.0-rc2+incompatible/model/client.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See License.txt for license information.
     3  
     4  package model
     5  
     6  import (
     7  	"bytes"
     8  	"fmt"
     9  	"io"
    10  	"io/ioutil"
    11  	"mime/multipart"
    12  	"net/http"
    13  	"net/url"
    14  	"strconv"
    15  	"strings"
    16  	"time"
    17  
    18  	l4g "github.com/alecthomas/log4go"
    19  )
    20  
    21  var UsedApiV3 *int32 = new(int32)
    22  
    23  const (
    24  	HEADER_REQUEST_ID         = "X-Request-ID"
    25  	HEADER_VERSION_ID         = "X-Version-ID"
    26  	HEADER_CLUSTER_ID         = "X-Cluster-ID"
    27  	HEADER_ETAG_SERVER        = "ETag"
    28  	HEADER_ETAG_CLIENT        = "If-None-Match"
    29  	HEADER_FORWARDED          = "X-Forwarded-For"
    30  	HEADER_REAL_IP            = "X-Real-IP"
    31  	HEADER_FORWARDED_PROTO    = "X-Forwarded-Proto"
    32  	HEADER_TOKEN              = "token"
    33  	HEADER_BEARER             = "BEARER"
    34  	HEADER_AUTH               = "Authorization"
    35  	HEADER_REQUESTED_WITH     = "X-Requested-With"
    36  	HEADER_REQUESTED_WITH_XML = "XMLHttpRequest"
    37  	STATUS                    = "status"
    38  	STATUS_OK                 = "OK"
    39  	STATUS_FAIL               = "FAIL"
    40  	STATUS_REMOVE             = "REMOVE"
    41  
    42  	CLIENT_DIR = "client"
    43  
    44  	API_URL_SUFFIX_V1 = "/api/v1"
    45  	API_URL_SUFFIX_V3 = "/api/v3"
    46  	API_URL_SUFFIX_V4 = "/api/v4"
    47  	API_URL_SUFFIX    = API_URL_SUFFIX_V4
    48  )
    49  
    50  type Result struct {
    51  	RequestId string
    52  	Etag      string
    53  	Data      interface{}
    54  }
    55  
    56  type ResponseMetadata struct {
    57  	StatusCode int
    58  	Error      *AppError
    59  	RequestId  string
    60  	Etag       string
    61  }
    62  
    63  type Client struct {
    64  	Url           string       // The location of the server like "http://localhost:8065"
    65  	ApiUrl        string       // The api location of the server like "http://localhost:8065/api/v3"
    66  	HttpClient    *http.Client // The http client
    67  	AuthToken     string
    68  	AuthType      string
    69  	TeamId        string
    70  	RequestId     string
    71  	Etag          string
    72  	ServerVersion string
    73  }
    74  
    75  // NewClient constructs a new client with convienence methods for talking to
    76  // the server.
    77  func NewClient(url string) *Client {
    78  	return &Client{url, url + API_URL_SUFFIX_V3, &http.Client{}, "", "", "", "", "", ""}
    79  }
    80  
    81  func closeBody(r *http.Response) {
    82  	if r.Body != nil {
    83  		ioutil.ReadAll(r.Body)
    84  		r.Body.Close()
    85  	}
    86  }
    87  
    88  func (c *Client) SetOAuthToken(token string) {
    89  	c.AuthToken = token
    90  	c.AuthType = HEADER_TOKEN
    91  }
    92  
    93  func (c *Client) ClearOAuthToken() {
    94  	c.AuthToken = ""
    95  	c.AuthType = HEADER_BEARER
    96  }
    97  
    98  func (c *Client) SetTeamId(teamId string) {
    99  	c.TeamId = teamId
   100  }
   101  
   102  func (c *Client) GetTeamId() string {
   103  	if len(c.TeamId) == 0 {
   104  		println(`You are trying to use a route that requires a team_id, 
   105          	but you have not called SetTeamId() in client.go`)
   106  	}
   107  
   108  	return c.TeamId
   109  }
   110  
   111  func (c *Client) ClearTeamId() {
   112  	c.TeamId = ""
   113  }
   114  
   115  func (c *Client) GetTeamRoute() string {
   116  	return fmt.Sprintf("/teams/%v", c.GetTeamId())
   117  }
   118  
   119  func (c *Client) GetChannelRoute(channelId string) string {
   120  	return fmt.Sprintf("/teams/%v/channels/%v", c.GetTeamId(), channelId)
   121  }
   122  
   123  func (c *Client) GetUserRequiredRoute(userId string) string {
   124  	return fmt.Sprintf("/users/%v", userId)
   125  }
   126  
   127  func (c *Client) GetChannelNameRoute(channelName string) string {
   128  	return fmt.Sprintf("/teams/%v/channels/name/%v", c.GetTeamId(), channelName)
   129  }
   130  
   131  func (c *Client) GetEmojiRoute() string {
   132  	return "/emoji"
   133  }
   134  
   135  func (c *Client) GetGeneralRoute() string {
   136  	return "/general"
   137  }
   138  
   139  func (c *Client) GetFileRoute(fileId string) string {
   140  	return fmt.Sprintf("/files/%v", fileId)
   141  }
   142  
   143  func (c *Client) DoPost(url, data, contentType string) (*http.Response, *AppError) {
   144  	rq, _ := http.NewRequest("POST", c.Url+url, strings.NewReader(data))
   145  	rq.Header.Set("Content-Type", contentType)
   146  	rq.Close = true
   147  
   148  	if rp, err := c.HttpClient.Do(rq); err != nil {
   149  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
   150  	} else if rp.StatusCode >= 300 {
   151  		defer closeBody(rp)
   152  		return nil, AppErrorFromJson(rp.Body)
   153  	} else {
   154  		return rp, nil
   155  	}
   156  }
   157  
   158  func (c *Client) DoApiPost(url string, data string) (*http.Response, *AppError) {
   159  	rq, _ := http.NewRequest("POST", c.ApiUrl+url, strings.NewReader(data))
   160  	rq.Close = true
   161  
   162  	if len(c.AuthToken) > 0 {
   163  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   164  	}
   165  
   166  	if rp, err := c.HttpClient.Do(rq); err != nil {
   167  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
   168  	} else if rp.StatusCode >= 300 {
   169  		defer closeBody(rp)
   170  		return nil, AppErrorFromJson(rp.Body)
   171  	} else {
   172  		return rp, nil
   173  	}
   174  }
   175  
   176  func (c *Client) DoApiGet(url string, data string, etag string) (*http.Response, *AppError) {
   177  	rq, _ := http.NewRequest("GET", c.ApiUrl+url, strings.NewReader(data))
   178  	rq.Close = true
   179  
   180  	if len(etag) > 0 {
   181  		rq.Header.Set(HEADER_ETAG_CLIENT, etag)
   182  	}
   183  
   184  	if len(c.AuthToken) > 0 {
   185  		rq.Header.Set(HEADER_AUTH, c.AuthType+" "+c.AuthToken)
   186  	}
   187  
   188  	if rp, err := c.HttpClient.Do(rq); err != nil {
   189  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
   190  	} else if rp.StatusCode == 304 {
   191  		return rp, nil
   192  	} else if rp.StatusCode >= 300 {
   193  		defer closeBody(rp)
   194  		return rp, AppErrorFromJson(rp.Body)
   195  	} else {
   196  		return rp, nil
   197  	}
   198  }
   199  
   200  func getCookie(name string, resp *http.Response) *http.Cookie {
   201  	for _, cookie := range resp.Cookies() {
   202  		if cookie.Name == name {
   203  			return cookie
   204  		}
   205  	}
   206  
   207  	return nil
   208  }
   209  
   210  // Must is a convenience function used for testing.
   211  func (c *Client) Must(result *Result, err *AppError) *Result {
   212  	if err != nil {
   213  		l4g.Close()
   214  		time.Sleep(time.Second)
   215  		panic(err)
   216  	}
   217  
   218  	return result
   219  }
   220  
   221  // MustGeneric is a convenience function used for testing.
   222  func (c *Client) MustGeneric(result interface{}, err *AppError) interface{} {
   223  	if err != nil {
   224  		l4g.Close()
   225  		time.Sleep(time.Second)
   226  		panic(err)
   227  	}
   228  
   229  	return result
   230  }
   231  
   232  // CheckStatusOK is a convenience function for checking the return of Web Service
   233  // call that return the a map of status=OK.
   234  func (c *Client) CheckStatusOK(r *http.Response) bool {
   235  	m := MapFromJson(r.Body)
   236  	defer closeBody(r)
   237  
   238  	if m != nil && m[STATUS] == STATUS_OK {
   239  		return true
   240  	}
   241  
   242  	return false
   243  }
   244  
   245  func (c *Client) fillInExtraProperties(r *http.Response) {
   246  	c.RequestId = r.Header.Get(HEADER_REQUEST_ID)
   247  	c.Etag = r.Header.Get(HEADER_ETAG_SERVER)
   248  	c.ServerVersion = r.Header.Get(HEADER_VERSION_ID)
   249  }
   250  
   251  func (c *Client) clearExtraProperties() {
   252  	c.RequestId = ""
   253  	c.Etag = ""
   254  	c.ServerVersion = ""
   255  }
   256  
   257  // General Routes Section
   258  
   259  // GetClientProperties returns properties needed by the client to show/hide
   260  // certian features.  It returns a map of strings.
   261  func (c *Client) GetClientProperties() (map[string]string, *AppError) {
   262  	c.clearExtraProperties()
   263  	if r, err := c.DoApiGet(c.GetGeneralRoute()+"/client_props", "", ""); err != nil {
   264  		return nil, err
   265  	} else {
   266  		defer closeBody(r)
   267  		c.fillInExtraProperties(r)
   268  		return MapFromJson(r.Body), nil
   269  	}
   270  }
   271  
   272  // LogClient is a convenience Web Service call so clients can log messages into
   273  // the server-side logs.  For example we typically log javascript error messages
   274  // into the server-side.  It returns true if the logging was successful.
   275  func (c *Client) LogClient(message string) (bool, *AppError) {
   276  	c.clearExtraProperties()
   277  	m := make(map[string]string)
   278  	m["level"] = "ERROR"
   279  	m["message"] = message
   280  
   281  	if r, err := c.DoApiPost(c.GetGeneralRoute()+"/log_client", MapToJson(m)); err != nil {
   282  		return false, err
   283  	} else {
   284  		defer closeBody(r)
   285  		c.fillInExtraProperties(r)
   286  		return c.CheckStatusOK(r), nil
   287  	}
   288  }
   289  
   290  // GetPing returns a map of strings with server time, server version, and node Id.
   291  // Systems that want to check on health status of the server should check the
   292  // url /api/v3/ping for a 200 status response.
   293  func (c *Client) GetPing() (map[string]string, *AppError) {
   294  	c.clearExtraProperties()
   295  	if r, err := c.DoApiGet(c.GetGeneralRoute()+"/ping", "", ""); err != nil {
   296  		return nil, err
   297  	} else {
   298  		defer closeBody(r)
   299  		c.fillInExtraProperties(r)
   300  		return MapFromJson(r.Body), nil
   301  	}
   302  }
   303  
   304  // Team Routes Section
   305  
   306  // CreateTeam creates a team based on the provided Team struct. On success it returns
   307  // the Team struct with the Id, CreateAt and other server-decided fields populated.
   308  func (c *Client) CreateTeam(team *Team) (*Result, *AppError) {
   309  	if r, err := c.DoApiPost("/teams/create", team.ToJson()); err != nil {
   310  		return nil, err
   311  	} else {
   312  		defer closeBody(r)
   313  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   314  			r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
   315  	}
   316  }
   317  
   318  // GetAllTeams returns a map of all teams using team ids as the key.
   319  func (c *Client) GetAllTeams() (*Result, *AppError) {
   320  	if r, err := c.DoApiGet("/teams/all", "", ""); err != nil {
   321  		return nil, err
   322  	} else {
   323  		defer closeBody(r)
   324  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   325  			r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
   326  	}
   327  }
   328  
   329  // GetAllTeamListings returns a map of all teams that are available to join
   330  // using team ids as the key. Must be authenticated.
   331  func (c *Client) GetAllTeamListings() (*Result, *AppError) {
   332  	if r, err := c.DoApiGet("/teams/all_team_listings", "", ""); err != nil {
   333  		return nil, err
   334  	} else {
   335  		defer closeBody(r)
   336  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   337  			r.Header.Get(HEADER_ETAG_SERVER), TeamMapFromJson(r.Body)}, nil
   338  	}
   339  }
   340  
   341  // FindTeamByName returns the strings "true" or "false" depending on if a team
   342  // with the provided name was found.
   343  func (c *Client) FindTeamByName(name string) (*Result, *AppError) {
   344  	m := make(map[string]string)
   345  	m["name"] = name
   346  	if r, err := c.DoApiPost("/teams/find_team_by_name", MapToJson(m)); err != nil {
   347  		return nil, err
   348  	} else {
   349  		val := false
   350  		if body, _ := ioutil.ReadAll(r.Body); string(body) == "true" {
   351  			val = true
   352  		}
   353  		defer closeBody(r)
   354  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   355  			r.Header.Get(HEADER_ETAG_SERVER), val}, nil
   356  	}
   357  }
   358  
   359  //  Adds a user directly to the team without sending an invite.
   360  //  The teamId and userId are required.  You must be a valid member of the team and/or
   361  //  have the correct role to add new users to the team.  Returns a map of user_id=userId
   362  //  if successful, otherwise returns an AppError.
   363  func (c *Client) AddUserToTeam(teamId string, userId string) (*Result, *AppError) {
   364  	if len(teamId) == 0 {
   365  		teamId = c.GetTeamId()
   366  	}
   367  
   368  	data := make(map[string]string)
   369  	data["user_id"] = userId
   370  	if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v", teamId)+"/add_user_to_team", MapToJson(data)); err != nil {
   371  		return nil, err
   372  	} else {
   373  		defer closeBody(r)
   374  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   375  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   376  	}
   377  }
   378  
   379  // AddUserToTeamFromInvite adds a user to a team based off data provided in an invite link.
   380  // Either hash and dataToHash are required or inviteId is required.
   381  func (c *Client) AddUserToTeamFromInvite(hash, dataToHash, inviteId string) (*Result, *AppError) {
   382  	data := make(map[string]string)
   383  	data["hash"] = hash
   384  	data["data"] = dataToHash
   385  	data["invite_id"] = inviteId
   386  	if r, err := c.DoApiPost("/teams/add_user_to_team_from_invite", MapToJson(data)); err != nil {
   387  		return nil, err
   388  	} else {
   389  		defer closeBody(r)
   390  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   391  			r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
   392  	}
   393  }
   394  
   395  //  Removes a user directly from the team.
   396  //  The teamId and userId are required.  You must be a valid member of the team and/or
   397  //  have the correct role to remove a user from the team.  Returns a map of user_id=userId
   398  //  if successful, otherwise returns an AppError.
   399  func (c *Client) RemoveUserFromTeam(teamId string, userId string) (*Result, *AppError) {
   400  	if len(teamId) == 0 {
   401  		teamId = c.GetTeamId()
   402  	}
   403  
   404  	data := make(map[string]string)
   405  	data["user_id"] = userId
   406  	if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v", teamId)+"/remove_user_from_team", MapToJson(data)); err != nil {
   407  		return nil, err
   408  	} else {
   409  		defer closeBody(r)
   410  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   411  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   412  	}
   413  }
   414  
   415  func (c *Client) InviteMembers(invites *Invites) (*Result, *AppError) {
   416  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/invite_members", invites.ToJson()); err != nil {
   417  		return nil, err
   418  	} else {
   419  		defer closeBody(r)
   420  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   421  			r.Header.Get(HEADER_ETAG_SERVER), InvitesFromJson(r.Body)}, nil
   422  	}
   423  }
   424  
   425  // UpdateTeam updates a team based on the changes in the provided team struct. On success
   426  // it returns a sanitized version of the updated team. Must be authenticated as a team admin
   427  // for that team or a system admin.
   428  func (c *Client) UpdateTeam(team *Team) (*Result, *AppError) {
   429  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/update", team.ToJson()); err != nil {
   430  		return nil, err
   431  	} else {
   432  		defer closeBody(r)
   433  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   434  			r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
   435  	}
   436  }
   437  
   438  // User Routes Section
   439  
   440  // CreateUser creates a user in the system based on the provided user struct.
   441  func (c *Client) CreateUser(user *User, hash string) (*Result, *AppError) {
   442  	if r, err := c.DoApiPost("/users/create", user.ToJson()); err != nil {
   443  		return nil, err
   444  	} else {
   445  		defer closeBody(r)
   446  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   447  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   448  	}
   449  }
   450  
   451  // CreateUserWithInvite creates a user based on the provided user struct. Either the hash and
   452  // data strings or the inviteId is required from the invite.
   453  func (c *Client) CreateUserWithInvite(user *User, hash string, data string, inviteId string) (*Result, *AppError) {
   454  
   455  	url := "/users/create?d=" + url.QueryEscape(data) + "&h=" + url.QueryEscape(hash) + "&iid=" + url.QueryEscape(inviteId)
   456  
   457  	if r, err := c.DoApiPost(url, user.ToJson()); err != nil {
   458  		return nil, err
   459  	} else {
   460  		defer closeBody(r)
   461  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   462  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   463  	}
   464  }
   465  
   466  func (c *Client) CreateUserFromSignup(user *User, data string, hash string) (*Result, *AppError) {
   467  	if r, err := c.DoApiPost("/users/create?d="+url.QueryEscape(data)+"&h="+hash, user.ToJson()); err != nil {
   468  		return nil, err
   469  	} else {
   470  		defer closeBody(r)
   471  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   472  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   473  	}
   474  }
   475  
   476  // GetUser returns a user based on a provided user id string. Must be authenticated.
   477  func (c *Client) GetUser(id string, etag string) (*Result, *AppError) {
   478  	if r, err := c.DoApiGet("/users/"+id+"/get", "", etag); err != nil {
   479  		return nil, err
   480  	} else {
   481  		defer closeBody(r)
   482  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   483  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   484  	}
   485  }
   486  
   487  // getByUsername returns a user based on a provided username string. Must be authenticated.
   488  func (c *Client) GetByUsername(username string, etag string) (*Result, *AppError) {
   489  	if r, err := c.DoApiGet(fmt.Sprintf("/users/name/%v", username), "", etag); err != nil {
   490  		return nil, err
   491  	} else {
   492  		defer closeBody(r)
   493  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   494  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   495  	}
   496  }
   497  
   498  // getByEmail returns a user based on a provided username string. Must be authenticated.
   499  func (c *Client) GetByEmail(email string, etag string) (*User, *ResponseMetadata) {
   500  	if r, err := c.DoApiGet(fmt.Sprintf("/users/email/%v", email), "", etag); err != nil {
   501  		return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
   502  	} else {
   503  		defer closeBody(r)
   504  		return UserFromJson(r.Body),
   505  			&ResponseMetadata{
   506  				StatusCode: r.StatusCode,
   507  				RequestId:  r.Header.Get(HEADER_REQUEST_ID),
   508  				Etag:       r.Header.Get(HEADER_ETAG_SERVER),
   509  			}
   510  	}
   511  }
   512  
   513  // GetMe returns the current user.
   514  func (c *Client) GetMe(etag string) (*Result, *AppError) {
   515  	if r, err := c.DoApiGet("/users/me", "", etag); err != nil {
   516  		return nil, err
   517  	} else {
   518  		defer closeBody(r)
   519  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   520  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   521  	}
   522  }
   523  
   524  // GetProfiles returns a map of users using user id as the key. Must be authenticated.
   525  func (c *Client) GetProfiles(offset int, limit int, etag string) (*Result, *AppError) {
   526  	if r, err := c.DoApiGet(fmt.Sprintf("/users/%v/%v", offset, limit), "", etag); err != nil {
   527  		return nil, err
   528  	} else {
   529  		defer closeBody(r)
   530  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   531  			r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
   532  	}
   533  }
   534  
   535  // GetProfilesInTeam returns a map of users for a team using user id as the key. Must
   536  // be authenticated.
   537  func (c *Client) GetProfilesInTeam(teamId string, offset int, limit int, etag string) (*Result, *AppError) {
   538  	if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/users/%v/%v", teamId, offset, limit), "", etag); err != nil {
   539  		return nil, err
   540  	} else {
   541  		defer closeBody(r)
   542  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   543  			r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
   544  	}
   545  }
   546  
   547  // GetProfilesInChannel returns a map of users for a channel using user id as the key. Must
   548  // be authenticated.
   549  func (c *Client) GetProfilesInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
   550  	if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/%v/%v", offset, limit), "", etag); err != nil {
   551  		return nil, err
   552  	} else {
   553  		defer closeBody(r)
   554  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   555  			r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
   556  	}
   557  }
   558  
   559  // GetProfilesNotInChannel returns a map of users not in a channel but on the team using user id as the key. Must
   560  // be authenticated.
   561  func (c *Client) GetProfilesNotInChannel(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
   562  	if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/users/not_in_channel/%v/%v", offset, limit), "", etag); err != nil {
   563  		return nil, err
   564  	} else {
   565  		defer closeBody(r)
   566  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   567  			r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
   568  	}
   569  }
   570  
   571  // GetProfilesByIds returns a map of users based on the user ids provided. Must
   572  // be authenticated.
   573  func (c *Client) GetProfilesByIds(userIds []string) (*Result, *AppError) {
   574  	if r, err := c.DoApiPost("/users/ids", ArrayToJson(userIds)); err != nil {
   575  		return nil, err
   576  	} else {
   577  		defer closeBody(r)
   578  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   579  			r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
   580  	}
   581  }
   582  
   583  // SearchUsers returns a list of users that have a username matching or similar to the search term. Must
   584  // be authenticated.
   585  func (c *Client) SearchUsers(params UserSearch) (*Result, *AppError) {
   586  	if r, err := c.DoApiPost("/users/search", params.ToJson()); err != nil {
   587  		return nil, err
   588  	} else {
   589  		defer closeBody(r)
   590  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   591  			r.Header.Get(HEADER_ETAG_SERVER), UserListFromJson(r.Body)}, nil
   592  	}
   593  }
   594  
   595  // AutocompleteUsersInChannel returns two lists for autocompletion of users in a channel. The first list "in_channel",
   596  // specifies users in the channel. The second list "out_of_channel" specifies users outside of the
   597  // channel. Term, the string to search against, is required, channel id is also required. Must be authenticated.
   598  func (c *Client) AutocompleteUsersInChannel(term string, channelId string) (*Result, *AppError) {
   599  	url := fmt.Sprintf("%s/users/autocomplete?term=%s", c.GetChannelRoute(channelId), url.QueryEscape(term))
   600  	if r, err := c.DoApiGet(url, "", ""); err != nil {
   601  		return nil, err
   602  	} else {
   603  		defer closeBody(r)
   604  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   605  			r.Header.Get(HEADER_ETAG_SERVER), UserAutocompleteInChannelFromJson(r.Body)}, nil
   606  	}
   607  }
   608  
   609  // AutocompleteUsersInTeam returns a list for autocompletion of users in a team. The list "in_team" specifies
   610  // the users in the team that match the provided term, matching against username, full name and
   611  // nickname. Must be authenticated.
   612  func (c *Client) AutocompleteUsersInTeam(term string) (*Result, *AppError) {
   613  	url := fmt.Sprintf("%s/users/autocomplete?term=%s", c.GetTeamRoute(), url.QueryEscape(term))
   614  	if r, err := c.DoApiGet(url, "", ""); err != nil {
   615  		return nil, err
   616  	} else {
   617  		defer closeBody(r)
   618  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   619  			r.Header.Get(HEADER_ETAG_SERVER), UserAutocompleteInTeamFromJson(r.Body)}, nil
   620  	}
   621  }
   622  
   623  // AutocompleteUsers returns a list for autocompletion of users on the system that match the provided term,
   624  // matching against username, full name and nickname. Must be authenticated.
   625  func (c *Client) AutocompleteUsers(term string) (*Result, *AppError) {
   626  	url := fmt.Sprintf("/users/autocomplete?term=%s", url.QueryEscape(term))
   627  	if r, err := c.DoApiGet(url, "", ""); err != nil {
   628  		return nil, err
   629  	} else {
   630  		defer closeBody(r)
   631  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   632  			r.Header.Get(HEADER_ETAG_SERVER), UserListFromJson(r.Body)}, nil
   633  	}
   634  }
   635  
   636  // LoginById authenticates a user by user id and password.
   637  func (c *Client) LoginById(id string, password string) (*Result, *AppError) {
   638  	m := make(map[string]string)
   639  	m["id"] = id
   640  	m["password"] = password
   641  	return c.login(m)
   642  }
   643  
   644  // Login authenticates a user by login id, which can be username, email or some sort
   645  // of SSO identifier based on configuration, and a password.
   646  func (c *Client) Login(loginId string, password string) (*Result, *AppError) {
   647  	m := make(map[string]string)
   648  	m["login_id"] = loginId
   649  	m["password"] = password
   650  	return c.login(m)
   651  }
   652  
   653  // LoginByLdap authenticates a user by LDAP id and password.
   654  func (c *Client) LoginByLdap(loginId string, password string) (*Result, *AppError) {
   655  	m := make(map[string]string)
   656  	m["login_id"] = loginId
   657  	m["password"] = password
   658  	m["ldap_only"] = "true"
   659  	return c.login(m)
   660  }
   661  
   662  // LoginWithDevice authenticates a user by login id (username, email or some sort
   663  // of SSO identifier based on configuration), password and attaches a device id to
   664  // the session.
   665  func (c *Client) LoginWithDevice(loginId string, password string, deviceId string) (*Result, *AppError) {
   666  	m := make(map[string]string)
   667  	m["login_id"] = loginId
   668  	m["password"] = password
   669  	m["device_id"] = deviceId
   670  	return c.login(m)
   671  }
   672  
   673  func (c *Client) login(m map[string]string) (*Result, *AppError) {
   674  	if r, err := c.DoApiPost("/users/login", MapToJson(m)); err != nil {
   675  		return nil, err
   676  	} else {
   677  		c.AuthToken = r.Header.Get(HEADER_TOKEN)
   678  		c.AuthType = HEADER_BEARER
   679  		sessionToken := getCookie(SESSION_COOKIE_TOKEN, r)
   680  
   681  		if c.AuthToken != sessionToken.Value {
   682  			NewAppError("/users/login", "model.client.login.app_error", nil, "", 0)
   683  		}
   684  
   685  		defer closeBody(r)
   686  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   687  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
   688  	}
   689  }
   690  
   691  // Logout terminates the current user's session.
   692  func (c *Client) Logout() (*Result, *AppError) {
   693  	if r, err := c.DoApiPost("/users/logout", ""); err != nil {
   694  		return nil, err
   695  	} else {
   696  		c.AuthToken = ""
   697  		c.AuthType = HEADER_BEARER
   698  		c.TeamId = ""
   699  
   700  		defer closeBody(r)
   701  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   702  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   703  	}
   704  }
   705  
   706  // CheckMfa returns a map with key "mfa_required" with the string value "true" or "false",
   707  // indicating whether MFA is required to log the user in, based on a provided login id
   708  // (username, email or some sort of SSO identifier based on configuration).
   709  func (c *Client) CheckMfa(loginId string) (*Result, *AppError) {
   710  	m := make(map[string]string)
   711  	m["login_id"] = loginId
   712  
   713  	if r, err := c.DoApiPost("/users/mfa", MapToJson(m)); err != nil {
   714  		return nil, err
   715  	} else {
   716  		defer closeBody(r)
   717  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   718  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   719  	}
   720  }
   721  
   722  // GenerateMfaSecret returns a QR code image containing the secret, to be scanned
   723  // by a multi-factor authentication mobile application. It also returns the secret
   724  // for manual entry. Must be authenticated.
   725  func (c *Client) GenerateMfaSecret() (*Result, *AppError) {
   726  	if r, err := c.DoApiGet("/users/generate_mfa_secret", "", ""); err != nil {
   727  		return nil, err
   728  	} else {
   729  		defer closeBody(r)
   730  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   731  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   732  	}
   733  }
   734  
   735  // UpdateMfa activates multi-factor authenticates for the current user if activate
   736  // is true and a valid token is provided. If activate is false, then token is not
   737  // required and multi-factor authentication is disabled for the current user.
   738  func (c *Client) UpdateMfa(activate bool, token string) (*Result, *AppError) {
   739  	m := make(map[string]interface{})
   740  	m["activate"] = activate
   741  	m["token"] = token
   742  
   743  	if r, err := c.DoApiPost("/users/update_mfa", StringInterfaceToJson(m)); err != nil {
   744  		return nil, err
   745  	} else {
   746  		defer closeBody(r)
   747  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   748  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   749  	}
   750  }
   751  
   752  func (c *Client) AdminResetMfa(userId string) (*Result, *AppError) {
   753  	m := make(map[string]string)
   754  	m["user_id"] = userId
   755  
   756  	if r, err := c.DoApiPost("/admin/reset_mfa", MapToJson(m)); err != nil {
   757  		return nil, err
   758  	} else {
   759  		defer closeBody(r)
   760  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   761  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   762  	}
   763  }
   764  
   765  func (c *Client) RevokeSession(sessionAltId string) (*Result, *AppError) {
   766  	m := make(map[string]string)
   767  	m["id"] = sessionAltId
   768  
   769  	if r, err := c.DoApiPost("/users/revoke_session", MapToJson(m)); err != nil {
   770  		return nil, err
   771  	} else {
   772  		defer closeBody(r)
   773  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   774  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   775  	}
   776  }
   777  
   778  func (c *Client) GetSessions(id string) (*Result, *AppError) {
   779  	if r, err := c.DoApiGet("/users/"+id+"/sessions", "", ""); err != nil {
   780  		return nil, err
   781  	} else {
   782  		defer closeBody(r)
   783  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   784  			r.Header.Get(HEADER_ETAG_SERVER), SessionsFromJson(r.Body)}, nil
   785  	}
   786  }
   787  
   788  func (c *Client) EmailToOAuth(m map[string]string) (*Result, *AppError) {
   789  	if r, err := c.DoApiPost("/users/claim/email_to_oauth", MapToJson(m)); err != nil {
   790  		return nil, err
   791  	} else {
   792  		defer closeBody(r)
   793  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   794  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   795  	}
   796  }
   797  
   798  func (c *Client) OAuthToEmail(m map[string]string) (*Result, *AppError) {
   799  	if r, err := c.DoApiPost("/users/claim/oauth_to_email", MapToJson(m)); err != nil {
   800  		return nil, err
   801  	} else {
   802  		defer closeBody(r)
   803  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   804  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   805  	}
   806  }
   807  
   808  func (c *Client) LDAPToEmail(m map[string]string) (*Result, *AppError) {
   809  	if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
   810  		return nil, err
   811  	} else {
   812  		defer closeBody(r)
   813  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   814  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   815  	}
   816  }
   817  
   818  func (c *Client) EmailToLDAP(m map[string]string) (*Result, *AppError) {
   819  	if r, err := c.DoApiPost("/users/claim/ldap_to_email", MapToJson(m)); err != nil {
   820  		return nil, err
   821  	} else {
   822  		defer closeBody(r)
   823  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   824  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   825  	}
   826  }
   827  
   828  func (c *Client) Command(channelId string, command string) (*Result, *AppError) {
   829  	args := &CommandArgs{ChannelId: channelId, Command: command}
   830  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/execute", args.ToJson()); err != nil {
   831  		return nil, err
   832  	} else {
   833  		defer closeBody(r)
   834  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   835  			r.Header.Get(HEADER_ETAG_SERVER), CommandResponseFromJson(r.Body)}, nil
   836  	}
   837  }
   838  
   839  func (c *Client) ListCommands() (*Result, *AppError) {
   840  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list", "", ""); err != nil {
   841  		return nil, err
   842  	} else {
   843  		defer closeBody(r)
   844  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   845  			r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
   846  	}
   847  }
   848  
   849  func (c *Client) ListTeamCommands() (*Result, *AppError) {
   850  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/commands/list_team_commands", "", ""); err != nil {
   851  		return nil, err
   852  	} else {
   853  		defer closeBody(r)
   854  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   855  			r.Header.Get(HEADER_ETAG_SERVER), CommandListFromJson(r.Body)}, nil
   856  	}
   857  }
   858  
   859  func (c *Client) CreateCommand(cmd *Command) (*Result, *AppError) {
   860  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/create", cmd.ToJson()); err != nil {
   861  		return nil, err
   862  	} else {
   863  		defer closeBody(r)
   864  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   865  			r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
   866  	}
   867  }
   868  
   869  func (c *Client) UpdateCommand(cmd *Command) (*Result, *AppError) {
   870  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/update", cmd.ToJson()); err != nil {
   871  		return nil, err
   872  	} else {
   873  		defer closeBody(r)
   874  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   875  			r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
   876  	}
   877  }
   878  
   879  func (c *Client) RegenCommandToken(data map[string]string) (*Result, *AppError) {
   880  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/regen_token", MapToJson(data)); err != nil {
   881  		return nil, err
   882  	} else {
   883  		defer closeBody(r)
   884  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   885  			r.Header.Get(HEADER_ETAG_SERVER), CommandFromJson(r.Body)}, nil
   886  	}
   887  }
   888  
   889  func (c *Client) DeleteCommand(data map[string]string) (*Result, *AppError) {
   890  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/commands/delete", MapToJson(data)); err != nil {
   891  		return nil, err
   892  	} else {
   893  		defer closeBody(r)
   894  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   895  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   896  	}
   897  }
   898  
   899  func (c *Client) GetAudits(id string, etag string) (*Result, *AppError) {
   900  	if r, err := c.DoApiGet("/users/"+id+"/audits", "", etag); err != nil {
   901  		return nil, err
   902  	} else {
   903  		defer closeBody(r)
   904  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   905  			r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
   906  	}
   907  }
   908  
   909  func (c *Client) GetLogs() (*Result, *AppError) {
   910  	if r, err := c.DoApiGet("/admin/logs", "", ""); err != nil {
   911  		return nil, err
   912  	} else {
   913  		defer closeBody(r)
   914  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   915  			r.Header.Get(HEADER_ETAG_SERVER), ArrayFromJson(r.Body)}, nil
   916  	}
   917  }
   918  
   919  func (c *Client) GetClusterStatus() ([]*ClusterInfo, *AppError) {
   920  	if r, err := c.DoApiGet("/admin/cluster_status", "", ""); err != nil {
   921  		return nil, err
   922  	} else {
   923  		defer closeBody(r)
   924  		return ClusterInfosFromJson(r.Body), nil
   925  	}
   926  }
   927  
   928  // GetRecentlyActiveUsers returns a map of users including lastActivityAt using user id as the key
   929  func (c *Client) GetRecentlyActiveUsers(teamId string) (*Result, *AppError) {
   930  	if r, err := c.DoApiGet("/admin/recently_active_users/"+teamId, "", ""); err != nil {
   931  		return nil, err
   932  	} else {
   933  		defer closeBody(r)
   934  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   935  			r.Header.Get(HEADER_ETAG_SERVER), UserMapFromJson(r.Body)}, nil
   936  	}
   937  }
   938  
   939  func (c *Client) GetAllAudits() (*Result, *AppError) {
   940  	if r, err := c.DoApiGet("/admin/audits", "", ""); err != nil {
   941  		return nil, err
   942  	} else {
   943  		defer closeBody(r)
   944  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   945  			r.Header.Get(HEADER_ETAG_SERVER), AuditsFromJson(r.Body)}, nil
   946  	}
   947  }
   948  
   949  func (c *Client) GetConfig() (*Result, *AppError) {
   950  	if r, err := c.DoApiGet("/admin/config", "", ""); err != nil {
   951  		return nil, err
   952  	} else {
   953  		defer closeBody(r)
   954  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   955  			r.Header.Get(HEADER_ETAG_SERVER), ConfigFromJson(r.Body)}, nil
   956  	}
   957  }
   958  
   959  // ReloadConfig will reload the config.json file from disk.  Properties
   960  // requiring a server restart will still need a server restart.  You must
   961  // have the system admin role to call this method.  It will return status=OK
   962  // if it's successfully reloaded the config file, otherwise check the returned error.
   963  func (c *Client) ReloadConfig() (bool, *AppError) {
   964  	c.clearExtraProperties()
   965  	if r, err := c.DoApiGet("/admin/reload_config", "", ""); err != nil {
   966  		return false, err
   967  	} else {
   968  		c.fillInExtraProperties(r)
   969  		return c.CheckStatusOK(r), nil
   970  	}
   971  }
   972  
   973  func (c *Client) InvalidateAllCaches() (bool, *AppError) {
   974  	c.clearExtraProperties()
   975  	if r, err := c.DoApiGet("/admin/invalidate_all_caches", "", ""); err != nil {
   976  		return false, err
   977  	} else {
   978  		c.fillInExtraProperties(r)
   979  		return c.CheckStatusOK(r), nil
   980  	}
   981  }
   982  
   983  func (c *Client) SaveConfig(config *Config) (*Result, *AppError) {
   984  	if r, err := c.DoApiPost("/admin/save_config", config.ToJson()); err != nil {
   985  		return nil, err
   986  	} else {
   987  		defer closeBody(r)
   988  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
   989  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
   990  	}
   991  }
   992  
   993  // RecycleDatabaseConnection will attempt to recycle the database connections.
   994  // You must have the system admin role to call this method.  It will return status=OK
   995  // if it's successfully recycled the connections, otherwise check the returned error.
   996  func (c *Client) RecycleDatabaseConnection() (bool, *AppError) {
   997  	c.clearExtraProperties()
   998  	if r, err := c.DoApiGet("/admin/recycle_db_conn", "", ""); err != nil {
   999  		return false, err
  1000  	} else {
  1001  		c.fillInExtraProperties(r)
  1002  		return c.CheckStatusOK(r), nil
  1003  	}
  1004  }
  1005  
  1006  func (c *Client) TestEmail(config *Config) (*Result, *AppError) {
  1007  	if r, err := c.DoApiPost("/admin/test_email", config.ToJson()); err != nil {
  1008  		return nil, err
  1009  	} else {
  1010  		defer closeBody(r)
  1011  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1012  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1013  	}
  1014  }
  1015  
  1016  // TestLdap will run a connection test on the current LDAP settings.
  1017  // It will return the standard OK response if settings work. Otherwise
  1018  // it will return an appropriate error.
  1019  func (c *Client) TestLdap(config *Config) (*Result, *AppError) {
  1020  	if r, err := c.DoApiPost("/admin/ldap_test", config.ToJson()); err != nil {
  1021  		return nil, err
  1022  	} else {
  1023  		defer closeBody(r)
  1024  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1025  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1026  	}
  1027  }
  1028  
  1029  func (c *Client) GetComplianceReports() (*Result, *AppError) {
  1030  	if r, err := c.DoApiGet("/admin/compliance_reports", "", ""); err != nil {
  1031  		return nil, err
  1032  	} else {
  1033  		defer closeBody(r)
  1034  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1035  			r.Header.Get(HEADER_ETAG_SERVER), CompliancesFromJson(r.Body)}, nil
  1036  	}
  1037  }
  1038  
  1039  func (c *Client) SaveComplianceReport(job *Compliance) (*Result, *AppError) {
  1040  	if r, err := c.DoApiPost("/admin/save_compliance_report", job.ToJson()); err != nil {
  1041  		return nil, err
  1042  	} else {
  1043  		defer closeBody(r)
  1044  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1045  			r.Header.Get(HEADER_ETAG_SERVER), ComplianceFromJson(r.Body)}, nil
  1046  	}
  1047  }
  1048  
  1049  func (c *Client) DownloadComplianceReport(id string) (*Result, *AppError) {
  1050  	var rq *http.Request
  1051  	rq, _ = http.NewRequest("GET", c.ApiUrl+"/admin/download_compliance_report/"+id, nil)
  1052  	rq.Close = true
  1053  
  1054  	if len(c.AuthToken) > 0 {
  1055  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  1056  	}
  1057  
  1058  	if rp, err := c.HttpClient.Do(rq); err != nil {
  1059  		return nil, NewAppError("/admin/download_compliance_report", "model.client.connecting.app_error", nil, err.Error(), 0)
  1060  	} else if rp.StatusCode >= 300 {
  1061  		defer rp.Body.Close()
  1062  		return nil, AppErrorFromJson(rp.Body)
  1063  	} else {
  1064  		defer closeBody(rp)
  1065  		return &Result{rp.Header.Get(HEADER_REQUEST_ID),
  1066  			rp.Header.Get(HEADER_ETAG_SERVER), rp.Body}, nil
  1067  	}
  1068  }
  1069  
  1070  func (c *Client) GetTeamAnalytics(teamId, name string) (*Result, *AppError) {
  1071  	if r, err := c.DoApiGet("/admin/analytics/"+teamId+"/"+name, "", ""); err != nil {
  1072  		return nil, err
  1073  	} else {
  1074  		defer closeBody(r)
  1075  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1076  			r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
  1077  	}
  1078  }
  1079  
  1080  func (c *Client) GetSystemAnalytics(name string) (*Result, *AppError) {
  1081  	if r, err := c.DoApiGet("/admin/analytics/"+name, "", ""); err != nil {
  1082  		return nil, err
  1083  	} else {
  1084  		defer closeBody(r)
  1085  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1086  			r.Header.Get(HEADER_ETAG_SERVER), AnalyticsRowsFromJson(r.Body)}, nil
  1087  	}
  1088  }
  1089  
  1090  // Initiate immediate synchronization of LDAP users.
  1091  // The synchronization will be performed asynchronously and this function will
  1092  // always return OK unless you don't have permissions.
  1093  // You must be the system administrator to use this function.
  1094  func (c *Client) LdapSyncNow() (*Result, *AppError) {
  1095  	if r, err := c.DoApiPost("/admin/ldap_sync_now", ""); err != nil {
  1096  		return nil, err
  1097  	} else {
  1098  		defer closeBody(r)
  1099  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1100  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1101  	}
  1102  }
  1103  
  1104  func (c *Client) CreateChannel(channel *Channel) (*Result, *AppError) {
  1105  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create", channel.ToJson()); err != nil {
  1106  		return nil, err
  1107  	} else {
  1108  		defer closeBody(r)
  1109  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1110  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1111  	}
  1112  }
  1113  
  1114  func (c *Client) CreateDirectChannel(userId string) (*Result, *AppError) {
  1115  	data := make(map[string]string)
  1116  	data["user_id"] = userId
  1117  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_direct", MapToJson(data)); err != nil {
  1118  		return nil, err
  1119  	} else {
  1120  		defer closeBody(r)
  1121  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1122  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1123  	}
  1124  }
  1125  
  1126  func (c *Client) CreateGroupChannel(userIds []string) (*Result, *AppError) {
  1127  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/create_group", ArrayToJson(userIds)); err != nil {
  1128  		return nil, err
  1129  	} else {
  1130  		defer closeBody(r)
  1131  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1132  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1133  	}
  1134  }
  1135  
  1136  func (c *Client) UpdateChannel(channel *Channel) (*Result, *AppError) {
  1137  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update", channel.ToJson()); err != nil {
  1138  		return nil, err
  1139  	} else {
  1140  		defer closeBody(r)
  1141  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1142  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1143  	}
  1144  }
  1145  
  1146  func (c *Client) UpdateChannelHeader(data map[string]string) (*Result, *AppError) {
  1147  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_header", MapToJson(data)); err != nil {
  1148  		return nil, err
  1149  	} else {
  1150  		defer closeBody(r)
  1151  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1152  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1153  	}
  1154  }
  1155  
  1156  func (c *Client) UpdateChannelPurpose(data map[string]string) (*Result, *AppError) {
  1157  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_purpose", MapToJson(data)); err != nil {
  1158  		return nil, err
  1159  	} else {
  1160  		defer closeBody(r)
  1161  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1162  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1163  	}
  1164  }
  1165  
  1166  func (c *Client) UpdateNotifyProps(data map[string]string) (*Result, *AppError) {
  1167  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/update_notify_props", MapToJson(data)); err != nil {
  1168  		return nil, err
  1169  	} else {
  1170  		defer closeBody(r)
  1171  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1172  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1173  	}
  1174  }
  1175  
  1176  func (c *Client) GetMyChannelMembers() (*Result, *AppError) {
  1177  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/members", "", ""); err != nil {
  1178  		return nil, err
  1179  	} else {
  1180  		defer closeBody(r)
  1181  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1182  			r.Header.Get(HEADER_ETAG_SERVER), ChannelMembersFromJson(r.Body)}, nil
  1183  	}
  1184  }
  1185  
  1186  func (c *Client) GetChannel(id, etag string) (*Result, *AppError) {
  1187  	if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/", "", etag); err != nil {
  1188  		return nil, err
  1189  	} else {
  1190  		defer closeBody(r)
  1191  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1192  			r.Header.Get(HEADER_ETAG_SERVER), ChannelDataFromJson(r.Body)}, nil
  1193  	}
  1194  }
  1195  
  1196  // GetMoreChannelsPage will return a page of open channels the user is not in based on
  1197  // the provided offset and limit. Must be authenticated.
  1198  func (c *Client) GetMoreChannelsPage(offset int, limit int) (*Result, *AppError) {
  1199  	if r, err := c.DoApiGet(fmt.Sprintf(c.GetTeamRoute()+"/channels/more/%v/%v", offset, limit), "", ""); err != nil {
  1200  		return nil, err
  1201  	} else {
  1202  		defer closeBody(r)
  1203  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1204  			r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
  1205  	}
  1206  }
  1207  
  1208  // SearchMoreChannels will return a list of open channels the user is not in, that matches
  1209  // the search criteria provided. Must be authenticated.
  1210  func (c *Client) SearchMoreChannels(channelSearch ChannelSearch) (*Result, *AppError) {
  1211  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/more/search", channelSearch.ToJson()); err != nil {
  1212  		return nil, err
  1213  	} else {
  1214  		defer closeBody(r)
  1215  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1216  			r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
  1217  	}
  1218  }
  1219  
  1220  // AutocompleteChannels will return a list of open channels that match the provided
  1221  // string. Must be authenticated.
  1222  func (c *Client) AutocompleteChannels(term string) (*Result, *AppError) {
  1223  	url := fmt.Sprintf("%s/channels/autocomplete?term=%s", c.GetTeamRoute(), url.QueryEscape(term))
  1224  	if r, err := c.DoApiGet(url, "", ""); err != nil {
  1225  		return nil, err
  1226  	} else {
  1227  		defer closeBody(r)
  1228  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1229  			r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
  1230  	}
  1231  }
  1232  
  1233  func (c *Client) GetChannelCounts(etag string) (*Result, *AppError) {
  1234  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/counts", "", etag); err != nil {
  1235  		return nil, err
  1236  	} else {
  1237  		defer closeBody(r)
  1238  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1239  			r.Header.Get(HEADER_ETAG_SERVER), ChannelCountsFromJson(r.Body)}, nil
  1240  	}
  1241  }
  1242  
  1243  func (c *Client) GetChannels(etag string) (*Result, *AppError) {
  1244  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/channels/", "", etag); err != nil {
  1245  		return nil, err
  1246  	} else {
  1247  		defer closeBody(r)
  1248  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1249  			r.Header.Get(HEADER_ETAG_SERVER), ChannelListFromJson(r.Body)}, nil
  1250  	}
  1251  }
  1252  
  1253  func (c *Client) GetChannelByName(channelName string) (*Result, *AppError) {
  1254  	if r, err := c.DoApiGet(c.GetChannelNameRoute(channelName), "", ""); err != nil {
  1255  		return nil, err
  1256  	} else {
  1257  		defer closeBody(r)
  1258  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1259  			r.Header.Get(HEADER_ETAG_SERVER), ChannelFromJson(r.Body)}, nil
  1260  	}
  1261  }
  1262  
  1263  func (c *Client) JoinChannel(id string) (*Result, *AppError) {
  1264  	if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/join", ""); err != nil {
  1265  		return nil, err
  1266  	} else {
  1267  		defer closeBody(r)
  1268  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1269  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  1270  	}
  1271  }
  1272  
  1273  func (c *Client) JoinChannelByName(name string) (*Result, *AppError) {
  1274  	if r, err := c.DoApiPost(c.GetChannelNameRoute(name)+"/join", ""); err != nil {
  1275  		return nil, err
  1276  	} else {
  1277  		defer closeBody(r)
  1278  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1279  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  1280  	}
  1281  }
  1282  
  1283  func (c *Client) LeaveChannel(id string) (*Result, *AppError) {
  1284  	if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/leave", ""); err != nil {
  1285  		return nil, err
  1286  	} else {
  1287  		defer closeBody(r)
  1288  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1289  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  1290  	}
  1291  }
  1292  
  1293  func (c *Client) DeleteChannel(id string) (*Result, *AppError) {
  1294  	if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/delete", ""); err != nil {
  1295  		return nil, err
  1296  	} else {
  1297  		defer closeBody(r)
  1298  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1299  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  1300  	}
  1301  }
  1302  
  1303  func (c *Client) AddChannelMember(id, user_id string) (*Result, *AppError) {
  1304  	data := make(map[string]string)
  1305  	data["user_id"] = user_id
  1306  	if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/add", MapToJson(data)); err != nil {
  1307  		return nil, err
  1308  	} else {
  1309  		defer closeBody(r)
  1310  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1311  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  1312  	}
  1313  }
  1314  
  1315  func (c *Client) RemoveChannelMember(id, user_id string) (*Result, *AppError) {
  1316  	data := make(map[string]string)
  1317  	data["user_id"] = user_id
  1318  	if r, err := c.DoApiPost(c.GetChannelRoute(id)+"/remove", MapToJson(data)); err != nil {
  1319  		return nil, err
  1320  	} else {
  1321  		defer closeBody(r)
  1322  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1323  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  1324  	}
  1325  }
  1326  
  1327  // ViewChannel performs all the actions related to viewing a channel. This includes marking
  1328  // the channel and the previous one as read, and marking the channel as being actively viewed.
  1329  // ChannelId is required but may be blank to indicate no channel is being viewed.
  1330  // PrevChannelId is optional, populate to indicate a channel switch occurred.
  1331  func (c *Client) ViewChannel(params ChannelView) (bool, *ResponseMetadata) {
  1332  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/channels/view", params.ToJson()); err != nil {
  1333  		return false, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
  1334  	} else {
  1335  		return c.CheckStatusOK(r),
  1336  			&ResponseMetadata{
  1337  				StatusCode: r.StatusCode,
  1338  				RequestId:  r.Header.Get(HEADER_REQUEST_ID),
  1339  				Etag:       r.Header.Get(HEADER_ETAG_SERVER),
  1340  			}
  1341  	}
  1342  }
  1343  
  1344  func (c *Client) GetChannelStats(id string, etag string) (*Result, *AppError) {
  1345  	if r, err := c.DoApiGet(c.GetChannelRoute(id)+"/stats", "", etag); err != nil {
  1346  		return nil, err
  1347  	} else {
  1348  		defer closeBody(r)
  1349  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1350  			r.Header.Get(HEADER_ETAG_SERVER), ChannelStatsFromJson(r.Body)}, nil
  1351  	}
  1352  }
  1353  
  1354  func (c *Client) GetChannelMember(channelId string, userId string) (*Result, *AppError) {
  1355  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/members/"+userId, "", ""); err != nil {
  1356  		return nil, err
  1357  	} else {
  1358  		defer closeBody(r)
  1359  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1360  			r.Header.Get(HEADER_ETAG_SERVER), ChannelMemberFromJson(r.Body)}, nil
  1361  	}
  1362  }
  1363  
  1364  // GetChannelMembersByIds will return channel member objects as an array based on the
  1365  // channel id and a list of user ids provided. Must be authenticated.
  1366  func (c *Client) GetChannelMembersByIds(channelId string, userIds []string) (*Result, *AppError) {
  1367  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/members/ids", ArrayToJson(userIds)); err != nil {
  1368  		return nil, err
  1369  	} else {
  1370  		defer closeBody(r)
  1371  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1372  			r.Header.Get(HEADER_ETAG_SERVER), ChannelMembersFromJson(r.Body)}, nil
  1373  	}
  1374  }
  1375  
  1376  func (c *Client) CreatePost(post *Post) (*Result, *AppError) {
  1377  	if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/create", post.ToJson()); err != nil {
  1378  		return nil, err
  1379  	} else {
  1380  		defer closeBody(r)
  1381  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1382  			r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
  1383  	}
  1384  }
  1385  
  1386  func (c *Client) UpdatePost(post *Post) (*Result, *AppError) {
  1387  	if r, err := c.DoApiPost(c.GetChannelRoute(post.ChannelId)+"/posts/update", post.ToJson()); err != nil {
  1388  		return nil, err
  1389  	} else {
  1390  		defer closeBody(r)
  1391  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1392  			r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
  1393  	}
  1394  }
  1395  
  1396  func (c *Client) GetPosts(channelId string, offset int, limit int, etag string) (*Result, *AppError) {
  1397  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/page/%v/%v", offset, limit), "", etag); err != nil {
  1398  		return nil, err
  1399  	} else {
  1400  		defer closeBody(r)
  1401  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1402  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1403  	}
  1404  }
  1405  
  1406  func (c *Client) GetPostsSince(channelId string, time int64) (*Result, *AppError) {
  1407  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/since/%v", time), "", ""); err != nil {
  1408  		return nil, err
  1409  	} else {
  1410  		defer closeBody(r)
  1411  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1412  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1413  	}
  1414  }
  1415  
  1416  func (c *Client) GetPostsBefore(channelId string, postid string, offset int, limit int, etag string) (*Result, *AppError) {
  1417  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/before/%v/%v", postid, offset, limit), "", etag); err != nil {
  1418  		return nil, err
  1419  	} else {
  1420  		defer closeBody(r)
  1421  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1422  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1423  	}
  1424  }
  1425  
  1426  func (c *Client) GetPostsAfter(channelId string, postid string, offset int, limit int, etag string) (*Result, *AppError) {
  1427  	if r, err := c.DoApiGet(fmt.Sprintf(c.GetChannelRoute(channelId)+"/posts/%v/after/%v/%v", postid, offset, limit), "", etag); err != nil {
  1428  		return nil, err
  1429  	} else {
  1430  		defer closeBody(r)
  1431  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1432  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1433  	}
  1434  }
  1435  
  1436  func (c *Client) GetPost(channelId string, postId string, etag string) (*Result, *AppError) {
  1437  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get", postId), "", etag); err != nil {
  1438  		return nil, err
  1439  	} else {
  1440  		defer closeBody(r)
  1441  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1442  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1443  	}
  1444  }
  1445  
  1446  // GetPostById returns a post and any posts in the same thread by post id
  1447  func (c *Client) GetPostById(postId string, etag string) (*PostList, *ResponseMetadata) {
  1448  	if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/posts/%v", postId), "", etag); err != nil {
  1449  		return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
  1450  	} else {
  1451  		defer closeBody(r)
  1452  		return PostListFromJson(r.Body),
  1453  			&ResponseMetadata{
  1454  				StatusCode: r.StatusCode,
  1455  				RequestId:  r.Header.Get(HEADER_REQUEST_ID),
  1456  				Etag:       r.Header.Get(HEADER_ETAG_SERVER),
  1457  			}
  1458  	}
  1459  }
  1460  
  1461  // GetPermalink returns a post list, based on the provided channel and post ID.
  1462  func (c *Client) GetPermalink(channelId string, postId string, etag string) (*PostList, *ResponseMetadata) {
  1463  	if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/pltmp/%v", postId), "", etag); err != nil {
  1464  		return nil, &ResponseMetadata{StatusCode: r.StatusCode, Error: err}
  1465  	} else {
  1466  		defer closeBody(r)
  1467  		return PostListFromJson(r.Body),
  1468  			&ResponseMetadata{
  1469  				StatusCode: r.StatusCode,
  1470  				RequestId:  r.Header.Get(HEADER_REQUEST_ID),
  1471  				Etag:       r.Header.Get(HEADER_ETAG_SERVER),
  1472  			}
  1473  	}
  1474  }
  1475  
  1476  func (c *Client) DeletePost(channelId string, postId string) (*Result, *AppError) {
  1477  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/delete", postId), ""); err != nil {
  1478  		return nil, err
  1479  	} else {
  1480  		defer closeBody(r)
  1481  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1482  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1483  	}
  1484  }
  1485  
  1486  func (c *Client) SearchPosts(terms string, isOrSearch bool) (*Result, *AppError) {
  1487  	data := map[string]interface{}{}
  1488  	data["terms"] = terms
  1489  	data["is_or_search"] = isOrSearch
  1490  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/posts/search", StringInterfaceToJson(data)); err != nil {
  1491  		return nil, err
  1492  	} else {
  1493  		defer closeBody(r)
  1494  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1495  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1496  	}
  1497  }
  1498  
  1499  // GetFlaggedPosts will return a post list of posts that have been flagged by the user.
  1500  // The page is set by the integer parameters offset and limit.
  1501  func (c *Client) GetFlaggedPosts(offset int, limit int) (*Result, *AppError) {
  1502  	if r, err := c.DoApiGet(c.GetTeamRoute()+fmt.Sprintf("/posts/flagged/%v/%v", offset, limit), "", ""); err != nil {
  1503  		return nil, err
  1504  	} else {
  1505  		defer closeBody(r)
  1506  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1507  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1508  	}
  1509  }
  1510  
  1511  func (c *Client) GetPinnedPosts(channelId string) (*Result, *AppError) {
  1512  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+"/pinned", "", ""); err != nil {
  1513  		return nil, err
  1514  	} else {
  1515  		defer closeBody(r)
  1516  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1517  			r.Header.Get(HEADER_ETAG_SERVER), PostListFromJson(r.Body)}, nil
  1518  	}
  1519  }
  1520  
  1521  func (c *Client) UploadProfileFile(data []byte, contentType string) (*Result, *AppError) {
  1522  	return c.uploadFile(c.ApiUrl+"/users/newimage", data, contentType)
  1523  }
  1524  
  1525  func (c *Client) UploadPostAttachment(data []byte, channelId string, filename string) (*FileUploadResponse, *AppError) {
  1526  	c.clearExtraProperties()
  1527  
  1528  	body := &bytes.Buffer{}
  1529  	writer := multipart.NewWriter(body)
  1530  
  1531  	if part, err := writer.CreateFormFile("files", filename); err != nil {
  1532  		return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), 0)
  1533  	} else if _, err = io.Copy(part, bytes.NewBuffer(data)); err != nil {
  1534  		return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.file.app_error", nil, err.Error(), 0)
  1535  	}
  1536  
  1537  	if part, err := writer.CreateFormField("channel_id"); err != nil {
  1538  		return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), 0)
  1539  	} else if _, err = io.Copy(part, strings.NewReader(channelId)); err != nil {
  1540  		return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.channel_id.app_error", nil, err.Error(), 0)
  1541  	}
  1542  
  1543  	if err := writer.Close(); err != nil {
  1544  		return nil, NewAppError("UploadPostAttachment", "model.client.upload_post_attachment.writer.app_error", nil, err.Error(), 0)
  1545  	}
  1546  
  1547  	if result, err := c.uploadFile(c.ApiUrl+c.GetTeamRoute()+"/files/upload", body.Bytes(), writer.FormDataContentType()); err != nil {
  1548  		return nil, err
  1549  	} else {
  1550  		return result.Data.(*FileUploadResponse), nil
  1551  	}
  1552  }
  1553  
  1554  func (c *Client) uploadFile(url string, data []byte, contentType string) (*Result, *AppError) {
  1555  	rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
  1556  	rq.Header.Set("Content-Type", contentType)
  1557  	rq.Close = true
  1558  
  1559  	if len(c.AuthToken) > 0 {
  1560  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  1561  	}
  1562  
  1563  	if rp, err := c.HttpClient.Do(rq); err != nil {
  1564  		return nil, NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
  1565  	} else if rp.StatusCode >= 300 {
  1566  		return nil, AppErrorFromJson(rp.Body)
  1567  	} else {
  1568  		defer closeBody(rp)
  1569  		return &Result{rp.Header.Get(HEADER_REQUEST_ID),
  1570  			rp.Header.Get(HEADER_ETAG_SERVER), FileUploadResponseFromJson(rp.Body)}, nil
  1571  	}
  1572  }
  1573  
  1574  func (c *Client) GetFile(fileId string) (io.ReadCloser, *AppError) {
  1575  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get", "", ""); err != nil {
  1576  		return nil, err
  1577  	} else {
  1578  		c.fillInExtraProperties(r)
  1579  		return r.Body, nil
  1580  	}
  1581  }
  1582  
  1583  func (c *Client) GetFileThumbnail(fileId string) (io.ReadCloser, *AppError) {
  1584  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_thumbnail", "", ""); err != nil {
  1585  		return nil, err
  1586  	} else {
  1587  		c.fillInExtraProperties(r)
  1588  		return r.Body, nil
  1589  	}
  1590  }
  1591  
  1592  func (c *Client) GetFilePreview(fileId string) (io.ReadCloser, *AppError) {
  1593  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_preview", "", ""); err != nil {
  1594  		return nil, err
  1595  	} else {
  1596  		defer closeBody(r)
  1597  		c.fillInExtraProperties(r)
  1598  		return r.Body, nil
  1599  	}
  1600  }
  1601  
  1602  func (c *Client) GetFileInfo(fileId string) (*FileInfo, *AppError) {
  1603  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_info", "", ""); err != nil {
  1604  		return nil, err
  1605  	} else {
  1606  		defer closeBody(r)
  1607  		c.fillInExtraProperties(r)
  1608  		return FileInfoFromJson(r.Body), nil
  1609  	}
  1610  }
  1611  
  1612  func (c *Client) GetPublicLink(fileId string) (string, *AppError) {
  1613  	if r, err := c.DoApiGet(c.GetFileRoute(fileId)+"/get_public_link", "", ""); err != nil {
  1614  		return "", err
  1615  	} else {
  1616  		defer closeBody(r)
  1617  		c.fillInExtraProperties(r)
  1618  		return StringFromJson(r.Body), nil
  1619  	}
  1620  }
  1621  
  1622  func (c *Client) UpdateUser(user *User) (*Result, *AppError) {
  1623  	if r, err := c.DoApiPost("/users/update", user.ToJson()); err != nil {
  1624  		return nil, err
  1625  	} else {
  1626  		defer closeBody(r)
  1627  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1628  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
  1629  	}
  1630  }
  1631  
  1632  func (c *Client) UpdateUserRoles(userId string, roles string) (*Result, *AppError) {
  1633  	data := make(map[string]string)
  1634  	data["new_roles"] = roles
  1635  
  1636  	if r, err := c.DoApiPost(c.GetUserRequiredRoute(userId)+"/update_roles", MapToJson(data)); err != nil {
  1637  		return nil, err
  1638  	} else {
  1639  		defer closeBody(r)
  1640  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1641  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1642  	}
  1643  }
  1644  
  1645  func (c *Client) UpdateTeamRoles(userId string, roles string) (*Result, *AppError) {
  1646  	data := make(map[string]string)
  1647  	data["new_roles"] = roles
  1648  	data["user_id"] = userId
  1649  
  1650  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/update_member_roles", MapToJson(data)); err != nil {
  1651  		return nil, err
  1652  	} else {
  1653  		defer closeBody(r)
  1654  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1655  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1656  	}
  1657  }
  1658  
  1659  func (c *Client) AttachDeviceId(deviceId string) (*Result, *AppError) {
  1660  	data := make(map[string]string)
  1661  	data["device_id"] = deviceId
  1662  	if r, err := c.DoApiPost("/users/attach_device", MapToJson(data)); err != nil {
  1663  		return nil, err
  1664  	} else {
  1665  		defer closeBody(r)
  1666  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1667  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
  1668  	}
  1669  }
  1670  
  1671  func (c *Client) UpdateActive(userId string, active bool) (*Result, *AppError) {
  1672  	data := make(map[string]string)
  1673  	data["user_id"] = userId
  1674  	data["active"] = strconv.FormatBool(active)
  1675  	if r, err := c.DoApiPost("/users/update_active", MapToJson(data)); err != nil {
  1676  		return nil, err
  1677  	} else {
  1678  		defer closeBody(r)
  1679  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1680  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
  1681  	}
  1682  }
  1683  
  1684  func (c *Client) UpdateUserNotify(data map[string]string) (*Result, *AppError) {
  1685  	if r, err := c.DoApiPost("/users/update_notify", MapToJson(data)); err != nil {
  1686  		return nil, err
  1687  	} else {
  1688  		defer closeBody(r)
  1689  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1690  			r.Header.Get(HEADER_ETAG_SERVER), UserFromJson(r.Body)}, nil
  1691  	}
  1692  }
  1693  
  1694  func (c *Client) UpdateUserPassword(userId, currentPassword, newPassword string) (*Result, *AppError) {
  1695  	data := make(map[string]string)
  1696  	data["current_password"] = currentPassword
  1697  	data["new_password"] = newPassword
  1698  	data["user_id"] = userId
  1699  
  1700  	if r, err := c.DoApiPost("/users/newpassword", MapToJson(data)); err != nil {
  1701  		return nil, err
  1702  	} else {
  1703  		defer closeBody(r)
  1704  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1705  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1706  	}
  1707  }
  1708  
  1709  func (c *Client) SendPasswordReset(email string) (*Result, *AppError) {
  1710  	data := map[string]string{}
  1711  	data["email"] = email
  1712  	if r, err := c.DoApiPost("/users/send_password_reset", MapToJson(data)); err != nil {
  1713  		return nil, err
  1714  	} else {
  1715  		defer closeBody(r)
  1716  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1717  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1718  	}
  1719  }
  1720  
  1721  func (c *Client) ResetPassword(code, newPassword string) (*Result, *AppError) {
  1722  	data := map[string]string{}
  1723  	data["code"] = code
  1724  	data["new_password"] = newPassword
  1725  	if r, err := c.DoApiPost("/users/reset_password", MapToJson(data)); err != nil {
  1726  		return nil, err
  1727  	} else {
  1728  		defer closeBody(r)
  1729  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1730  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1731  	}
  1732  }
  1733  
  1734  func (c *Client) AdminResetPassword(userId, newPassword string) (*Result, *AppError) {
  1735  	data := map[string]string{}
  1736  	data["user_id"] = userId
  1737  	data["new_password"] = newPassword
  1738  	if r, err := c.DoApiPost("/admin/reset_password", MapToJson(data)); err != nil {
  1739  		return nil, err
  1740  	} else {
  1741  		defer closeBody(r)
  1742  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1743  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1744  	}
  1745  }
  1746  
  1747  // GetStatuses returns a map of string statuses using user id as the key
  1748  func (c *Client) GetStatuses() (*Result, *AppError) {
  1749  	if r, err := c.DoApiGet("/users/status", "", ""); err != nil {
  1750  		return nil, err
  1751  	} else {
  1752  		defer closeBody(r)
  1753  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1754  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1755  	}
  1756  }
  1757  
  1758  // GetStatusesByIds returns a map of string statuses using user id as the key,
  1759  // based on the provided user ids
  1760  func (c *Client) GetStatusesByIds(userIds []string) (*Result, *AppError) {
  1761  	if r, err := c.DoApiPost("/users/status/ids", ArrayToJson(userIds)); err != nil {
  1762  		return nil, err
  1763  	} else {
  1764  		defer closeBody(r)
  1765  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1766  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1767  	}
  1768  }
  1769  
  1770  func (c *Client) GetMyTeam(etag string) (*Result, *AppError) {
  1771  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/me", "", etag); err != nil {
  1772  		return nil, err
  1773  	} else {
  1774  		defer closeBody(r)
  1775  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1776  			r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
  1777  	}
  1778  }
  1779  
  1780  // GetTeamMembers will return a page of team member objects as an array paged based on the
  1781  // team id, offset and limit provided. Must be authenticated.
  1782  func (c *Client) GetTeamMembers(teamId string, offset int, limit int) (*Result, *AppError) {
  1783  	if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/members/%v/%v", teamId, offset, limit), "", ""); err != nil {
  1784  		return nil, err
  1785  	} else {
  1786  		defer closeBody(r)
  1787  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1788  			r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
  1789  	}
  1790  }
  1791  
  1792  // GetMyTeamMembers will return an array with team member objects that the current user
  1793  // is a member of. Must be authenticated.
  1794  func (c *Client) GetMyTeamMembers() (*Result, *AppError) {
  1795  	if r, err := c.DoApiGet("/teams/members", "", ""); err != nil {
  1796  		return nil, err
  1797  	} else {
  1798  		defer closeBody(r)
  1799  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1800  			r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
  1801  	}
  1802  }
  1803  
  1804  // GetMyTeamsUnread will return an array with TeamUnread objects that contain the amount of
  1805  // unread messages and mentions the current user has for the teams it belongs to.
  1806  // An optional team ID can be set to exclude that team from the results. Must be authenticated.
  1807  func (c *Client) GetMyTeamsUnread(teamId string) (*Result, *AppError) {
  1808  	endpoint := "/teams/unread"
  1809  
  1810  	if teamId != "" {
  1811  		endpoint += fmt.Sprintf("?id=%s", url.QueryEscape(teamId))
  1812  	}
  1813  	if r, err := c.DoApiGet(endpoint, "", ""); err != nil {
  1814  		return nil, err
  1815  	} else {
  1816  		defer closeBody(r)
  1817  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1818  			r.Header.Get(HEADER_ETAG_SERVER), TeamsUnreadFromJson(r.Body)}, nil
  1819  	}
  1820  }
  1821  
  1822  // GetTeamMember will return a team member object based on the team id and user id provided.
  1823  // Must be authenticated.
  1824  func (c *Client) GetTeamMember(teamId string, userId string) (*Result, *AppError) {
  1825  	if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/members/%v", teamId, userId), "", ""); err != nil {
  1826  		return nil, err
  1827  	} else {
  1828  		defer closeBody(r)
  1829  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1830  			r.Header.Get(HEADER_ETAG_SERVER), TeamMemberFromJson(r.Body)}, nil
  1831  	}
  1832  }
  1833  
  1834  // GetTeamStats will return a team stats object containing the number of users on the team
  1835  // based on the team id provided. Must be authenticated.
  1836  func (c *Client) GetTeamStats(teamId string) (*Result, *AppError) {
  1837  	if r, err := c.DoApiGet(fmt.Sprintf("/teams/%v/stats", teamId), "", ""); err != nil {
  1838  		return nil, err
  1839  	} else {
  1840  		defer closeBody(r)
  1841  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1842  			r.Header.Get(HEADER_ETAG_SERVER), TeamStatsFromJson(r.Body)}, nil
  1843  	}
  1844  }
  1845  
  1846  // GetTeamByName will return a team object based on the team name provided. Must be authenticated.
  1847  func (c *Client) GetTeamByName(teamName string) (*Result, *AppError) {
  1848  	if r, err := c.DoApiGet(fmt.Sprintf("/teams/name/%v", teamName), "", ""); err != nil {
  1849  		return nil, err
  1850  	} else {
  1851  		defer closeBody(r)
  1852  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1853  			r.Header.Get(HEADER_ETAG_SERVER), TeamFromJson(r.Body)}, nil
  1854  	}
  1855  }
  1856  
  1857  // GetTeamMembersByIds will return team member objects as an array based on the
  1858  // team id and a list of user ids provided. Must be authenticated.
  1859  func (c *Client) GetTeamMembersByIds(teamId string, userIds []string) (*Result, *AppError) {
  1860  	if r, err := c.DoApiPost(fmt.Sprintf("/teams/%v/members/ids", teamId), ArrayToJson(userIds)); err != nil {
  1861  		return nil, err
  1862  	} else {
  1863  		defer closeBody(r)
  1864  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1865  			r.Header.Get(HEADER_ETAG_SERVER), TeamMembersFromJson(r.Body)}, nil
  1866  	}
  1867  }
  1868  
  1869  // RegisterApp creates a new OAuth2 app to be used with the OAuth2 Provider. On success
  1870  // it returns the created app. Must be authenticated as a user.
  1871  func (c *Client) RegisterApp(app *OAuthApp) (*Result, *AppError) {
  1872  	if r, err := c.DoApiPost("/oauth/register", app.ToJson()); err != nil {
  1873  		return nil, err
  1874  	} else {
  1875  		defer closeBody(r)
  1876  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1877  			r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
  1878  	}
  1879  }
  1880  
  1881  // AllowOAuth allows a new session by an OAuth2 App. On success
  1882  // it returns the url to be redirected back to the app which initiated the oauth2 flow.
  1883  // Must be authenticated as a user.
  1884  func (c *Client) AllowOAuth(rspType, clientId, redirect, scope, state string) (*Result, *AppError) {
  1885  	if r, err := c.DoApiGet("/oauth/allow?response_type="+rspType+"&client_id="+clientId+"&redirect_uri="+url.QueryEscape(redirect)+"&scope="+scope+"&state="+url.QueryEscape(state), "", ""); err != nil {
  1886  		return nil, err
  1887  	} else {
  1888  		defer closeBody(r)
  1889  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1890  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1891  	}
  1892  }
  1893  
  1894  // GetOAuthAppsByUser returns the OAuth2 Apps registered by the user. On success
  1895  // it returns a list of OAuth2 Apps from the same user or all the registered apps if the user
  1896  // is a System Administrator. Must be authenticated as a user.
  1897  func (c *Client) GetOAuthAppsByUser() (*Result, *AppError) {
  1898  	if r, err := c.DoApiGet("/oauth/list", "", ""); err != nil {
  1899  		return nil, err
  1900  	} else {
  1901  		defer closeBody(r)
  1902  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1903  			r.Header.Get(HEADER_ETAG_SERVER), OAuthAppListFromJson(r.Body)}, nil
  1904  	}
  1905  }
  1906  
  1907  // GetOAuthAppInfo lookup an OAuth2 App using the client_id. On success
  1908  // it returns a Sanitized OAuth2 App. Must be authenticated as a user.
  1909  func (c *Client) GetOAuthAppInfo(clientId string) (*Result, *AppError) {
  1910  	if r, err := c.DoApiGet("/oauth/app/"+clientId, "", ""); err != nil {
  1911  		return nil, err
  1912  	} else {
  1913  		defer closeBody(r)
  1914  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1915  			r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
  1916  	}
  1917  }
  1918  
  1919  // DeleteOAuthApp deletes an OAuth2 app, the app must be deleted by the same user who created it or
  1920  // a System Administrator. On success returs Status OK. Must be authenticated as a user.
  1921  func (c *Client) DeleteOAuthApp(id string) (*Result, *AppError) {
  1922  	data := make(map[string]string)
  1923  	data["id"] = id
  1924  	if r, err := c.DoApiPost("/oauth/delete", MapToJson(data)); err != nil {
  1925  		return nil, err
  1926  	} else {
  1927  		defer closeBody(r)
  1928  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1929  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  1930  	}
  1931  }
  1932  
  1933  // GetOAuthAuthorizedApps returns the OAuth2 Apps authorized by the user. On success
  1934  // it returns a list of sanitized OAuth2 Authorized Apps by the user.
  1935  func (c *Client) GetOAuthAuthorizedApps() (*Result, *AppError) {
  1936  	if r, err := c.DoApiGet("/oauth/authorized", "", ""); err != nil {
  1937  		return nil, err
  1938  	} else {
  1939  		defer closeBody(r)
  1940  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1941  			r.Header.Get(HEADER_ETAG_SERVER), OAuthAppListFromJson(r.Body)}, nil
  1942  	}
  1943  }
  1944  
  1945  // OAuthDeauthorizeApp deauthorize a user an OAuth 2.0 app. On success
  1946  // it returns status OK or an AppError on fail.
  1947  func (c *Client) OAuthDeauthorizeApp(clientId string) *AppError {
  1948  	if r, err := c.DoApiPost("/oauth/"+clientId+"/deauthorize", ""); err != nil {
  1949  		return err
  1950  	} else {
  1951  		defer closeBody(r)
  1952  		return nil
  1953  	}
  1954  }
  1955  
  1956  // RegenerateOAuthAppSecret generates a new OAuth App Client Secret. On success
  1957  // it returns an OAuth2 App. Must be authenticated as a user and the same user who
  1958  // registered the app or a System Admin.
  1959  func (c *Client) RegenerateOAuthAppSecret(clientId string) (*Result, *AppError) {
  1960  	if r, err := c.DoApiPost("/oauth/"+clientId+"/regen_secret", ""); err != nil {
  1961  		return nil, err
  1962  	} else {
  1963  		defer closeBody(r)
  1964  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1965  			r.Header.Get(HEADER_ETAG_SERVER), OAuthAppFromJson(r.Body)}, nil
  1966  	}
  1967  }
  1968  
  1969  func (c *Client) GetAccessToken(data url.Values) (*Result, *AppError) {
  1970  	if r, err := c.DoPost("/oauth/access_token", data.Encode(), "application/x-www-form-urlencoded"); err != nil {
  1971  		return nil, err
  1972  	} else {
  1973  		defer closeBody(r)
  1974  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1975  			r.Header.Get(HEADER_ETAG_SERVER), AccessResponseFromJson(r.Body)}, nil
  1976  	}
  1977  }
  1978  
  1979  func (c *Client) CreateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppError) {
  1980  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/create", hook.ToJson()); err != nil {
  1981  		return nil, err
  1982  	} else {
  1983  		defer closeBody(r)
  1984  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1985  			r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
  1986  	}
  1987  }
  1988  
  1989  func (c *Client) UpdateIncomingWebhook(hook *IncomingWebhook) (*Result, *AppError) {
  1990  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/update", hook.ToJson()); err != nil {
  1991  		return nil, err
  1992  	} else {
  1993  		defer closeBody(r)
  1994  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  1995  			r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookFromJson(r.Body)}, nil
  1996  	}
  1997  }
  1998  
  1999  func (c *Client) PostToWebhook(id, payload string) (*Result, *AppError) {
  2000  	if r, err := c.DoPost("/hooks/"+id, payload, "application/x-www-form-urlencoded"); err != nil {
  2001  		return nil, err
  2002  	} else {
  2003  		defer closeBody(r)
  2004  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2005  			r.Header.Get(HEADER_ETAG_SERVER), nil}, nil
  2006  	}
  2007  }
  2008  
  2009  func (c *Client) DeleteIncomingWebhook(id string) (*Result, *AppError) {
  2010  	data := make(map[string]string)
  2011  	data["id"] = id
  2012  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/incoming/delete", MapToJson(data)); err != nil {
  2013  		return nil, err
  2014  	} else {
  2015  		defer closeBody(r)
  2016  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2017  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  2018  	}
  2019  }
  2020  
  2021  func (c *Client) ListIncomingWebhooks() (*Result, *AppError) {
  2022  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/incoming/list", "", ""); err != nil {
  2023  		return nil, err
  2024  	} else {
  2025  		defer closeBody(r)
  2026  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2027  			r.Header.Get(HEADER_ETAG_SERVER), IncomingWebhookListFromJson(r.Body)}, nil
  2028  	}
  2029  }
  2030  
  2031  func (c *Client) GetAllPreferences() (*Result, *AppError) {
  2032  	if r, err := c.DoApiGet("/preferences/", "", ""); err != nil {
  2033  		return nil, err
  2034  	} else {
  2035  		defer closeBody(r)
  2036  		preferences, _ := PreferencesFromJson(r.Body)
  2037  		return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
  2038  	}
  2039  }
  2040  
  2041  func (c *Client) SetPreferences(preferences *Preferences) (*Result, *AppError) {
  2042  	if r, err := c.DoApiPost("/preferences/save", preferences.ToJson()); err != nil {
  2043  		return nil, err
  2044  	} else {
  2045  		defer closeBody(r)
  2046  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2047  			r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
  2048  	}
  2049  }
  2050  
  2051  func (c *Client) GetPreference(category string, name string) (*Result, *AppError) {
  2052  	if r, err := c.DoApiGet("/preferences/"+category+"/"+name, "", ""); err != nil {
  2053  		return nil, err
  2054  	} else {
  2055  		defer closeBody(r)
  2056  		return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), PreferenceFromJson(r.Body)}, nil
  2057  	}
  2058  }
  2059  
  2060  func (c *Client) GetPreferenceCategory(category string) (*Result, *AppError) {
  2061  	if r, err := c.DoApiGet("/preferences/"+category, "", ""); err != nil {
  2062  		return nil, err
  2063  	} else {
  2064  		defer closeBody(r)
  2065  		preferences, _ := PreferencesFromJson(r.Body)
  2066  		return &Result{r.Header.Get(HEADER_REQUEST_ID), r.Header.Get(HEADER_ETAG_SERVER), preferences}, nil
  2067  	}
  2068  }
  2069  
  2070  // DeletePreferences deletes a list of preferences owned by the current user. If successful,
  2071  // it will return status=ok. Otherwise, an error will be returned.
  2072  func (c *Client) DeletePreferences(preferences *Preferences) (bool, *AppError) {
  2073  	if r, err := c.DoApiPost("/preferences/delete", preferences.ToJson()); err != nil {
  2074  		return false, err
  2075  	} else {
  2076  		return c.CheckStatusOK(r), nil
  2077  	}
  2078  }
  2079  
  2080  func (c *Client) CreateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
  2081  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/create", hook.ToJson()); err != nil {
  2082  		return nil, err
  2083  	} else {
  2084  		defer closeBody(r)
  2085  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2086  			r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
  2087  	}
  2088  }
  2089  
  2090  func (c *Client) UpdateOutgoingWebhook(hook *OutgoingWebhook) (*Result, *AppError) {
  2091  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/update", hook.ToJson()); err != nil {
  2092  		return nil, err
  2093  	} else {
  2094  		defer closeBody(r)
  2095  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2096  			r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
  2097  	}
  2098  }
  2099  
  2100  func (c *Client) DeleteOutgoingWebhook(id string) (*Result, *AppError) {
  2101  	data := make(map[string]string)
  2102  	data["id"] = id
  2103  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/delete", MapToJson(data)); err != nil {
  2104  		return nil, err
  2105  	} else {
  2106  		defer closeBody(r)
  2107  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2108  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  2109  	}
  2110  }
  2111  
  2112  func (c *Client) ListOutgoingWebhooks() (*Result, *AppError) {
  2113  	if r, err := c.DoApiGet(c.GetTeamRoute()+"/hooks/outgoing/list", "", ""); err != nil {
  2114  		return nil, err
  2115  	} else {
  2116  		defer closeBody(r)
  2117  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2118  			r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookListFromJson(r.Body)}, nil
  2119  	}
  2120  }
  2121  
  2122  func (c *Client) RegenOutgoingWebhookToken(id string) (*Result, *AppError) {
  2123  	data := make(map[string]string)
  2124  	data["id"] = id
  2125  	if r, err := c.DoApiPost(c.GetTeamRoute()+"/hooks/outgoing/regen_token", MapToJson(data)); err != nil {
  2126  		return nil, err
  2127  	} else {
  2128  		defer closeBody(r)
  2129  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2130  			r.Header.Get(HEADER_ETAG_SERVER), OutgoingWebhookFromJson(r.Body)}, nil
  2131  	}
  2132  }
  2133  
  2134  func (c *Client) MockSession(sessionToken string) {
  2135  	c.AuthToken = sessionToken
  2136  	c.AuthType = HEADER_BEARER
  2137  }
  2138  
  2139  func (c *Client) GetClientLicenceConfig(etag string) (*Result, *AppError) {
  2140  	if r, err := c.DoApiGet("/license/client_config", "", etag); err != nil {
  2141  		return nil, err
  2142  	} else {
  2143  		defer closeBody(r)
  2144  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2145  			r.Header.Get(HEADER_ETAG_SERVER), MapFromJson(r.Body)}, nil
  2146  	}
  2147  }
  2148  
  2149  func (c *Client) GetInitialLoad() (*Result, *AppError) {
  2150  	if r, err := c.DoApiGet("/users/initial_load", "", ""); err != nil {
  2151  		return nil, err
  2152  	} else {
  2153  		defer closeBody(r)
  2154  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2155  			r.Header.Get(HEADER_ETAG_SERVER), InitialLoadFromJson(r.Body)}, nil
  2156  	}
  2157  }
  2158  
  2159  // ListEmoji returns a list of all user-created emoji for the server.
  2160  func (c *Client) ListEmoji() ([]*Emoji, *AppError) {
  2161  	if r, err := c.DoApiGet(c.GetEmojiRoute()+"/list", "", ""); err != nil {
  2162  		return nil, err
  2163  	} else {
  2164  		defer closeBody(r)
  2165  		c.fillInExtraProperties(r)
  2166  		return EmojiListFromJson(r.Body), nil
  2167  	}
  2168  }
  2169  
  2170  // CreateEmoji will save an emoji to the server if the current user has permission
  2171  // to do so. If successful, the provided emoji will be returned with its Id field
  2172  // filled in. Otherwise, an error will be returned.
  2173  func (c *Client) CreateEmoji(emoji *Emoji, image []byte, filename string) (*Emoji, *AppError) {
  2174  	c.clearExtraProperties()
  2175  
  2176  	body := &bytes.Buffer{}
  2177  	writer := multipart.NewWriter(body)
  2178  
  2179  	if part, err := writer.CreateFormFile("image", filename); err != nil {
  2180  		return nil, NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)
  2181  	} else if _, err = io.Copy(part, bytes.NewBuffer(image)); err != nil {
  2182  		return nil, NewAppError("CreateEmoji", "model.client.create_emoji.image.app_error", nil, err.Error(), 0)
  2183  	}
  2184  
  2185  	if err := writer.WriteField("emoji", emoji.ToJson()); err != nil {
  2186  		return nil, NewAppError("CreateEmoji", "model.client.create_emoji.emoji.app_error", nil, err.Error(), 0)
  2187  	}
  2188  
  2189  	if err := writer.Close(); err != nil {
  2190  		return nil, NewAppError("CreateEmoji", "model.client.create_emoji.writer.app_error", nil, err.Error(), 0)
  2191  	}
  2192  
  2193  	rq, _ := http.NewRequest("POST", c.ApiUrl+c.GetEmojiRoute()+"/create", body)
  2194  	rq.Header.Set("Content-Type", writer.FormDataContentType())
  2195  	rq.Close = true
  2196  
  2197  	if len(c.AuthToken) > 0 {
  2198  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  2199  	}
  2200  
  2201  	if r, err := c.HttpClient.Do(rq); err != nil {
  2202  		return nil, NewAppError("CreateEmoji", "model.client.connecting.app_error", nil, err.Error(), 0)
  2203  	} else if r.StatusCode >= 300 {
  2204  		return nil, AppErrorFromJson(r.Body)
  2205  	} else {
  2206  		defer closeBody(r)
  2207  		c.fillInExtraProperties(r)
  2208  		return EmojiFromJson(r.Body), nil
  2209  	}
  2210  }
  2211  
  2212  // DeleteEmoji will delete an emoji from the server if the current user has permission
  2213  // to do so. If successful, it will return status=ok. Otherwise, an error will be returned.
  2214  func (c *Client) DeleteEmoji(id string) (bool, *AppError) {
  2215  	data := map[string]string{"id": id}
  2216  
  2217  	if r, err := c.DoApiPost(c.GetEmojiRoute()+"/delete", MapToJson(data)); err != nil {
  2218  		return false, err
  2219  	} else {
  2220  		defer closeBody(r)
  2221  		c.fillInExtraProperties(r)
  2222  		return c.CheckStatusOK(r), nil
  2223  	}
  2224  }
  2225  
  2226  // GetCustomEmojiImageUrl returns the API route that can be used to get the image used by
  2227  // the given emoji.
  2228  func (c *Client) GetCustomEmojiImageUrl(id string) string {
  2229  	return c.GetEmojiRoute() + "/" + id
  2230  }
  2231  
  2232  // Uploads a x509 base64 Certificate or Private Key file to be used with SAML.
  2233  // data byte array is required and needs to be a Multi-Part with 'certificate' as the field name
  2234  // contentType is also required. Returns nil if succesful, otherwise returns an AppError
  2235  func (c *Client) UploadCertificateFile(data []byte, contentType string) *AppError {
  2236  	url := c.ApiUrl + "/admin/add_certificate"
  2237  	rq, _ := http.NewRequest("POST", url, bytes.NewReader(data))
  2238  	rq.Header.Set("Content-Type", contentType)
  2239  	rq.Close = true
  2240  
  2241  	if len(c.AuthToken) > 0 {
  2242  		rq.Header.Set(HEADER_AUTH, "BEARER "+c.AuthToken)
  2243  	}
  2244  
  2245  	if rp, err := c.HttpClient.Do(rq); err != nil {
  2246  		return NewAppError(url, "model.client.connecting.app_error", nil, err.Error(), 0)
  2247  	} else if rp.StatusCode >= 300 {
  2248  		return AppErrorFromJson(rp.Body)
  2249  	} else {
  2250  		defer closeBody(rp)
  2251  		c.fillInExtraProperties(rp)
  2252  		return nil
  2253  	}
  2254  }
  2255  
  2256  // Removes a x509 base64 Certificate or Private Key file used with SAML.
  2257  // filename is required. Returns nil if successful, otherwise returns an AppError
  2258  func (c *Client) RemoveCertificateFile(filename string) *AppError {
  2259  	if r, err := c.DoApiPost("/admin/remove_certificate", MapToJson(map[string]string{"filename": filename})); err != nil {
  2260  		return err
  2261  	} else {
  2262  		defer closeBody(r)
  2263  		c.fillInExtraProperties(r)
  2264  		return nil
  2265  	}
  2266  }
  2267  
  2268  // Checks if the x509 base64 Certificates and Private Key files used with SAML exists on the file system.
  2269  // Returns a map[string]interface{} if successful, otherwise returns an AppError. Must be System Admin authenticated.
  2270  func (c *Client) SamlCertificateStatus(filename string) (map[string]interface{}, *AppError) {
  2271  	if r, err := c.DoApiGet("/admin/remove_certificate", "", ""); err != nil {
  2272  		return nil, err
  2273  	} else {
  2274  		defer closeBody(r)
  2275  		c.fillInExtraProperties(r)
  2276  		return StringInterfaceFromJson(r.Body), nil
  2277  	}
  2278  }
  2279  
  2280  // GetWebrtcToken if Successful returns a map with a valid token, stun server and turn server with credentials to use with
  2281  // the Mattermost WebRTC service, otherwise returns an AppError. Must be authenticated user.
  2282  func (c *Client) GetWebrtcToken() (map[string]string, *AppError) {
  2283  	if r, err := c.DoApiPost("/webrtc/token", ""); err != nil {
  2284  		return nil, err
  2285  	} else {
  2286  		defer closeBody(r)
  2287  		return MapFromJson(r.Body), nil
  2288  	}
  2289  }
  2290  
  2291  // GetFileInfosForPost returns a list of FileInfo objects for a given post id, if successful.
  2292  // Otherwise, it returns an error.
  2293  func (c *Client) GetFileInfosForPost(channelId string, postId string, etag string) ([]*FileInfo, *AppError) {
  2294  	c.clearExtraProperties()
  2295  
  2296  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/get_file_infos", postId), "", etag); err != nil {
  2297  		return nil, err
  2298  	} else {
  2299  		defer closeBody(r)
  2300  		c.fillInExtraProperties(r)
  2301  		return FileInfosFromJson(r.Body), nil
  2302  	}
  2303  }
  2304  
  2305  // Saves an emoji reaction for a post in the given channel. Returns the saved reaction if successful, otherwise returns an AppError.
  2306  func (c *Client) SaveReaction(channelId string, reaction *Reaction) (*Reaction, *AppError) {
  2307  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/reactions/save", reaction.PostId), reaction.ToJson()); err != nil {
  2308  		return nil, err
  2309  	} else {
  2310  		defer closeBody(r)
  2311  		c.fillInExtraProperties(r)
  2312  		return ReactionFromJson(r.Body), nil
  2313  	}
  2314  }
  2315  
  2316  // Removes an emoji reaction for a post in the given channel. Returns nil if successful, otherwise returns an AppError.
  2317  func (c *Client) DeleteReaction(channelId string, reaction *Reaction) *AppError {
  2318  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/reactions/delete", reaction.PostId), reaction.ToJson()); err != nil {
  2319  		return err
  2320  	} else {
  2321  		defer closeBody(r)
  2322  		c.fillInExtraProperties(r)
  2323  		return nil
  2324  	}
  2325  }
  2326  
  2327  // Lists all emoji reactions made for the given post in the given channel. Returns a list of Reactions if successful, otherwise returns an AppError.
  2328  func (c *Client) ListReactions(channelId string, postId string) ([]*Reaction, *AppError) {
  2329  	if r, err := c.DoApiGet(c.GetChannelRoute(channelId)+fmt.Sprintf("/posts/%v/reactions", postId), "", ""); err != nil {
  2330  		return nil, err
  2331  	} else {
  2332  		defer closeBody(r)
  2333  		c.fillInExtraProperties(r)
  2334  		return ReactionsFromJson(r.Body), nil
  2335  	}
  2336  }
  2337  
  2338  // Updates the user's roles in the channel by replacing them with the roles provided.
  2339  func (c *Client) UpdateChannelRoles(channelId string, userId string, roles string) (map[string]string, *ResponseMetadata) {
  2340  	data := make(map[string]string)
  2341  	data["new_roles"] = roles
  2342  	data["user_id"] = userId
  2343  
  2344  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/update_member_roles", MapToJson(data)); err != nil {
  2345  		metadata := ResponseMetadata{Error: err}
  2346  		if r != nil {
  2347  			metadata.StatusCode = r.StatusCode
  2348  		}
  2349  		return nil, &metadata
  2350  	} else {
  2351  		defer closeBody(r)
  2352  		return MapFromJson(r.Body),
  2353  			&ResponseMetadata{
  2354  				StatusCode: r.StatusCode,
  2355  				RequestId:  r.Header.Get(HEADER_REQUEST_ID),
  2356  				Etag:       r.Header.Get(HEADER_ETAG_SERVER),
  2357  			}
  2358  	}
  2359  }
  2360  
  2361  func (c *Client) PinPost(channelId string, postId string) (*Result, *AppError) {
  2362  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/pin", ""); err != nil {
  2363  		return nil, err
  2364  	} else {
  2365  		defer closeBody(r)
  2366  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2367  			r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
  2368  	}
  2369  }
  2370  
  2371  func (c *Client) UnpinPost(channelId string, postId string) (*Result, *AppError) {
  2372  	if r, err := c.DoApiPost(c.GetChannelRoute(channelId)+"/posts/"+postId+"/unpin", ""); err != nil {
  2373  		return nil, err
  2374  	} else {
  2375  		defer closeBody(r)
  2376  		return &Result{r.Header.Get(HEADER_REQUEST_ID),
  2377  			r.Header.Get(HEADER_ETAG_SERVER), PostFromJson(r.Body)}, nil
  2378  	}
  2379  }