diff options
Diffstat (limited to 'teleirc/matterbridge/vendor/github.com/slack-go/slack/files.go')
| -rw-r--r-- | teleirc/matterbridge/vendor/github.com/slack-go/slack/files.go | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/teleirc/matterbridge/vendor/github.com/slack-go/slack/files.go b/teleirc/matterbridge/vendor/github.com/slack-go/slack/files.go new file mode 100644 index 0000000..3562844 --- /dev/null +++ b/teleirc/matterbridge/vendor/github.com/slack-go/slack/files.go @@ -0,0 +1,597 @@ +package slack + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/url" + "strconv" + "strings" +) + +const ( + // Add here the defaults in the siten + DEFAULT_FILES_USER = "" + DEFAULT_FILES_CHANNEL = "" + DEFAULT_FILES_TS_FROM = 0 + DEFAULT_FILES_TS_TO = -1 + DEFAULT_FILES_TYPES = "all" + DEFAULT_FILES_COUNT = 100 + DEFAULT_FILES_PAGE = 1 + DEFAULT_FILES_SHOW_HIDDEN = false +) + +// File contains all the information for a file +type File struct { + ID string `json:"id"` + Created JSONTime `json:"created"` + Timestamp JSONTime `json:"timestamp"` + + Name string `json:"name"` + Title string `json:"title"` + Mimetype string `json:"mimetype"` + ImageExifRotation int `json:"image_exif_rotation"` + Filetype string `json:"filetype"` + PrettyType string `json:"pretty_type"` + User string `json:"user"` + + Mode string `json:"mode"` + Editable bool `json:"editable"` + IsExternal bool `json:"is_external"` + ExternalType string `json:"external_type"` + + Size int `json:"size"` + + URL string `json:"url"` // Deprecated - never set + URLDownload string `json:"url_download"` // Deprecated - never set + URLPrivate string `json:"url_private"` + URLPrivateDownload string `json:"url_private_download"` + + OriginalH int `json:"original_h"` + OriginalW int `json:"original_w"` + Thumb64 string `json:"thumb_64"` + Thumb80 string `json:"thumb_80"` + Thumb160 string `json:"thumb_160"` + Thumb360 string `json:"thumb_360"` + Thumb360Gif string `json:"thumb_360_gif"` + Thumb360W int `json:"thumb_360_w"` + Thumb360H int `json:"thumb_360_h"` + Thumb480 string `json:"thumb_480"` + Thumb480W int `json:"thumb_480_w"` + Thumb480H int `json:"thumb_480_h"` + Thumb720 string `json:"thumb_720"` + Thumb720W int `json:"thumb_720_w"` + Thumb720H int `json:"thumb_720_h"` + Thumb960 string `json:"thumb_960"` + Thumb960W int `json:"thumb_960_w"` + Thumb960H int `json:"thumb_960_h"` + Thumb1024 string `json:"thumb_1024"` + Thumb1024W int `json:"thumb_1024_w"` + Thumb1024H int `json:"thumb_1024_h"` + + Permalink string `json:"permalink"` + PermalinkPublic string `json:"permalink_public"` + + EditLink string `json:"edit_link"` + Preview string `json:"preview"` + PreviewHighlight string `json:"preview_highlight"` + Lines int `json:"lines"` + LinesMore int `json:"lines_more"` + + IsPublic bool `json:"is_public"` + PublicURLShared bool `json:"public_url_shared"` + Channels []string `json:"channels"` + Groups []string `json:"groups"` + IMs []string `json:"ims"` + InitialComment Comment `json:"initial_comment"` + CommentsCount int `json:"comments_count"` + NumStars int `json:"num_stars"` + IsStarred bool `json:"is_starred"` + Shares Share `json:"shares"` +} + +type Share struct { + Public map[string][]ShareFileInfo `json:"public"` + Private map[string][]ShareFileInfo `json:"private"` +} + +type ShareFileInfo struct { + ReplyUsers []string `json:"reply_users"` + ReplyUsersCount int `json:"reply_users_count"` + ReplyCount int `json:"reply_count"` + Ts string `json:"ts"` + ThreadTs string `json:"thread_ts"` + LatestReply string `json:"latest_reply"` + ChannelName string `json:"channel_name"` + TeamID string `json:"team_id"` +} + +// FileUploadParameters contains all the parameters necessary (including the optional ones) for an UploadFile() request. +// +// There are three ways to upload a file. You can either set Content if file is small, set Reader if file is large, +// or provide a local file path in File to upload it from your filesystem. +// +// Note that when using the Reader option, you *must* specify the Filename, otherwise the Slack API isn't happy. +type FileUploadParameters struct { + File string + Content string + Reader io.Reader + Filetype string + Filename string + Title string + InitialComment string + Channels []string + ThreadTimestamp string +} + +// GetFilesParameters contains all the parameters necessary (including the optional ones) for a GetFiles() request +type GetFilesParameters struct { + User string + Channel string + TimestampFrom JSONTime + TimestampTo JSONTime + Types string + Count int + Page int + ShowHidden bool +} + +// ListFilesParameters contains all the parameters necessary (including the optional ones) for a ListFiles() request +type ListFilesParameters struct { + Limit int + User string + Channel string + Types string + Cursor string +} + +type UploadFileV2Parameters struct { + File string + FileSize int + Content string + Reader io.Reader + Filename string + Title string + InitialComment string + Channel string + ThreadTimestamp string + AltTxt string + SnippetText string +} + +type getUploadURLExternalParameters struct { + altText string + fileSize int + fileName string + snippetText string +} + +type getUploadURLExternalResponse struct { + UploadURL string `json:"upload_url"` + FileID string `json:"file_id"` + SlackResponse +} + +type uploadToURLParameters struct { + UploadURL string + Reader io.Reader + File string + Content string + Filename string +} + +type FileSummary struct { + ID string `json:"id"` + Title string `json:"title"` +} + +type completeUploadExternalParameters struct { + title string + channel string + initialComment string + threadTimestamp string +} + +type completeUploadExternalResponse struct { + SlackResponse + Files []FileSummary `json:"files"` +} + +type fileResponseFull struct { + File `json:"file"` + Paging `json:"paging"` + Comments []Comment `json:"comments"` + Files []File `json:"files"` + Metadata ResponseMetadata `json:"response_metadata"` + + SlackResponse +} + +// NewGetFilesParameters provides an instance of GetFilesParameters with all the sane default values set +func NewGetFilesParameters() GetFilesParameters { + return GetFilesParameters{ + User: DEFAULT_FILES_USER, + Channel: DEFAULT_FILES_CHANNEL, + TimestampFrom: DEFAULT_FILES_TS_FROM, + TimestampTo: DEFAULT_FILES_TS_TO, + Types: DEFAULT_FILES_TYPES, + Count: DEFAULT_FILES_COUNT, + Page: DEFAULT_FILES_PAGE, + ShowHidden: DEFAULT_FILES_SHOW_HIDDEN, + } +} + +func (api *Client) fileRequest(ctx context.Context, path string, values url.Values) (*fileResponseFull, error) { + response := &fileResponseFull{} + err := api.postMethod(ctx, path, values, response) + if err != nil { + return nil, err + } + + return response, response.Err() +} + +// GetFileInfo retrieves a file and related comments +func (api *Client) GetFileInfo(fileID string, count, page int) (*File, []Comment, *Paging, error) { + return api.GetFileInfoContext(context.Background(), fileID, count, page) +} + +// GetFileInfoContext retrieves a file and related comments with a custom context +func (api *Client) GetFileInfoContext(ctx context.Context, fileID string, count, page int) (*File, []Comment, *Paging, error) { + values := url.Values{ + "token": {api.token}, + "file": {fileID}, + "count": {strconv.Itoa(count)}, + "page": {strconv.Itoa(page)}, + } + + response, err := api.fileRequest(ctx, "files.info", values) + if err != nil { + return nil, nil, nil, err + } + return &response.File, response.Comments, &response.Paging, nil +} + +// GetFile retreives a given file from its private download URL +func (api *Client) GetFile(downloadURL string, writer io.Writer) error { + return api.GetFileContext(context.Background(), downloadURL, writer) +} + +// GetFileContext retreives a given file from its private download URL with a custom context +// +// For more details, see GetFile documentation. +func (api *Client) GetFileContext(ctx context.Context, downloadURL string, writer io.Writer) error { + return downloadFile(ctx, api.httpclient, api.token, downloadURL, writer, api) +} + +// GetFiles retrieves all files according to the parameters given +func (api *Client) GetFiles(params GetFilesParameters) ([]File, *Paging, error) { + return api.GetFilesContext(context.Background(), params) +} + +// GetFilesContext retrieves all files according to the parameters given with a custom context +func (api *Client) GetFilesContext(ctx context.Context, params GetFilesParameters) ([]File, *Paging, error) { + values := url.Values{ + "token": {api.token}, + } + if params.User != DEFAULT_FILES_USER { + values.Add("user", params.User) + } + if params.Channel != DEFAULT_FILES_CHANNEL { + values.Add("channel", params.Channel) + } + if params.TimestampFrom != DEFAULT_FILES_TS_FROM { + values.Add("ts_from", strconv.FormatInt(int64(params.TimestampFrom), 10)) + } + if params.TimestampTo != DEFAULT_FILES_TS_TO { + values.Add("ts_to", strconv.FormatInt(int64(params.TimestampTo), 10)) + } + if params.Types != DEFAULT_FILES_TYPES { + values.Add("types", params.Types) + } + if params.Count != DEFAULT_FILES_COUNT { + values.Add("count", strconv.Itoa(params.Count)) + } + if params.Page != DEFAULT_FILES_PAGE { + values.Add("page", strconv.Itoa(params.Page)) + } + if params.ShowHidden != DEFAULT_FILES_SHOW_HIDDEN { + values.Add("show_files_hidden_by_limit", strconv.FormatBool(params.ShowHidden)) + } + + response, err := api.fileRequest(ctx, "files.list", values) + if err != nil { + return nil, nil, err + } + return response.Files, &response.Paging, nil +} + +// ListFiles retrieves all files according to the parameters given. Uses cursor based pagination. +func (api *Client) ListFiles(params ListFilesParameters) ([]File, *ListFilesParameters, error) { + return api.ListFilesContext(context.Background(), params) +} + +// ListFilesContext retrieves all files according to the parameters given with a custom context. +// +// For more details, see ListFiles documentation. +func (api *Client) ListFilesContext(ctx context.Context, params ListFilesParameters) ([]File, *ListFilesParameters, error) { + values := url.Values{ + "token": {api.token}, + } + + if params.User != DEFAULT_FILES_USER { + values.Add("user", params.User) + } + if params.Channel != DEFAULT_FILES_CHANNEL { + values.Add("channel", params.Channel) + } + if params.Limit != DEFAULT_FILES_COUNT { + values.Add("limit", strconv.Itoa(params.Limit)) + } + if params.Cursor != "" { + values.Add("cursor", params.Cursor) + } + + response, err := api.fileRequest(ctx, "files.list", values) + if err != nil { + return nil, nil, err + } + + params.Cursor = response.Metadata.Cursor + + return response.Files, ¶ms, nil +} + +// UploadFile uploads a file +func (api *Client) UploadFile(params FileUploadParameters) (file *File, err error) { + return api.UploadFileContext(context.Background(), params) +} + +// UploadFileContext uploads a file and setting a custom context +func (api *Client) UploadFileContext(ctx context.Context, params FileUploadParameters) (file *File, err error) { + // Test if user token is valid. This helps because client.Do doesn't like this for some reason. XXX: More + // investigation needed, but for now this will do. + _, err = api.AuthTestContext(ctx) + if err != nil { + return nil, err + } + response := &fileResponseFull{} + values := url.Values{} + if params.Filetype != "" { + values.Add("filetype", params.Filetype) + } + if params.Filename != "" { + values.Add("filename", params.Filename) + } + if params.Title != "" { + values.Add("title", params.Title) + } + if params.InitialComment != "" { + values.Add("initial_comment", params.InitialComment) + } + if params.ThreadTimestamp != "" { + values.Add("thread_ts", params.ThreadTimestamp) + } + if len(params.Channels) != 0 { + values.Add("channels", strings.Join(params.Channels, ",")) + } + if params.Content != "" { + values.Add("content", params.Content) + values.Add("token", api.token) + err = api.postMethod(ctx, "files.upload", values, response) + } else if params.File != "" { + err = postLocalWithMultipartResponse(ctx, api.httpclient, api.endpoint+"files.upload", params.File, "file", api.token, values, response, api) + } else if params.Reader != nil { + if params.Filename == "" { + return nil, fmt.Errorf("files.upload: FileUploadParameters.Filename is mandatory when using FileUploadParameters.Reader") + } + err = postWithMultipartResponse(ctx, api.httpclient, api.endpoint+"files.upload", params.Filename, "file", api.token, values, params.Reader, response, api) + } + + if err != nil { + return nil, err + } + + return &response.File, response.Err() +} + +// DeleteFileComment deletes a file's comment +func (api *Client) DeleteFileComment(commentID, fileID string) error { + return api.DeleteFileCommentContext(context.Background(), fileID, commentID) +} + +// DeleteFileCommentContext deletes a file's comment with a custom context +func (api *Client) DeleteFileCommentContext(ctx context.Context, fileID, commentID string) (err error) { + if fileID == "" || commentID == "" { + return ErrParametersMissing + } + + values := url.Values{ + "token": {api.token}, + "file": {fileID}, + "id": {commentID}, + } + _, err = api.fileRequest(ctx, "files.comments.delete", values) + return err +} + +// DeleteFile deletes a file +func (api *Client) DeleteFile(fileID string) error { + return api.DeleteFileContext(context.Background(), fileID) +} + +// DeleteFileContext deletes a file with a custom context +func (api *Client) DeleteFileContext(ctx context.Context, fileID string) (err error) { + values := url.Values{ + "token": {api.token}, + "file": {fileID}, + } + + _, err = api.fileRequest(ctx, "files.delete", values) + return err +} + +// RevokeFilePublicURL disables public/external sharing for a file +func (api *Client) RevokeFilePublicURL(fileID string) (*File, error) { + return api.RevokeFilePublicURLContext(context.Background(), fileID) +} + +// RevokeFilePublicURLContext disables public/external sharing for a file with a custom context +func (api *Client) RevokeFilePublicURLContext(ctx context.Context, fileID string) (*File, error) { + values := url.Values{ + "token": {api.token}, + "file": {fileID}, + } + + response, err := api.fileRequest(ctx, "files.revokePublicURL", values) + if err != nil { + return nil, err + } + return &response.File, nil +} + +// ShareFilePublicURL enabled public/external sharing for a file +func (api *Client) ShareFilePublicURL(fileID string) (*File, []Comment, *Paging, error) { + return api.ShareFilePublicURLContext(context.Background(), fileID) +} + +// ShareFilePublicURLContext enabled public/external sharing for a file with a custom context +func (api *Client) ShareFilePublicURLContext(ctx context.Context, fileID string) (*File, []Comment, *Paging, error) { + values := url.Values{ + "token": {api.token}, + "file": {fileID}, + } + + response, err := api.fileRequest(ctx, "files.sharedPublicURL", values) + if err != nil { + return nil, nil, nil, err + } + return &response.File, response.Comments, &response.Paging, nil +} + +// getUploadURLExternal gets a URL and fileID from slack which can later be used to upload a file +func (api *Client) getUploadURLExternal(ctx context.Context, params getUploadURLExternalParameters) (*getUploadURLExternalResponse, error) { + values := url.Values{ + "token": {api.token}, + "filename": {params.fileName}, + "length": {strconv.Itoa(params.fileSize)}, + } + if params.altText != "" { + values.Add("initial_comment", params.altText) + } + if params.snippetText != "" { + values.Add("thread_ts", params.snippetText) + } + response := &getUploadURLExternalResponse{} + err := api.postMethod(ctx, "files.getUploadURLExternal", values, response) + if err != nil { + return nil, err + } + + return response, response.Err() +} + +// uploadToURL uploads the file to the provided URL using post method +func (api *Client) uploadToURL(ctx context.Context, params uploadToURLParameters) (err error) { + values := url.Values{} + if params.Content != "" { + values.Add("content", params.Content) + values.Add("token", api.token) + err = postForm(ctx, api.httpclient, params.UploadURL, values, nil, api) + } else if params.File != "" { + err = postLocalWithMultipartResponse(ctx, api.httpclient, params.UploadURL, params.File, "file", api.token, values, nil, api) + } else if params.Reader != nil { + err = postWithMultipartResponse(ctx, api.httpclient, params.UploadURL, params.Filename, "file", api.token, values, params.Reader, nil, api) + } + return err +} + +// completeUploadExternal once files are uploaded, this completes the upload and shares it to the specified channel +func (api *Client) completeUploadExternal(ctx context.Context, fileID string, params completeUploadExternalParameters) (file *completeUploadExternalResponse, err error) { + request := []FileSummary{{ID: fileID, Title: params.title}} + requestBytes, err := json.Marshal(request) + if err != nil { + return nil, err + } + values := url.Values{ + "token": {api.token}, + "files": {string(requestBytes)}, + "channel_id": {params.channel}, + } + + if params.initialComment != "" { + values.Add("initial_comment", params.initialComment) + } + if params.threadTimestamp != "" { + values.Add("thread_ts", params.threadTimestamp) + } + response := &completeUploadExternalResponse{} + err = api.postMethod(ctx, "files.completeUploadExternal", values, response) + if err != nil { + return nil, err + } + if response.Err() != nil { + return nil, response.Err() + } + return response, nil +} + +// UploadFileV2 uploads file to a given slack channel using 3 steps - +// 1. Get an upload URL using files.getUploadURLExternal API +// 2. Send the file as a post to the URL provided by slack +// 3. Complete the upload and share it to the specified channel using files.completeUploadExternal +func (api *Client) UploadFileV2(params UploadFileV2Parameters) (*FileSummary, error) { + return api.UploadFileV2Context(context.Background(), params) +} + +// UploadFileV2 uploads file to a given slack channel using 3 steps with a custom context - +// 1. Get an upload URL using files.getUploadURLExternal API +// 2. Send the file as a post to the URL provided by slack +// 3. Complete the upload and share it to the specified channel using files.completeUploadExternal +func (api *Client) UploadFileV2Context(ctx context.Context, params UploadFileV2Parameters) (file *FileSummary, err error) { + if params.Filename == "" { + return nil, fmt.Errorf("file.upload.v2: filename cannot be empty") + } + if params.FileSize == 0 { + return nil, fmt.Errorf("file.upload.v2: file size cannot be 0") + } + if params.Channel == "" { + return nil, fmt.Errorf("file.upload.v2: channel cannot be empty") + } + u, err := api.getUploadURLExternal(ctx, getUploadURLExternalParameters{ + altText: params.AltTxt, + fileName: params.Filename, + fileSize: params.FileSize, + snippetText: params.SnippetText, + }) + if err != nil { + return nil, err + } + + err = api.uploadToURL(ctx, uploadToURLParameters{ + UploadURL: u.UploadURL, + Reader: params.Reader, + File: params.File, + Content: params.Content, + Filename: params.Filename, + }) + if err != nil { + return nil, err + } + + c, err := api.completeUploadExternal(ctx, u.FileID, completeUploadExternalParameters{ + title: params.Title, + channel: params.Channel, + initialComment: params.InitialComment, + threadTimestamp: params.ThreadTimestamp, + }) + if err != nil { + return nil, err + } + if len(c.Files) != 1 { + return nil, fmt.Errorf("file.upload.v2: something went wrong; received %d files instead of 1", len(c.Files)) + } + + return &c.Files[0], nil +} |
