diff --git a/internal_packages/message-list/lib/message-controls.cjsx b/internal_packages/message-list/lib/message-controls.cjsx index 2c5e9d23d..5dd7f99b8 100644 --- a/internal_packages/message-list/lib/message-controls.cjsx +++ b/internal_packages/message-list/lib/message-controls.cjsx @@ -1,6 +1,6 @@ React = require 'react' {remote} = require 'electron' -{Actions, NylasAPI, AccountStore} = require 'nylas-exports' +{Actions, NylasAPI, NylasAPIRequest, AccountStore} = require 'nylas-exports' {RetinaImg, ButtonDropdown, Menu} = require 'nylas-component-kit' class MessageControls extends React.Component @@ -123,16 +123,19 @@ class MessageControls extends React.Component app = remote.app tmpfile = path.join(app.getPath('temp'), @props.message.id) - NylasAPI.makeRequest - headers: - Accept: 'message/rfc822' - path: "/messages/#{@props.message.id}" - accountId: @props.message.accountId - json:false - success: (body) => - fs.writeFile tmpfile, body, => - window = new BrowserWindow(width: 800, height: 600, title: "#{@props.message.subject} - RFC822") - window.loadURL('file://'+tmpfile) + request = new NylasAPIRequest + api: NylasAPI + options: + headers: + Accept: 'message/rfc822' + path: "/messages/#{@props.message.id}" + accountId: @props.message.accountId + json:false + success: (body) => + fs.writeFile tmpfile, body, => + window = new BrowserWindow(width: 800, height: 600, title: "#{@props.message.subject} - RFC822") + window.loadURL('file://'+tmpfile) + request.run() _onLogData: => console.log @props.message diff --git a/internal_packages/message-list/lib/message-item-body.cjsx b/internal_packages/message-list/lib/message-item-body.cjsx index c19769fbf..929fdc71d 100644 --- a/internal_packages/message-list/lib/message-item-body.cjsx +++ b/internal_packages/message-list/lib/message-item-body.cjsx @@ -6,12 +6,16 @@ EmailFrame = require('./email-frame').default DraftHelpers, CanvasUtils, NylasAPI, + NylasAPIRequest, MessageUtils, MessageBodyProcessor, QuotedHTMLTransformer, FileDownloadStore } = require 'nylas-exports' -{InjectedComponentSet, RetinaImg} = require 'nylas-component-kit' +{ + InjectedComponentSet, + RetinaImg +} = require 'nylas-component-kit' TransparentPixel = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR4nGNikAQAACIAHF/uBd8AAAAASUVORK5CYII=" @@ -88,10 +92,13 @@ class MessageItemBody extends React.Component showQuotedText: !@state.showQuotedText _onFetchBody: => - NylasAPI.makeRequest - path: "/messages/#{@props.message.id}" - accountId: @props.message.accountId - returnsModel: true + request = new NylasAPIRequest + api: NylasAPI + options: + path: "/messages/#{@props.message.id}" + accountId: @props.message.accountId + returnsModel: true + request.run() .then => return unless @_mounted @setState({error: null}) diff --git a/internal_packages/onboarding/lib/onboarding-helpers.es6 b/internal_packages/onboarding/lib/onboarding-helpers.es6 index d97ca17ac..d32390b7d 100644 --- a/internal_packages/onboarding/lib/onboarding-helpers.es6 +++ b/internal_packages/onboarding/lib/onboarding-helpers.es6 @@ -1,7 +1,14 @@ /* eslint global-require: 0 */ import crypto from 'crypto'; -import {NylasAPI, N1CloudAPI, AccountStore, RegExpUtils, IdentityStore} from 'nylas-exports'; +import { + N1CloudAPI, + NylasAPI, + NylasAPIRequest, + AccountStore, + RegExpUtils, + IdentityStore, +} from 'nylas-exports'; const IMAP_FIELDS = new Set([ "imap_host", @@ -41,24 +48,24 @@ export function makeGmailOAuthRequest(sessionKey, callback) { error: callback, auth: noauth, success: (remoteJSON) => { - NylasAPI.makeRequest({ - path: `/auth`, - method: 'POST', - auth: noauth, - body: { - email: remoteJSON.email_address, - name: remoteJSON.name, - provider: 'gmail', - settings: { - xoauth2: remoteJSON.resolved_settings.xoauth2, + const request = new NylasAPIRequest({ + api: NylasAPI, + options: { + path: `/auth`, + method: 'POST', + auth: noauth, + body: { + email: remoteJSON.email_address, + name: remoteJSON.name, + provider: 'gmail', + settings: { + xoauth2: remoteJSON.resolved_settings.xoauth2, + }, }, success: callback, }, - error: callback, - success: (localJSON) => { - callback(null, localJSON); - }, - }); + }) + request.run() }, }); } @@ -109,18 +116,21 @@ export function runAuthRequest(accountInfo) { // Send the form data directly to Nylas to get code // If this succeeds, send the received code to N1 server to register the account // Otherwise process the error message from the server and highlight UI as needed - return NylasAPI.makeRequest({ - path: `/auth?client_id=${NylasAPI.AppID}&n1_id=${IdentityStore.identityId()}${reauthParam}`, - method: 'POST', - body: data, - returnsModel: false, - timeout: 150000, - auth: { - user: '', - pass: '', - sendImmediately: true, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: `/auth?client_id=${NylasAPI.AppID}&n1_id=${IdentityStore.identityId()}${reauthParam}`, + method: 'POST', + body: data, + returnsModel: false, + timeout: 150000, + auth: { + user: '', + pass: '', + sendImmediately: true, + }, }, - }) + }).run() } export function isValidHost(value) { diff --git a/internal_packages/worker-sync/lib/contact-rankings-cache.coffee b/internal_packages/worker-sync/lib/contact-rankings-cache.coffee deleted file mode 100644 index 16cf02bb4..000000000 --- a/internal_packages/worker-sync/lib/contact-rankings-cache.coffee +++ /dev/null @@ -1,35 +0,0 @@ - -RefreshingJSONCache = require './refreshing-json-cache' -{NylasAPI} = require 'nylas-exports' - -# Stores contact rankings -class ContactRankingsCache extends RefreshingJSONCache - constructor: (accountId) -> - @_accountId = accountId - super({ - key: "ContactRankingsFor#{accountId}", - version: 1, - refreshInterval: 60 * 60 * 1000 * 24 # one day - }) - - fetchData: (callback) => - return if NylasEnv.inSpecMode() - - NylasAPI.makeRequest - accountId: @_accountId - path: "/contacts/rankings" - returnsModel: false - .then (json) => - return unless json and json instanceof Array - - # Convert rankings into the format needed for quick lookup - rankings = {} - for [email, rank] in json - rankings[email.toLowerCase()] = rank - callback(rankings) - - .catch (err) => - console.warn("Request for Contact Rankings failed for - account #{@_accountId}. #{err}") - -module.exports = ContactRankingsCache diff --git a/internal_packages/worker-sync/lib/contact-rankings-cache.es6 b/internal_packages/worker-sync/lib/contact-rankings-cache.es6 new file mode 100644 index 000000000..e8f3a905e --- /dev/null +++ b/internal_packages/worker-sync/lib/contact-rankings-cache.es6 @@ -0,0 +1,49 @@ +import { + NylasAPI, + NylasAPIRequest, +} from 'nylas-exports' +import RefreshingJSONCache from './refreshing-json-cache' + + +// Stores contact rankings +class ContactRankingsCache extends RefreshingJSONCache { + constructor(accountId) { + super({ + key: `ContactRankingsFor${accountId}`, + version: 1, + refreshInterval: 60 * 60 * 1000 * 24, // one day + }) + this._accountId = accountId + } + + fetchData = (callback) => { + if (NylasEnv.inSpecMode()) return + + const request = new NylasAPIRequest({ + api: NylasAPI, + options: { + accountId: this._accountId, + path: "/contacts/rankings", + returnsModel: false, + }, + }) + + request.run() + .then((json) => { + if (!json || !(json instanceof Array)) return + + // Convert rankings into the format needed for quick lookup + const rankings = {} + for (const [email, rank] of json) { + rankings[email.toLowerCase()] = rank + } + callback(rankings) + }) + .catch((err) => { + console.warn(`Request for Contact Rankings failed for + account ${this._accountId}. ${err}`) + }) + } +} + +export default ContactRankingsCache diff --git a/src/flux/nylas-api-request.es6 b/src/flux/nylas-api-request.es6 index 6b40a3c3b..5936444ce 100644 --- a/src/flux/nylas-api-request.es6 +++ b/src/flux/nylas-api-request.es6 @@ -86,6 +86,10 @@ export default class NylasAPIRequest { } run() { + if (NylasEnv.getLoadSettings().isSpec) { + return Promise.resolve() + } + if (this.options.ensureOnce === true) { try { if (this.requestHasSucceededBefore()) { @@ -106,6 +110,39 @@ export default class NylasAPIRequest { const requestId = Utils.generateTempId(); + const onSuccess = (body) => { + let responseBody = body; + if (this.options.beforeProcessing) { + responseBody = this.options.beforeProcessing(responseBody) + } + if (this.options.returnsModel) { + this._handleModelResponse(responseBody).then(() => { + return Promise.resolve(responseBody) + }) + } + return Promise.resolve(responseBody) + } + + const onError = (err) => { + const {url, auth, returnsModel} = this.options + + let handlePromise = Promise.resolve() + if (err.response) { + if (err.response.statusCode === 404 && returnsModel) { + handlePromise = NylasAPI.handleModel404(url) + } + if ([401, 403].includes(err.response.statusCode)) { + handlePromise = NylasAPI.handleAuthenticationFailure(url, auth.user) + } + if (err.response.statusCode === 400) { + NylasEnv.reportError(err) + } + } + handlePromise.finally(() => { + Promise.reject(err) + }) + } + return new Promise((resolve, reject) => { this.options.startTime = Date.now(); Actions.willMakeAPIRequest({ @@ -154,6 +191,7 @@ export default class NylasAPIRequest { }); this.options.started(req); - }); + }) + .then(onSuccess, onError) } } diff --git a/src/flux/nylas-api.coffee b/src/flux/nylas-api.coffee index 1de9d1381..3d91545ce 100644 --- a/src/flux/nylas-api.coffee +++ b/src/flux/nylas-api.coffee @@ -58,53 +58,6 @@ class NylasAPI @_lockTracker = new NylasAPIChangeLockTracker() @APIRoot = "http://localhost:2578" - # Delegates to node's request object. - # On success, it will call the passed in success callback with options. - # On error it will create a new APIError object that wraps the error, - # response, and body. - # - # Options: - # {Any option that node's request takes} - # returnsModel - boolean to determine if the response should be - # unpacked into an Nylas data wrapper - # success: (body) -> callback gets passed the returned json object - # error: (apiError) -> the error callback gets passed an Nylas - # APIError object. - # - # Returns a Promise, which resolves or rejects in the success / error - # scenarios, respectively. - # - makeRequest: (options={}) -> - if NylasEnv.getLoadSettings().isSpec - return Promise.resolve() - - NylasAPIRequest ?= require('./nylas-api-request').default - req = new NylasAPIRequest(@, options) - - success = (body) => - if options.beforeProcessing - body = options.beforeProcessing(body) - if options.returnsModel - @_handleModelResponse(body).then (objects) -> - return Promise.resolve(body) - Promise.resolve(body) - - error = (err) => - {url, auth, returnsModel} = req.options - - handlePromise = Promise.resolve() - if err.response - if err.response.statusCode is 404 and returnsModel - handlePromise = @_handleModel404(url) - if err.response.statusCode in [401, 403] - handlePromise = @_handleAuthenticationFailure(url, auth?.user) - if err.response.statusCode is 400 - NylasEnv.reportError(err) - handlePromise.finally -> - Promise.reject(err) - - req.run().then(success, error) - longConnection: (opts) -> connection = new NylasLongConnection(@, opts.accountId, opts) connection.onResults(opts.onResults) @@ -119,7 +72,7 @@ class NylasAPI # # Handles: /account/// # - _handleModel404: (modelUrl) -> + handleModel404: (modelUrl) -> url = require('url') {pathname, query} = url.parse(modelUrl, true) components = pathname.split('/') @@ -139,7 +92,7 @@ class NylasAPI else return Promise.resolve() - _handleAuthenticationFailure: (modelUrl, apiToken) -> + handleAuthenticationFailure: (modelUrl, apiToken) -> # prevent /auth errors from presenting auth failure notices return Promise.resolve() unless apiToken @@ -174,8 +127,8 @@ class NylasAPI if uniquedJSONs.length < jsons.length console.warn("NylasAPI::handleModelResponse: called with non-unique object set. Maybe an API request returned the same object more than once?") - # Step 2: Filter out any objects we've locked (usually because we successfully) - # deleted them moments ago. + # Step 2: Filter out any objects we've locked (usually because we successfully + # deleted them moments ago). unlockedJSONs = _.filter uniquedJSONs, (json) => if @_lockTracker.acceptRemoteChangesTo(klass, json.id) is false json._delta?.ignoredBecause = "Model is locked, possibly because it's already been deleted." diff --git a/src/flux/stores/account-store.coffee b/src/flux/stores/account-store.coffee index 3d6a88e57..452269ad2 100644 --- a/src/flux/stores/account-store.coffee +++ b/src/flux/stores/account-store.coffee @@ -6,6 +6,7 @@ Utils = require '../models/utils' DatabaseStore = require('./database-store').default keytar = require 'keytar' NylasAPI = null +NylasAPIRequest = null configAccountsKey = "nylas.accounts" configVersionKey = "nylas.accountsVersion" @@ -188,11 +189,15 @@ class AccountStore extends NylasStore refreshHealthOfAccounts: (accountIds) => NylasAPI ?= require '../nylas-api' + NylasAPIRequest ?= require '../nylas-api-request' Promise.all(accountIds.map (accountId) => - return NylasAPI.makeRequest({ - path: '/account', - accountId: accountId, - }).then (json) => + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: '/account', + accountId: accountId, + }, + }).run().then (json) => existing = @accountForId(accountId) return unless existing # user may have deleted existing.fromJSON(json) diff --git a/src/flux/stores/file-download-store.es6 b/src/flux/stores/file-download-store.es6 index 7e7f24f71..83c04b0e0 100644 --- a/src/flux/stores/file-download-store.es6 +++ b/src/flux/stores/file-download-store.es6 @@ -9,6 +9,7 @@ import progress from 'request-progress'; import NylasStore from 'nylas-store'; import Actions from '../actions'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; Promise.promisifyAll(fs); @@ -111,39 +112,44 @@ export class Download { resolve(this); }; - NylasAPI.makeRequest({ - json: false, - path: `/files/${this.fileId}/download`, - accountId: this.accountId, - encoding: null, // Tell `request` not to parse the response data - started: (req) => { - this.request = req; - return progress(this.request, {throtte: 250}) - .on('progress', (prog) => { - this.percent = prog.percent; - this.progressCallback(); - }) + const request = new NylasAPIRequest({ + api: NylasAPI, + options: { + json: false, + path: `/files/${this.fileId}/download`, + accountId: this.accountId, + encoding: null, // Tell `request` not to parse the response data + started: (req) => { + this.request = req; + return progress(this.request, {throtte: 250}) + .on('progress', (prog) => { + this.percent = prog.percent; + this.progressCallback(); + }) - // This is a /socket/ error event, not an HTTP error event. It fires - // when the conn is dropped, user if offline, but not on HTTP status codes. - // It is sometimes called in place of "end", not before or after. - .on('error', onFailed) + // This is a /socket/ error event, not an HTTP error event. It fires + // when the conn is dropped, user if offline, but not on HTTP status codes. + // It is sometimes called in place of "end", not before or after. + .on('error', onFailed) - .on('end', () => { - if (this.state === State.Failed) { return; } + .on('end', () => { + if (this.state === State.Failed) { return; } - const {response} = this.request - const statusCode = response ? response.statusCode : null; - if ([200, 202, 204].includes(statusCode)) { - onSuccess(); - } else { - onFailed(new Error(`Server returned a ${statusCode}`)); - } - }) + const {response} = this.request + const statusCode = response ? response.statusCode : null; + if ([200, 202, 204].includes(statusCode)) { + onSuccess(); + } else { + onFailed(new Error(`Server returned a ${statusCode}`)); + } + }) - .pipe(stream); + .pipe(stream); + }, }, }); + + request.run() }); return this.promise } diff --git a/src/flux/tasks/change-mail-task.es6 b/src/flux/tasks/change-mail-task.es6 index 68303612d..36e4cf33c 100644 --- a/src/flux/tasks/change-mail-task.es6 +++ b/src/flux/tasks/change-mail-task.es6 @@ -4,6 +4,7 @@ import Task from './task'; import Thread from '../models/thread'; import Message from '../models/message'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import DatabaseStore from '../stores/database-store'; import {APIError} from '../errors'; @@ -250,17 +251,20 @@ export default class ChangeMailTask extends Task { const endpoint = (klass === Thread) ? 'threads' : 'messages'; - return NylasAPI.makeRequest({ - path: `/${endpoint}/${model.id}`, - accountId: model.accountId, - method: 'PUT', - body: this.requestBodyForModel(model), - returnsModel: true, - beforeProcessing: (body) => { - this._removeLock(model); - return body; + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: `/${endpoint}/${model.id}`, + accountId: model.accountId, + method: 'PUT', + body: this.requestBodyForModel(model), + returnsModel: true, + beforeProcessing: (body) => { + this._removeLock(model); + return body; + }, }, - }) + }).run() .catch((err) => { if (err instanceof APIError && err.statusCode === 404) { return Promise.resolve(); diff --git a/src/flux/tasks/destroy-category-task.es6 b/src/flux/tasks/destroy-category-task.es6 index ceb0141a7..474c8b3f6 100644 --- a/src/flux/tasks/destroy-category-task.es6 +++ b/src/flux/tasks/destroy-category-task.es6 @@ -6,6 +6,7 @@ import ChangeFolderTask from './change-folder-task'; import ChangeLabelTask from './change-labels-task'; import SyncbackCategoryTask from './syncback-category-task'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import {APIError} from '../errors'; export default class DestroyCategoryTask extends Task { @@ -52,12 +53,16 @@ export default class DestroyCategoryTask extends Task { // delta which comes after a delay NylasAPI.incrementRemoteChangeLock(Category, this.category.serverId); - return NylasAPI.makeRequest({ - accountId, - path, - method: 'DELETE', - returnsModel: false, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + accountId, + path, + method: 'DELETE', + returnsModel: false, + }, }) + .run() .thenReturn(Task.Status.Success) .catch(APIError, (err) => { if (!NylasAPI.PermanentErrorCodes.includes(err.statusCode)) { diff --git a/src/flux/tasks/destroy-draft-task.es6 b/src/flux/tasks/destroy-draft-task.es6 index fdf5b5d24..5e12d3655 100644 --- a/src/flux/tasks/destroy-draft-task.es6 +++ b/src/flux/tasks/destroy-draft-task.es6 @@ -3,6 +3,7 @@ import {APIError} from '../errors'; import Message from '../models/message'; import DatabaseStore from '../stores/database-store'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import BaseDraftTask from './base-draft-task'; export default class DestroyDraftTask extends BaseDraftTask { @@ -35,15 +36,19 @@ export default class DestroyDraftTask extends BaseDraftTask { NylasAPI.incrementRemoteChangeLock(Message, this.draft.serverId); - return NylasAPI.makeRequest({ - path: `/drafts/${this.draft.serverId}`, - accountId: this.draft.accountId, - method: "DELETE", - body: { - version: this.draft.version, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: `/drafts/${this.draft.serverId}`, + accountId: this.draft.accountId, + method: "DELETE", + body: { + version: this.draft.version, + }, + returnsModel: false, }, - returnsModel: false, }) + .run() // We deliberately do not decrement the change count, ensuring no deltas // about this object are received that could restore it. .thenReturn(Task.Status.Success) diff --git a/src/flux/tasks/destroy-model-task.es6 b/src/flux/tasks/destroy-model-task.es6 index 1c84ebfd5..1342cfcb5 100644 --- a/src/flux/tasks/destroy-model-task.es6 +++ b/src/flux/tasks/destroy-model-task.es6 @@ -2,6 +2,7 @@ import _ from 'underscore' import Task from './task' import NylasAPI from '../nylas-api' +import NylasAPIRequest from '../nylas-api-request' import DatabaseStore from '../stores/database-store' export default class DestroyModelTask extends Task { @@ -50,11 +51,16 @@ export default class DestroyModelTask extends Task { if (!this.serverId) { return Promise.resolve(Task.Status.Continue) } - return NylasAPI.makeRequest({ - path: `${this.endpoint}/${this.serverId}`, - method: "DELETE", - accountId: this.accountId, - }).then(() => { + return new NylasAPIRequest({ + api: new NylasAPI(), + options: { + path: `${this.endpoint}/${this.serverId}`, + method: "DELETE", + accountId: this.accountId, + }, + }) + .run() + .then(() => { return Promise.resolve(Task.Status.Success) }).catch(this.apiErrorHandler) } diff --git a/src/flux/tasks/event-rsvp-task.es6 b/src/flux/tasks/event-rsvp-task.es6 index d44482e06..fe0d8a54a 100644 --- a/src/flux/tasks/event-rsvp-task.es6 +++ b/src/flux/tasks/event-rsvp-task.es6 @@ -4,6 +4,8 @@ import {APIError} from '../errors'; import Utils from '../models/utils'; import DatabaseStore from '../stores/database-store'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; + export default class EventRSVPTask extends Task { constructor(event, RSVPEmail, RSVPResponse) { @@ -33,17 +35,21 @@ export default class EventRSVPTask extends Task { performRemote() { const {accountId, id} = this.event; - return NylasAPI.makeRequest({ - accountId, - timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent - path: "/send-rsvp", - method: "POST", - body: { - event_id: id, - status: this.RSVPResponse, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + accountId, + timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent + path: "/send-rsvp", + method: "POST", + body: { + event_id: id, + status: this.RSVPResponse, + }, + returnsModel: true, }, - returnsModel: true, }) + .run() .thenReturn(Task.Status.Success) .catch(APIError, (err) => { this.event.participants = this._previousParticipantsState; diff --git a/src/flux/tasks/multi-send-session-close-task.es6 b/src/flux/tasks/multi-send-session-close-task.es6 index 7ba900a96..434863b0e 100644 --- a/src/flux/tasks/multi-send-session-close-task.es6 +++ b/src/flux/tasks/multi-send-session-close-task.es6 @@ -3,6 +3,7 @@ import Task from './task'; import Actions from '../actions'; import {APIError} from '../errors'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import TaskQueue from '../../flux/stores/task-queue'; import SoundRegistry from '../../registries/sound-registry'; import MultiSendToIndividualTask from './multi-send-to-individual-task'; @@ -43,12 +44,16 @@ export default class MultiSendSessionCloseTask extends Task { } performRemote() { - return NylasAPI.makeRequest({ - timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent - method: "DELETE", - path: `/send-multiple/${this.message.id}`, - accountId: this.message.accountId, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent + method: "DELETE", + path: `/send-multiple/${this.message.id}`, + accountId: this.message.accountId, + }, }) + .run() .then(() => { // TODO: This is duplicated from SendDraftTask! Actions.recordUserEvent("Draft Sent") diff --git a/src/flux/tasks/multi-send-to-individual-task.es6 b/src/flux/tasks/multi-send-to-individual-task.es6 index 2678c18ff..89f88198b 100644 --- a/src/flux/tasks/multi-send-to-individual-task.es6 +++ b/src/flux/tasks/multi-send-to-individual-task.es6 @@ -3,6 +3,7 @@ import {RegExpUtils} from 'nylas-exports'; import Task from './task'; import {APIError} from '../errors'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; export default class MultiSendToIndividualTask extends Task { @@ -13,21 +14,25 @@ export default class MultiSendToIndividualTask extends Task { } performRemote() { - return NylasAPI.makeRequest({ - method: "POST", - timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent - path: `/send-multiple/${this.message.id}`, - accountId: this.message.accountId, - body: { - send_to: { - email: this.recipient.email, - name: this.recipient.name, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + method: "POST", + timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent + path: `/send-multiple/${this.message.id}`, + accountId: this.message.accountId, + body: { + send_to: { + email: this.recipient.email, + name: this.recipient.name, + }, + body: this._customizeTrackingForRecipient(this.message.body), }, - body: this._customizeTrackingForRecipient(this.message.body), + ensureOnce: true, + requestId: this.message.id, }, - ensureOnce: true, - requestId: this.message.id, }) + .run() .then(() => { return Promise.resolve(Task.Status.Success); }) diff --git a/src/flux/tasks/send-draft-task.es6 b/src/flux/tasks/send-draft-task.es6 index 723145f32..d3f7aa658 100644 --- a/src/flux/tasks/send-draft-task.es6 +++ b/src/flux/tasks/send-draft-task.es6 @@ -4,6 +4,7 @@ import Task from './task'; import Actions from '../actions'; import Message from '../models/message'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import {APIError, RequestEnsureOnceError} from '../errors'; import SoundRegistry from '../../registries/sound-registry'; import DatabaseStore from '../stores/database-store'; @@ -90,14 +91,18 @@ export default class SendDraftTask extends BaseDraftTask { const draft = this.draft.clone(); draft.body = this.stripTrackingFromBody(draft.body); - return NylasAPI.makeRequest({ - path: "/send-multiple", - accountId: this.draft.accountId, - method: 'POST', - body: draft.toJSON(), - timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent - returnsModel: false, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: "/send-multiple", + accountId: this.draft.accountId, + method: 'POST', + body: draft.toJSON(), + timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent + returnsModel: false, + }, }) + .run() .then((responseJSON) => { return this.createMessageFromResponse(responseJSON); }) @@ -124,16 +129,20 @@ export default class SendDraftTask extends BaseDraftTask { // This function returns a promise that resolves to the draft when the draft has // been sent successfully. sendWithSingleBody = () => { - return NylasAPI.makeRequest({ - path: "/send", - accountId: this.draft.accountId, - method: 'POST', - body: this.draft.toJSON(), - timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent - returnsModel: false, - ensureOnce: true, - requestId: this.draft.clientId, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: "/send", + accountId: this.draft.accountId, + method: 'POST', + body: this.draft.toJSON(), + timeout: 1000 * 60 * 5, // We cannot hang up a send - won't know if it sent + returnsModel: false, + ensureOnce: true, + requestId: this.draft.clientId, + }, }) + .run() .then((responseJSON) => { return this.createMessageFromResponse(responseJSON) }) diff --git a/src/flux/tasks/syncback-category-task.es6 b/src/flux/tasks/syncback-category-task.es6 index a5a217412..5b2b8c6ee 100644 --- a/src/flux/tasks/syncback-category-task.es6 +++ b/src/flux/tasks/syncback-category-task.es6 @@ -2,6 +2,7 @@ import DatabaseStore from '../stores/database-store'; import AccountStore from '../stores/account-store'; import Task from './task'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import {APIError} from '../errors'; export default class SyncbackCategoryTask extends Task { @@ -50,17 +51,21 @@ export default class SyncbackCategoryTask extends Task { const method = serverId ? "PUT" : "POST"; const path = serverId ? `/${collection}/${serverId}` : `/${collection}`; - return NylasAPI.makeRequest({ - path, - method, - accountId, - body: { - display_name: displayName, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path, + method, + accountId, + body: { + display_name: displayName, + }, + // returnsModel must be false because we want to update the + // existing model rather than returning a new model. + returnsModel: false, }, - // returnsModel must be false because we want to update the - // existing model rather than returning a new model. - returnsModel: false, }) + .run() .then((json) => { // This is where we update the existing model with the newly // created serverId. diff --git a/src/flux/tasks/syncback-draft-files-task.es6 b/src/flux/tasks/syncback-draft-files-task.es6 index 9c945d2d9..130cabff2 100644 --- a/src/flux/tasks/syncback-draft-files-task.es6 +++ b/src/flux/tasks/syncback-draft-files-task.es6 @@ -5,6 +5,7 @@ import Task from './task'; import {APIError} from '../errors'; import File from '../models/file'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import BaseDraftTask from './base-draft-task'; import DatabaseStore from '../stores/database-store'; import MultiRequestProgressMonitor from '../../multi-request-progress-monitor'; @@ -76,16 +77,20 @@ export default class SyncbackDraftFilesTask extends BaseDraftTask { }, } - return NylasAPI.makeRequest({ - path: "/files", - accountId: this.draft.accountId, - method: "POST", - json: false, - formData, - started: (req) => - this._attachmentUploadsMonitor.add(targetPath, size, req), - timeout: 20 * 60 * 1000, + return new NylasAPIRequest({ + api: NylasAPI, + options: { + path: "/files", + accountId: this.draft.accountId, + method: "POST", + json: false, + formData, + started: (req) => + this._attachmentUploadsMonitor.add(targetPath, size, req), + timeout: 20 * 60 * 1000, + }, }) + .run() .finally(() => { this._attachmentUploadsMonitor.remove(targetPath); }) diff --git a/src/flux/tasks/syncback-draft-task.es6 b/src/flux/tasks/syncback-draft-task.es6 index ac54f0773..46dc71dbb 100644 --- a/src/flux/tasks/syncback-draft-task.es6 +++ b/src/flux/tasks/syncback-draft-task.es6 @@ -2,6 +2,7 @@ import Task from './task'; import Actions from '../actions'; import DatabaseStore from '../stores/database-store'; import NylasAPI from '../nylas-api'; +import NylasAPIRequest from '../nylas-api-request'; import Message from '../models/message'; import BaseDraftTask from './base-draft-task'; import SyncbackMetadataTask from './syncback-metadata-task'; @@ -13,13 +14,17 @@ export default class SyncbackDraftTask extends BaseDraftTask { performRemote() { return this.refreshDraftReference() .then(() => - NylasAPI.makeRequest({ - accountId: this.draft.accountId, - path: (this.draft.serverId) ? `/drafts/${this.draft.serverId}` : "/drafts", - method: (this.draft.serverId) ? 'PUT' : 'POST', - body: this.draft.toJSON(), - returnsModel: false, + new NylasAPIRequest({ + api: NylasAPI, + options: { + accountId: this.draft.accountId, + path: (this.draft.serverId) ? `/drafts/${this.draft.serverId}` : "/drafts", + method: (this.draft.serverId) ? 'PUT' : 'POST', + body: this.draft.toJSON(), + returnsModel: false, + }, }) + .run() .then(this.applyResponseToDraft) .thenReturn(Task.Status.Success) ) diff --git a/src/flux/tasks/syncback-model-task.es6 b/src/flux/tasks/syncback-model-task.es6 index 766f56269..30aaee61a 100644 --- a/src/flux/tasks/syncback-model-task.es6 +++ b/src/flux/tasks/syncback-model-task.es6 @@ -1,6 +1,7 @@ import _ from 'underscore' import Task from './task' import NylasAPI from '../nylas-api' +import NylasAPIRequest from '../nylas-api-request' import {APIError} from '../errors' import DatabaseStore from '../stores/database-store' @@ -54,7 +55,10 @@ export default class SyncbackModelTask extends Task { accountId: model.accountId, returnsModel: false, }, this.getRequestData(model)); - return NylasAPI.makeRequest(options); + return new NylasAPIRequest({ + api: NylasAPI, + options, + }).run() } catch (error) { return Promise.reject(error) }