Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for uploading files #56

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added .hubot_history
Empty file.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@
},
"dependencies": {
"coffee-script": "~1.9.0",
"ws": "0.4.31",
"log": "1.4.0"
"form-data": "^0.2.0",
"log": "1.4.0",
"ws": "0.4.31"
},
"devDependencies": {
"grunt": "^0.4.5",
Expand Down
126 changes: 112 additions & 14 deletions src/client.coffee
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
https = require 'https'
fs = require 'fs'
path = require 'path'
querystring = require 'querystring'
WebSocket = require 'ws'
Log = require 'log'
{EventEmitter} = require 'events'
FormData = require 'form-data'

User = require './user'
Team = require './team'
Channel = require './channel'
Group = require './group'
File = require './file'
DM = require './dm'
Message = require './message'
Bot = require './bot'
Expand All @@ -26,13 +30,15 @@ class Client extends EventEmitter
@channels = {}
@dms = {}
@groups = {}
@files = {}
@users = {}
@bots = {}

@socketUrl = null
@ws = null
@_messageID = 0
@_pending = {}
@_fetchedFiles = false

@_connAttempts = 0

Expand Down Expand Up @@ -83,6 +89,7 @@ class Client extends EventEmitter
g = data.groups[k]
@groups[g.id] = new Group @, g

@setFiles()
# TODO: Process bots

@emit 'loggedIn', @self, @team
Expand Down Expand Up @@ -204,6 +211,23 @@ class Client extends EventEmitter
_onCreateGroup: (data) =>
@logger.debug data

createFile: (params, callback) ->
if params.channels and typeof params.channels == 'string'
toChannelId = (channelName) =>
@getChannelGroupOrDMByName(channelName).id
params.channels = params.channels.split(',').map(toChannelId).join(',')

fs.readFile params.file, (err, content) =>
return callback?(err) if err
params.filename = path.basename(params.file)
params.file = content
@_apiCall 'files.upload', params, =>
@_onCreateFile arguments...
callback? arguments...

_onCreateFile: (data) =>
@logger.debug data

setPresence: (presence, callback) ->
if presence is not 'away' and presence is not 'active' then return null

Expand Down Expand Up @@ -240,6 +264,19 @@ class Client extends EventEmitter
_onSetStatus: (data) =>
@logger.debug data

setFiles: (callback) ->
@_apiCall 'files.list', {}, =>
@_onSetFiles arguments...
callback? arguments...

_onSetFiles: (data)=>
@logger.debug data
@_fetchedFiles = true
for k of data.files
f = data.files[k]
@files[f.id] = new File @, f
@emit 'fetchFiles', data.files

#
# Utility functions
#
Expand Down Expand Up @@ -333,6 +370,18 @@ class Client extends EventEmitter
onStarRemoved: (data) ->
@emit 'star_removed', data

getFileByID: (id) ->
@files[id]

getCommentByID: (file_id, id) ->
@files[file_id].comments[id]

getFiles: ()->
if @_fetchedFiles
@files
else
null

#
# Message handler callback and dispatch
#
Expand Down Expand Up @@ -492,6 +541,37 @@ class Client extends EventEmitter
when 'star_removed'
@emit 'star_removed', message

when "file_created"
f = message.file
@files[message.file.id] = new File @, f
@emit 'fileCreated', f

when "file_change"
f = message.file
@files[message.file.id] = new File @, f
@emit 'fileChange', f

when "file_deleted"
if @files[message.file_id] then @emit "fileDeleted", @files[message.file_id]

when "file_comment_added"
if @files[message.file.id]
c = message.comment
c.file_id = message.file.id
@files[message.file.id].comments[c.id] = @files[message.file.id].newComment c
@emit 'fileCommentAdded', c

when "file_comment_edited"
if @files[message.file.id]
c = message.comment
c.file_id = message.file.id
@files[message.file.id].comments[c.id] = @files[message.file.id].newComment c
@emit 'fileCommentEdited', c

when "file_comment_deleted"
if @files[message.file.id] and @files[message.file.id].comments[message.comment]
@emit "fileCommentDeleted"

else
if message.reply_to
if message.type == 'pong'
Expand All @@ -513,7 +593,7 @@ class Client extends EventEmitter
@emit 'error', if message.error? then message.error else message
# TODO: resend?
else
if message.type not in ["file_created", "file_shared", "file_unshared", "file_comment", "file_public", "file_comment_edited", "file_comment_deleted", "file_change", "file_deleted", "star_added", "star_removed"]
if message.type not in ["file_shared", "file_unshared", "file_public", "star_added", "star_removed"]
@logger.debug 'Unknown message type: '+message.type
@logger.debug message

Expand All @@ -532,19 +612,37 @@ class Client extends EventEmitter
return message

_apiCall: (method, params, callback) ->
params['token'] = @token

post_data = querystring.stringify(params)

options =
hostname: @host,
method: 'POST',
path: '/api/' + method,
headers:
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length

req = https.request(options)
params['token'] ?= @token

req =
if params.file?
# multipart upload
fileName = params.filename
delete params.filename
form = new FormData()
for name, value of params
if name == 'file'
form.append(name, value, filename: fileName)
else
form.append(name, value)
request = https.request({
hostname: @host,
method: 'POST',
path: '/api/' + method,
headers: form.getHeaders()
})
form.pipe(request)
request
else
post_data = querystring.stringify(params)
https.request({
hostname: @host,
method: 'POST',
path: '/api/' + method,
headers:
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': post_data.length
})

req.on 'response', (res) =>
buffer = ''
Expand Down
32 changes: 32 additions & 0 deletions src/comment.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
Channel = require './channel'

class Comment extends Channel
constructor: (@_file, data = {}) ->
super @_file._client, data

edit: (text, callback)->
params = {
"id": @id
"file": @_file.id
"comment": text
}
@_client._apiCall 'files.comments.edit', params, =>
@_onEditComment arguments...
callback? arguments...

_onEdit: (data)=>
@_client.logger.debug data

delete: (callback) ->
params = {
"id": @id
"file": @_file.id
}
@_client._apiCall 'files.comments.delete', params, =>
@_onDeleteComment arguments...
callback? arguments...

_onDelete: (data)=>
@_client.logger.debug data

module.exports = Comment
105 changes: 105 additions & 0 deletions src/file.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
Channel = require './channel'
Comment = require './comment'

class File extends Channel
constructor: (@_client, data = {}) ->
super @_client, data

@comments = {}
@_fetchedComments = false

if @comments_count > 0
@setComments()
else
@_fetchedComments = true

setComments: (callback) ->
params = {
"file": @id
}
@_client._apiCall 'files.info', params, =>
@_onSetComments arguments...
callback? arguments...

_onSetComments: (data) =>
@_client.logger.debug data

@_fetchedComments = true
for k of data.comments
c = data.comments[k]
@comments[c.id] = @newComment c

@_client.emit 'fetchCommentsOn' + @id, data.comments

newComment: (comment) ->
return new Comment @, comment

getComments: ->
if @_fetchedComments
@comments
else
null

edit: (params, callback) ->
params.file = @id
@_client._apiCall 'files.edit', params, =>
@_onEdit arguments...
callback? arguments...

_onEdit: (data) =>
@_client.logger.debug data

delete: (callback) ->
params = {
"file": @id
}
@_client._apiCall 'files.delete', params, =>
@_onDelete arguments...
callback? arguments...

_onDelete: (data) =>
@_client.logger.debug data


addComment: (text, callback) ->
params = {
"file": @id,
"comment": text
}
@_client._apiCall 'files.comments.add', params, =>
@_onAddComment arguments...
callback arguments...

_onAddComment: (data)=>
@_client.logger.debug data

# TODO Not Supported yet

# share: (text)->
# params = {
# "file": @id
# }
# @_client._apiCall 'files.share', params, @_onShare

# _onShare: (data)=>
# @_client.logger.debug data

# unshared: (text)->
# params = {
# "file": @id
# }
# @_client._apiCall 'files.unshared', params, @_onUnshared

# _onUnshared: (data)=>
# @_client.logger.debug data

# public: (text)->
# params = {
# "file": @id
# }
# @_client._apiCall 'files.public', params, @_onPublic

# _onPublic: (data)=>
# @_client.logger.debug data

module.exports = File