refactor(nylas-api): Create API requests from tasks

This commit is contained in:
Jackie Luo 2016-11-29 12:29:28 -08:00
parent bab39a5c21
commit 7b7fbb3b1b
21 changed files with 355 additions and 255 deletions

View file

@ -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

View file

@ -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})

View file

@ -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) {

View file

@ -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

View file

@ -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

View file

@ -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)
}
}

View file

@ -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/<nid>/<collection>/<id>
#
_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."

View file

@ -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)

View file

@ -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
}

View file

@ -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();

View file

@ -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)) {

View file

@ -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)

View file

@ -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)
}

View file

@ -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;

View file

@ -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")

View file

@ -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);
})

View file

@ -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)
})

View file

@ -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.

View file

@ -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);
})

View file

@ -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)
)

View file

@ -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)
}