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