2016-09-05 07:34:37 -07:00
|
|
|
package slack
|
|
|
|
|
|
|
|
import (
|
2017-07-16 05:29:46 -07:00
|
|
|
"context"
|
|
|
|
"encoding/json"
|
2016-09-05 07:34:37 -07:00
|
|
|
"errors"
|
|
|
|
"net/url"
|
|
|
|
)
|
|
|
|
|
2017-07-16 05:29:46 -07:00
|
|
|
const (
|
|
|
|
DEFAULT_USER_PHOTO_CROP_X = -1
|
|
|
|
DEFAULT_USER_PHOTO_CROP_Y = -1
|
|
|
|
DEFAULT_USER_PHOTO_CROP_W = -1
|
|
|
|
)
|
|
|
|
|
2016-09-05 07:34:37 -07:00
|
|
|
// UserProfile contains all the information details of a given user
|
|
|
|
type UserProfile struct {
|
|
|
|
FirstName string `json:"first_name"`
|
|
|
|
LastName string `json:"last_name"`
|
|
|
|
RealName string `json:"real_name"`
|
|
|
|
RealNameNormalized string `json:"real_name_normalized"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
Skype string `json:"skype"`
|
|
|
|
Phone string `json:"phone"`
|
|
|
|
Image24 string `json:"image_24"`
|
|
|
|
Image32 string `json:"image_32"`
|
|
|
|
Image48 string `json:"image_48"`
|
|
|
|
Image72 string `json:"image_72"`
|
|
|
|
Image192 string `json:"image_192"`
|
|
|
|
ImageOriginal string `json:"image_original"`
|
|
|
|
Title string `json:"title"`
|
2016-11-05 16:07:24 -07:00
|
|
|
BotID string `json:"bot_id,omitempty"`
|
|
|
|
ApiAppID string `json:"api_app_id,omitempty"`
|
2017-07-16 05:29:46 -07:00
|
|
|
StatusText string `json:"status_text,omitempty"`
|
|
|
|
StatusEmoji string `json:"status_emoji,omitempty"`
|
2016-09-05 07:34:37 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// User contains all the information of a user
|
|
|
|
type User struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Deleted bool `json:"deleted"`
|
|
|
|
Color string `json:"color"`
|
|
|
|
RealName string `json:"real_name"`
|
|
|
|
TZ string `json:"tz,omitempty"`
|
|
|
|
TZLabel string `json:"tz_label"`
|
|
|
|
TZOffset int `json:"tz_offset"`
|
|
|
|
Profile UserProfile `json:"profile"`
|
|
|
|
IsBot bool `json:"is_bot"`
|
|
|
|
IsAdmin bool `json:"is_admin"`
|
|
|
|
IsOwner bool `json:"is_owner"`
|
|
|
|
IsPrimaryOwner bool `json:"is_primary_owner"`
|
|
|
|
IsRestricted bool `json:"is_restricted"`
|
|
|
|
IsUltraRestricted bool `json:"is_ultra_restricted"`
|
|
|
|
Has2FA bool `json:"has_2fa"`
|
|
|
|
HasFiles bool `json:"has_files"`
|
|
|
|
Presence string `json:"presence"`
|
|
|
|
}
|
|
|
|
|
|
|
|
// UserPresence contains details about a user online status
|
|
|
|
type UserPresence struct {
|
|
|
|
Presence string `json:"presence,omitempty"`
|
|
|
|
Online bool `json:"online,omitempty"`
|
|
|
|
AutoAway bool `json:"auto_away,omitempty"`
|
|
|
|
ManualAway bool `json:"manual_away,omitempty"`
|
|
|
|
ConnectionCount int `json:"connection_count,omitempty"`
|
|
|
|
LastActivity JSONTime `json:"last_activity,omitempty"`
|
|
|
|
}
|
|
|
|
|
2016-11-05 16:07:24 -07:00
|
|
|
type UserIdentityResponse struct {
|
|
|
|
User UserIdentity `json:"user"`
|
|
|
|
Team TeamIdentity `json:"team"`
|
|
|
|
SlackResponse
|
|
|
|
}
|
|
|
|
|
|
|
|
type UserIdentity struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Email string `json:"email"`
|
|
|
|
Image24 string `json:"image_24"`
|
|
|
|
Image32 string `json:"image_32"`
|
|
|
|
Image48 string `json:"image_48"`
|
|
|
|
Image72 string `json:"image_72"`
|
|
|
|
Image192 string `json:"image_192"`
|
|
|
|
Image512 string `json:"image_512"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type TeamIdentity struct {
|
|
|
|
ID string `json:"id"`
|
|
|
|
Name string `json:"name"`
|
|
|
|
Domain string `json:"domain"`
|
|
|
|
Image34 string `json:"image_34"`
|
|
|
|
Image44 string `json:"image_44"`
|
|
|
|
Image68 string `json:"image_68"`
|
|
|
|
Image88 string `json:"image_88"`
|
|
|
|
Image102 string `json:"image_102"`
|
|
|
|
Image132 string `json:"image_132"`
|
|
|
|
Image230 string `json:"image_230"`
|
|
|
|
ImageDefault bool `json:"image_default"`
|
|
|
|
ImageOriginal string `json:"image_original"`
|
|
|
|
}
|
|
|
|
|
2016-09-05 07:34:37 -07:00
|
|
|
type userResponseFull struct {
|
|
|
|
Members []User `json:"members,omitempty"` // ListUsers
|
|
|
|
User `json:"user,omitempty"` // GetUserInfo
|
|
|
|
UserPresence // GetUserPresence
|
|
|
|
SlackResponse
|
|
|
|
}
|
|
|
|
|
2017-07-16 05:29:46 -07:00
|
|
|
type UserSetPhotoParams struct {
|
|
|
|
CropX int
|
|
|
|
CropY int
|
|
|
|
CropW int
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewUserSetPhotoParams() UserSetPhotoParams {
|
|
|
|
return UserSetPhotoParams{
|
|
|
|
CropX: DEFAULT_USER_PHOTO_CROP_X,
|
|
|
|
CropY: DEFAULT_USER_PHOTO_CROP_Y,
|
|
|
|
CropW: DEFAULT_USER_PHOTO_CROP_W,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func userRequest(ctx context.Context, path string, values url.Values, debug bool) (*userResponseFull, error) {
|
2016-09-05 07:34:37 -07:00
|
|
|
response := &userResponseFull{}
|
2017-07-16 05:29:46 -07:00
|
|
|
err := post(ctx, path, values, response, debug)
|
2016-09-05 07:34:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !response.Ok {
|
|
|
|
return nil, errors.New(response.Error)
|
|
|
|
}
|
|
|
|
return response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUserPresence will retrieve the current presence status of given user.
|
|
|
|
func (api *Client) GetUserPresence(user string) (*UserPresence, error) {
|
2017-07-16 05:29:46 -07:00
|
|
|
return api.GetUserPresenceContext(context.Background(), user)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUserPresenceContext will retrieve the current presence status of given user with a custom context.
|
|
|
|
func (api *Client) GetUserPresenceContext(ctx context.Context, user string) (*UserPresence, error) {
|
2016-09-05 07:34:37 -07:00
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
"user": {user},
|
|
|
|
}
|
2017-07-16 05:29:46 -07:00
|
|
|
response, err := userRequest(ctx, "users.getPresence", values, api.debug)
|
2016-09-05 07:34:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &response.UserPresence, nil
|
|
|
|
}
|
|
|
|
|
2017-01-27 15:36:22 -08:00
|
|
|
// GetUserInfo will retrieve the complete user information
|
2016-09-05 07:34:37 -07:00
|
|
|
func (api *Client) GetUserInfo(user string) (*User, error) {
|
2017-07-16 05:29:46 -07:00
|
|
|
return api.GetUserInfoContext(context.Background(), user)
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUserInfoContext will retrieve the complete user information with a custom context
|
|
|
|
func (api *Client) GetUserInfoContext(ctx context.Context, user string) (*User, error) {
|
2016-09-05 07:34:37 -07:00
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
"user": {user},
|
|
|
|
}
|
2017-07-16 05:29:46 -07:00
|
|
|
response, err := userRequest(ctx, "users.info", values, api.debug)
|
2016-09-05 07:34:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &response.User, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUsers returns the list of users (with their detailed information)
|
|
|
|
func (api *Client) GetUsers() ([]User, error) {
|
2017-07-16 05:29:46 -07:00
|
|
|
return api.GetUsersContext(context.Background())
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUsersContext returns the list of users (with their detailed information) with a custom context
|
|
|
|
func (api *Client) GetUsersContext(ctx context.Context) ([]User, error) {
|
2016-09-05 07:34:37 -07:00
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
"presence": {"1"},
|
|
|
|
}
|
2017-07-16 05:29:46 -07:00
|
|
|
response, err := userRequest(ctx, "users.list", values, api.debug)
|
2016-09-05 07:34:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return response.Members, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserAsActive marks the currently authenticated user as active
|
|
|
|
func (api *Client) SetUserAsActive() error {
|
2017-07-16 05:29:46 -07:00
|
|
|
return api.SetUserAsActiveContext(context.Background())
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserAsActiveContext marks the currently authenticated user as active with a custom context
|
|
|
|
func (api *Client) SetUserAsActiveContext(ctx context.Context) error {
|
2016-09-05 07:34:37 -07:00
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
}
|
2017-07-16 05:29:46 -07:00
|
|
|
_, err := userRequest(ctx, "users.setActive", values, api.debug)
|
2016-09-05 07:34:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserPresence changes the currently authenticated user presence
|
|
|
|
func (api *Client) SetUserPresence(presence string) error {
|
2017-07-16 05:29:46 -07:00
|
|
|
return api.SetUserPresenceContext(context.Background(), presence)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserPresenceContext changes the currently authenticated user presence with a custom context
|
|
|
|
func (api *Client) SetUserPresenceContext(ctx context.Context, presence string) error {
|
2016-09-05 07:34:37 -07:00
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
"presence": {presence},
|
|
|
|
}
|
2017-07-16 05:29:46 -07:00
|
|
|
_, err := userRequest(ctx, "users.setPresence", values, api.debug)
|
2016-09-05 07:34:37 -07:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
|
|
|
|
}
|
2016-11-05 16:07:24 -07:00
|
|
|
|
|
|
|
// GetUserIdentity will retrieve user info available per identity scopes
|
|
|
|
func (api *Client) GetUserIdentity() (*UserIdentityResponse, error) {
|
2017-07-16 05:29:46 -07:00
|
|
|
return api.GetUserIdentityContext(context.Background())
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetUserIdentityContext will retrieve user info available per identity scopes with a custom context
|
|
|
|
func (api *Client) GetUserIdentityContext(ctx context.Context) (*UserIdentityResponse, error) {
|
2016-11-05 16:07:24 -07:00
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
}
|
|
|
|
response := &UserIdentityResponse{}
|
2017-07-16 05:29:46 -07:00
|
|
|
err := post(ctx, "users.identity", values, response, api.debug)
|
2016-11-05 16:07:24 -07:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if !response.Ok {
|
|
|
|
return nil, errors.New(response.Error)
|
|
|
|
}
|
|
|
|
return response, nil
|
|
|
|
}
|
2017-07-16 05:29:46 -07:00
|
|
|
|
|
|
|
// SetUserPhoto changes the currently authenticated user's profile image
|
|
|
|
func (api *Client) SetUserPhoto(ctx context.Context, image string, params UserSetPhotoParams) error {
|
|
|
|
return api.SetUserPhoto(context.Background(), image, params)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserPhotoContext changes the currently authenticated user's profile image using a custom context
|
|
|
|
func (api *Client) SetUserPhotoContext(ctx context.Context, image string, params UserSetPhotoParams) error {
|
|
|
|
response := &SlackResponse{}
|
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
}
|
|
|
|
if params.CropX != DEFAULT_USER_PHOTO_CROP_X {
|
|
|
|
values.Add("crop_x", string(params.CropX))
|
|
|
|
}
|
|
|
|
if params.CropY != DEFAULT_USER_PHOTO_CROP_Y {
|
|
|
|
values.Add("crop_y", string(params.CropY))
|
|
|
|
}
|
|
|
|
if params.CropW != DEFAULT_USER_PHOTO_CROP_W {
|
|
|
|
values.Add("crop_w", string(params.CropW))
|
|
|
|
}
|
|
|
|
err := postLocalWithMultipartResponse(ctx, "users.setPhoto", image, "image", values, response, api.debug)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !response.Ok {
|
|
|
|
return errors.New(response.Error)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteUserPhoto deletes the current authenticated user's profile image
|
|
|
|
func (api *Client) DeleteUserPhoto() error {
|
|
|
|
return api.DeleteUserPhotoContext(context.Background())
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteUserPhotoContext deletes the current authenticated user's profile image with a custom context
|
|
|
|
func (api *Client) DeleteUserPhotoContext(ctx context.Context) error {
|
|
|
|
response := &SlackResponse{}
|
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
}
|
|
|
|
err := post(ctx, "users.deletePhoto", values, response, api.debug)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
if !response.Ok {
|
|
|
|
return errors.New(response.Error)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserCustomStatus will set a custom status and emoji for the currently
|
|
|
|
// authenticated user. If statusEmoji is "" and statusText is not, the Slack API
|
|
|
|
// will automatically set it to ":speech_balloon:". Otherwise, if both are ""
|
|
|
|
// the Slack API will unset the custom status/emoji.
|
|
|
|
func (api *Client) SetUserCustomStatus(statusText, statusEmoji string) error {
|
|
|
|
return api.SetUserCustomStatusContext(context.Background(), statusText, statusEmoji)
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetUserCustomStatusContext will set a custom status and emoji for the currently authenticated user with a custom context
|
|
|
|
//
|
|
|
|
// For more information see SetUserCustomStatus
|
|
|
|
func (api *Client) SetUserCustomStatusContext(ctx context.Context, statusText, statusEmoji string) error {
|
|
|
|
// XXX(theckman): this anonymous struct is for making requests to the Slack
|
|
|
|
// API for setting and unsetting a User's Custom Status/Emoji. To change
|
|
|
|
// these values we must provide a JSON document as the profile POST field.
|
|
|
|
//
|
|
|
|
// We use an anonymous struct over UserProfile because to unset the values
|
|
|
|
// on the User's profile we cannot use the `json:"omitempty"` tag. This is
|
|
|
|
// because an empty string ("") is what's used to unset the values. Check
|
|
|
|
// out the API docs for more details:
|
|
|
|
//
|
|
|
|
// - https://api.slack.com/docs/presence-and-status#custom_status
|
|
|
|
profile, err := json.Marshal(
|
|
|
|
&struct {
|
|
|
|
StatusText string `json:"status_text"`
|
|
|
|
StatusEmoji string `json:"status_emoji"`
|
|
|
|
}{
|
|
|
|
StatusText: statusText,
|
|
|
|
StatusEmoji: statusEmoji,
|
|
|
|
},
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
values := url.Values{
|
|
|
|
"token": {api.config.token},
|
|
|
|
"profile": {string(profile)},
|
|
|
|
}
|
|
|
|
|
|
|
|
response := &userResponseFull{}
|
|
|
|
|
|
|
|
if err = post(ctx, "users.profile.set", values, response, api.debug); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
if !response.Ok {
|
|
|
|
return errors.New(response.Error)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnsetUserCustomStatus removes the custom status message for the currently
|
|
|
|
// authenticated user. This is a convenience method that wraps (*Client).SetUserCustomStatus().
|
|
|
|
func (api *Client) UnsetUserCustomStatus() error {
|
|
|
|
return api.UnsetUserCustomStatusContext(context.Background())
|
|
|
|
}
|
|
|
|
|
|
|
|
// UnsetUserCustomStatusContext removes the custom status message for the currently authenticated user
|
|
|
|
// with a custom context. This is a convenience method that wraps (*Client).SetUserCustomStatus().
|
|
|
|
func (api *Client) UnsetUserCustomStatusContext(ctx context.Context) error {
|
|
|
|
return api.SetUserCustomStatusContext(ctx, "", "")
|
|
|
|
}
|