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