-
Notifications
You must be signed in to change notification settings - Fork 662
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
fix file upload - consider metadata options by creating form data #500
Conversation
Codecov Report
@@ Coverage Diff @@
## master #500 +/- ##
=========================================
- Coverage 80.08% 79.7% -0.38%
=========================================
Files 6 6
Lines 241 271 +30
Branches 37 42 +5
=========================================
+ Hits 193 216 +23
- Misses 30 38 +8
+ Partials 18 17 -1
Continue to review full report at Codecov.
|
Allows WebClient token to be undefined
…ypes exports method argument types
removes pjson and directly requires package.json
more tightly specifies OAuthAccessArguments and OAuthTokenArguments
@@ -390,7 +400,7 @@ describe('WebClient', function () { | |||
// verify that any requests after maxRequestConcurrency were delayed by the responseDelay | |||
const queuedResponses = responses.slice(3); | |||
const minDiff = concurrentResponses[concurrentResponses.length - 1].diff + responseDelay; | |||
queuedResponses.forEach(r => assert.isAbove(r.diff, minDiff)); | |||
queuedResponses.forEach(r => assert.isAtLeast(r.diff, minDiff)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was this actually causing a failure? i think your change is more technically correct, but i'm wondering if you actually got a test run where the timers were so perfect that r.diff
and minDiff
were actually equal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can confirm that I've run into the issue of getting a test run where the timers matched up and a false positive was thrown--just once, but it has happened.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, I added this fix to the PR, because the build of my first commit broke accidentally
src/WebClient.spec.js
Outdated
const minDiff = concurrentResponses[concurrentResponses.length - 1].diff + responseDelay; | ||
queuedResponses.forEach(r => assert.isAbove(r.diff, minDiff)); | ||
queuedResponses.forEach(r => { | ||
assert.isAtLeast(r.diff, minDiff) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think this could fit in a single line rather than a block.
src/WebClient.spec.js
Outdated
// intentially vague about the method name | ||
return this.client.apiCall('upload', { | ||
file: { value: imageBuffer, options: { filename: 'train.png' } }, | ||
filename: 'train.png', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was trying to avoid this usage all together, because it seems redundant to have to specify the filename twice. can you see any advantage to doing it this way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The main advantage I see is the current implementation state of all the folks who used the old style. I don't know whether there is a need for someone to provide further attributes in the options field (e.g. contentType or knownLength)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i also want to make sure the implementation accounts for those who used the old style, but i prefer that the path we take to get there is not to redo the same hack, but to smooth out the API so that you don't need to redundantly specify the filename.
i wouldn't call it a hack if there was legitimately a use case or need for using the { value, options }
format for file
. i don't see any benefit from exposing contentType
and/or knownLength
at this time, since that only has the potential to force to incorrect values and cause the upload to fail (but I'm happy to be corrected if there is a real use case).
maybe we can channel this effort towards investigating why the following code didn't behave as we want:
node-slack-sdk/src/WebClient.ts
Lines 530 to 537 in a206c3e
// options.file = { | |
// // @ts-ignore | |
// value: options.file, | |
// options: { | |
// // @ts-ignore | |
// filename: options.filename, | |
// }, | |
// }; |
AFAICT it should result in the same thing...
also, have you tried this implementation to upload actual files? i'm not 100% confident that the nock expectations are correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, but I don't really understand your comment... this code snippet, you mentioned above works now as well. Off course I have tried it before I've opened this PR. And the problem with it, why it didn't work before was in the implementation of
node-slack-sdk/src/WebClient.ts
Lines 556 to 561 in a206c3e
if (containsBinaryData) { | |
return flattened.reduce((form, [key, value]) => { | |
form.append(key, value); | |
return form; | |
}, new FormData()); | |
} |
I've added this part in order to provide the attribute options
to the form builder.
if (key === 'file' && value.value) {
form.append(key, value.value, value.options);
return form;
}
This is actually the main goal of this PR and all other things we talked here about, were done with intention not to break the current state. As I mentioned in the PR description, you can upload files now with no need of additional/redundant information
let file = fs.readFileSync('../file.png')
slackClient.files.upload({ channels, file, filename: 'file.png' })
Should i remove the 'backup' solution to restrict the file upload to only one way?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@KharitonOff thanks so much for your clarification. i missed that diff amidst the rest of the changes but i now see where the issue was before.
yes, i'd prefer removing the backup solution so that we don't unnecessarily expand the API contract. if you can do that, i'm happy to land this PR!
src/WebClient.spec.js
Outdated
assert.lengthOf(parts.files, 1); | ||
const file = parts.files[0]; | ||
// options were not provided to the form builder | ||
assert.include(file, { fieldname: 'file' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still not asserting that the filename
field exists, and removed the comment that would remind us to improve the tests so that it is asserted. why?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, I've overseen this assertion statement and felt that the fix solved the problem pointed in the comment. I'll bring your TODO and assertion back.
src/WebClient.spec.js
Outdated
// defined error would occur, or if Slack just doesn't need a filename for the part | ||
// assert.include(file, { fieldname: 'file', filename: 'train.jpg' }); | ||
// NOTE: it seems the file and its filename are emitted as a field in addition to the token, not sure if | ||
// this was happening in the old implementation. | ||
assert.include(file, { fieldname: 'file' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
still not asserting that the filename
field exists.
@KharitonOff thanks for your contribution! can you help clarify by answering my comments above? |
I've changed your test again in order to fix the build. I hope it is ok for you. |
test/typescript/test.ts
Outdated
@@ -4,7 +4,7 @@ import { check, checkDirectory } from 'typings-tester'; | |||
describe('typescript typings tests', () => { | |||
it('should allow WebClient to work without a token', () => { | |||
check([`${__dirname}/sources/webclient-no-token.ts`], `${__dirname}/tsconfig-strict.json`); | |||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe the best place to override this value is in test/mocha.opts
, so that it doesn't just apply to this one case. i don't see anything unique to this case that should make it run longer than the other. its my guess that Travis generally has unpredictable speed and we should make the ceiling high enough to accomodate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree! I didn't find this setting before, that's why I added it only to this test.
@KharitonOff its a small world. I just noticed that you work on CLA Assistant (which we use) and you helped review an implementation for a feature i requested, way back when (cla-assistant/cla-assistant#246). 🙌 |
@aoberoi yes, indeed, glad to meet you again! It is nice to see that you are using CLA Assistant and it was very interesting to have a contributer role and sign your CLA 😄 |
// TODO: understand why this assertion is failing. already employed the buffer metadata workaround, should | ||
// look into the details about whether that workaround is still required, or why else the `source.on` is not | ||
// defined error would occur, or if Slack just doesn't need a filename for the part | ||
// assert.include(file, { fieldname: 'file', filename: 'train.jpg' }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to self: should the assertion with filename work now?
// look into the details about whether that workaround is still required, or why else the `source.on` is not | ||
// defined error would occur, or if Slack just doesn't need a filename for the part | ||
// assert.include(file, { fieldname: 'file', filename: 'train.jpg' }); | ||
assert.include(file, { fieldname: 'file', filename: 'train.jpg' }); | ||
|
||
// NOTE: it seems the file and its filename are emitted as a field in addition to the token, not sure if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note to self: the following assertion is probably redundant now
This is so great!! Extra thanks for cleaning up the style issues and some incorrect behavior in the existing tests. I'm going to follow up with a PR that addresses the "note to self" comments above. |
Cool! Thanks for merging it 👍 |
Summary
fix file upload issue, now you can upload buffer stream as expected:
as well as proposed fix in #307:
related to #307
Requirements (place an
x
in each[ ]
)