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