mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-01-12 02:58:20 +08:00
☕(account-store): Convert to ES6
This commit is contained in:
parent
30ce9be8d9
commit
bd30adec15
16 changed files with 453 additions and 382 deletions
|
@ -116,7 +116,7 @@ export default class Category extends Model {
|
|||
}
|
||||
|
||||
displayType = () => {
|
||||
AccountStore = AccountStore || require('../stores/account-store');
|
||||
AccountStore = AccountStore || require('../stores/account-store').default;
|
||||
if (AccountStore.accountForId(this.accountId).usesLabels()) {
|
||||
return 'label';
|
||||
}
|
||||
|
|
|
@ -127,9 +127,11 @@ class NylasAPI {
|
|||
|
||||
handleAuthenticationFailure = (modelUrl, apiToken, apiName) => {
|
||||
// Prevent /auth errors from presenting auth failure notices
|
||||
if (!apiToken) return Promise.resolve()
|
||||
if (!apiToken) {
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
AccountStore = AccountStore || require('./stores/account-store')
|
||||
AccountStore = AccountStore || require('./stores/account-store').default
|
||||
const account = AccountStore.accounts().find((acc) => {
|
||||
const localMatch = AccountStore.tokensForAccountId(acc.id).localSync === apiToken;
|
||||
const cloudMatch = AccountStore.tokensForAccountId(acc.id).n1Cloud === apiToken;
|
||||
|
@ -319,7 +321,7 @@ class NylasAPI {
|
|||
}
|
||||
|
||||
accessTokenForAccountId = (aid) => {
|
||||
AccountStore = AccountStore || require('./stores/account-store')
|
||||
AccountStore = AccountStore || require('./stores/account-store').default
|
||||
return AccountStore.tokensForAccountId(aid).localSync
|
||||
}
|
||||
|
||||
|
@ -369,7 +371,7 @@ class NylasAPI {
|
|||
|
||||
let account = accountOrId
|
||||
if (!(accountOrId instanceof Account)) {
|
||||
AccountStore = AccountStore || require('./stores/account-store')
|
||||
AccountStore = AccountStore || require('./stores/account-store').default
|
||||
account = AccountStore.accountForId(accountOrId)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,365 +0,0 @@
|
|||
_ = require 'underscore'
|
||||
NylasStore = require 'nylas-store'
|
||||
Actions = require('../actions').default
|
||||
Account = require('../models/account').default
|
||||
Utils = require '../models/utils'
|
||||
DatabaseStore = require('./database-store').default
|
||||
keytar = require 'keytar'
|
||||
NylasAPI = null
|
||||
NylasAPIRequest = null
|
||||
|
||||
configAccountsKey = "nylas.accounts"
|
||||
configVersionKey = "nylas.accountsVersion"
|
||||
configTokensKey = "nylas.accountTokens"
|
||||
keytarServiceName = 'Nylas'
|
||||
|
||||
###
|
||||
Public: The AccountStore listens to changes to the available accounts in
|
||||
the database and exposes the currently active Account via {::current}
|
||||
|
||||
Section: Stores
|
||||
###
|
||||
class AccountStore extends NylasStore
|
||||
|
||||
constructor: ->
|
||||
@_loadAccounts()
|
||||
@listenTo Actions.removeAccount, @_onRemoveAccount
|
||||
@listenTo Actions.updateAccount, @_onUpdateAccount
|
||||
@listenTo Actions.reorderAccount, @_onReorderAccount
|
||||
|
||||
NylasEnv.config.onDidChange configVersionKey, (change) =>
|
||||
# If we already have this version of the accounts config, it means we
|
||||
# are the ones who saved the change, and we don't need to reload.
|
||||
return if @_version / 1 is change.newValue / 1
|
||||
oldAccountIds = _.pluck(@_accounts, 'id')
|
||||
@_loadAccounts()
|
||||
accountIds = _.pluck(@_accounts, 'id')
|
||||
newAccountIds = _.difference(accountIds, oldAccountIds)
|
||||
|
||||
if newAccountIds.length > 0
|
||||
newId = newAccountIds[0]
|
||||
CategoryStore = require './category-store'
|
||||
CategoryStore.whenCategoriesReady(newId).then =>
|
||||
Actions.focusDefaultMailboxPerspectiveForAccounts([newId], sidebarAccountIds: accountIds)
|
||||
# TODO this Action is a hack, get rid of it in sidebar refactor
|
||||
# Wait until the FocusedPerspectiveStore triggers and the sidebar is
|
||||
# updated to uncollapse the inbox for the new account
|
||||
_.defer =>
|
||||
Actions.setCollapsedSidebarItem('Inbox', false)
|
||||
|
||||
_loadAccounts: =>
|
||||
try
|
||||
@_caches = {}
|
||||
@_tokens = {}
|
||||
@_version = NylasEnv.config.get(configVersionKey) || 0
|
||||
|
||||
@_accounts = []
|
||||
for json in NylasEnv.config.get(configAccountsKey) || []
|
||||
@_accounts.push((new Account).fromJSON(json))
|
||||
|
||||
# Run a few checks on account consistency. We want to display useful error
|
||||
# messages and these can result in very strange exceptions downstream otherwise.
|
||||
@_enforceAccountsValidity()
|
||||
|
||||
# Load tokens using the new keytar method
|
||||
@_tokens = {}
|
||||
for account in @_accounts
|
||||
@_tokens[account.id] = {
|
||||
n1Cloud: keytar.getPassword(keytarServiceName, "#{account.emailAddress}.n1Cloud"),
|
||||
localSync: keytar.getPassword(keytarServiceName, "#{account.emailAddress}.localSync"),
|
||||
}
|
||||
catch error
|
||||
NylasEnv.reportError(error)
|
||||
|
||||
@_trigger()
|
||||
|
||||
_enforceAccountsValidity: =>
|
||||
seenIds = {}
|
||||
seenEmails = {}
|
||||
message = null
|
||||
|
||||
@_accounts = @_accounts.filter (account) =>
|
||||
if not account.emailAddress
|
||||
message = "Assertion failure: One of the accounts in config.json did not have an emailAddress, and was removed. You should re-link the account."
|
||||
return false
|
||||
if seenIds[account.id]
|
||||
message = "Assertion failure: Two of the accounts in config.json had the same ID and one was removed. Please give each account a separate ID."
|
||||
return false
|
||||
if seenEmails[account.emailAddress]
|
||||
message = "Assertion failure: Two of the accounts in config.json had the same email address and one was removed."
|
||||
return false
|
||||
|
||||
seenIds[account.id] = true
|
||||
seenEmails[account.emailAddress] = true
|
||||
return true
|
||||
|
||||
if message and NylasEnv.isMainWindow()
|
||||
NylasEnv.showErrorDialog("N1 was unable to load your account preferences.\n\n#{message}");
|
||||
|
||||
_trigger: ->
|
||||
for account in @_accounts
|
||||
if not account?.id
|
||||
err = new Error("An invalid account was added to `this._accounts`")
|
||||
NylasEnv.reportError(err)
|
||||
@_accounts = _.compact(@_accounts)
|
||||
@trigger()
|
||||
|
||||
_save: =>
|
||||
@_version += 1
|
||||
NylasEnv.config.set(configTokensKey, null)
|
||||
NylasEnv.config.set(configAccountsKey, @_accounts)
|
||||
NylasEnv.config.set(configVersionKey, @_version)
|
||||
@_trigger()
|
||||
|
||||
# Inbound Events
|
||||
|
||||
_onUpdateAccount: (id, updated) =>
|
||||
idx = _.findIndex @_accounts, (a) -> a.id is id
|
||||
account = @_accounts[idx]
|
||||
return unless account
|
||||
account = _.extend(account, updated)
|
||||
@_caches = {}
|
||||
@_accounts[idx] = account
|
||||
@_save()
|
||||
|
||||
_onRemoveAccount: (id) =>
|
||||
account = _.findWhere(@_accounts, {id})
|
||||
return unless account
|
||||
keytar.deletePassword(keytarServiceName, account.emailAddress)
|
||||
|
||||
@_caches = {}
|
||||
|
||||
remainingAccounts = _.without(@_accounts, account)
|
||||
# This action is called before saving because we need to unfocus the
|
||||
# perspective of the account that is being removed before removing the
|
||||
# account, otherwise when we trigger with the new set of accounts, the
|
||||
# current perspective will still reference a stale accountId which will
|
||||
# cause things to break
|
||||
Actions.focusDefaultMailboxPerspectiveForAccounts(remainingAccounts)
|
||||
_.defer =>
|
||||
Actions.setCollapsedSidebarItem('Inbox', true)
|
||||
|
||||
@_accounts = remainingAccounts
|
||||
@_save()
|
||||
|
||||
if remainingAccounts.length is 0
|
||||
ipc = require('electron').ipcRenderer
|
||||
ipc.send('command', 'application:relaunch-to-initial-windows', {
|
||||
resetDatabase: true,
|
||||
})
|
||||
|
||||
_onReorderAccount: (id, newIdx) =>
|
||||
existingIdx = _.findIndex @_accounts, (a) -> a.id is id
|
||||
return if existingIdx is -1
|
||||
account = @_accounts[existingIdx]
|
||||
@_caches = {}
|
||||
@_accounts.splice(existingIdx, 1)
|
||||
@_accounts.splice(newIdx, 0, account)
|
||||
@_save()
|
||||
|
||||
addAccountFromJSON: (json, localToken, cloudToken) =>
|
||||
if not json.email_address or not json.provider
|
||||
console.error("Returned account data is invalid", json)
|
||||
console.log JSON.stringify(json)
|
||||
throw new Error("Returned account data is invalid")
|
||||
|
||||
@_loadAccounts()
|
||||
|
||||
@_tokens[json.id] =
|
||||
n1Cloud: cloudToken
|
||||
localSync: localToken
|
||||
keytar.replacePassword(keytarServiceName, "#{json.email_address}.n1Cloud", cloudToken)
|
||||
keytar.replacePassword(keytarServiceName, "#{json.email_address}.localSync", localToken)
|
||||
|
||||
existingIdx = _.findIndex @_accounts, (a) ->
|
||||
a.id is json.id or a.emailAddress is json.email_address
|
||||
|
||||
if existingIdx is -1
|
||||
account = (new Account).fromJSON(json)
|
||||
@_accounts.push(account)
|
||||
else
|
||||
account = @_accounts[existingIdx]
|
||||
account.fromJSON(json)
|
||||
|
||||
@_save()
|
||||
|
||||
refreshHealthOfAccounts: (accountIds) =>
|
||||
NylasAPI ?= require('../nylas-api').default
|
||||
NylasAPIRequest ?= require('../nylas-api-request').default
|
||||
Promise.all(accountIds.map (accountId) =>
|
||||
return new NylasAPIRequest({
|
||||
api: NylasAPI,
|
||||
options: {
|
||||
path: '/account',
|
||||
accountId: accountId,
|
||||
},
|
||||
}).run().then (json) =>
|
||||
return unless json
|
||||
existing = @accountForId(accountId)
|
||||
return unless existing # user may have deleted
|
||||
existing.fromJSON(json)
|
||||
).finally =>
|
||||
@_caches = {}
|
||||
@_save()
|
||||
|
||||
# Exposed Data
|
||||
|
||||
# Private: Helper which caches the results of getter functions often needed
|
||||
# in the middle of React render cycles. (Performance critical!)
|
||||
|
||||
_cachedGetter: (key, fn) ->
|
||||
@_caches[key] ?= fn()
|
||||
@_caches[key]
|
||||
|
||||
# Public: Returns an {Array} of {Account} objects
|
||||
accounts: =>
|
||||
@_accounts
|
||||
|
||||
accountIds: =>
|
||||
_.pluck(@_accounts, 'id')
|
||||
|
||||
accountsForItems: (items) =>
|
||||
accounts = {}
|
||||
items.forEach ({accountId}) =>
|
||||
accounts[accountId] ?= @accountForId(accountId)
|
||||
_.values(accounts)
|
||||
|
||||
accountForItems: (items) =>
|
||||
accounts = @accountsForItems(items)
|
||||
return null if accounts.length > 1
|
||||
return accounts[0]
|
||||
|
||||
# Public: Returns the {Account} for the given email address, or null.
|
||||
accountForEmail: (email) =>
|
||||
for account in @accounts()
|
||||
if Utils.emailIsEquivalent(email, account.emailAddress)
|
||||
return account
|
||||
for alias in @aliases()
|
||||
if Utils.emailIsEquivalent(email, alias.email)
|
||||
return @accountForId(alias.accountId)
|
||||
return null
|
||||
|
||||
# Public: Returns the {Account} for the given account id, or null.
|
||||
accountForId: (id) =>
|
||||
@_cachedGetter "accountForId:#{id}", => _.findWhere(@_accounts, {id})
|
||||
|
||||
emailAddresses: ->
|
||||
addresses = _.pluck((@accounts() ? []), "emailAddress")
|
||||
addresses = addresses.concat(_.pluck((@aliases() ? []), "email"))
|
||||
return _.unique(addresses)
|
||||
|
||||
aliases: =>
|
||||
@_cachedGetter "aliases", =>
|
||||
aliases = []
|
||||
for acc in @_accounts
|
||||
aliases.push(acc.me())
|
||||
for alias in acc.aliases
|
||||
aliasContact = acc.meUsingAlias(alias)
|
||||
aliasContact.isAlias = true
|
||||
aliases.push(aliasContact)
|
||||
return aliases
|
||||
|
||||
aliasesFor: (accountsOrIds) =>
|
||||
ids = accountsOrIds.map (accOrId) ->
|
||||
if accOrId instanceof Account then accOrId.id else accOrId
|
||||
@aliases().filter((contact) -> contact.accountId in ids)
|
||||
|
||||
# Public: Returns the currently active {Account}.
|
||||
current: =>
|
||||
throw new Error("AccountStore.current() has been deprecated.")
|
||||
|
||||
# Private: This method is going away soon, do not rely on it.
|
||||
#
|
||||
tokensForAccountId: (id) =>
|
||||
@_tokens[id]
|
||||
|
||||
# Private: Load fake data from a directory for taking nice screenshots
|
||||
#
|
||||
_importFakeData: (dir) =>
|
||||
fs = require 'fs-plus'
|
||||
path = require 'path'
|
||||
Message = require('../models/message').default
|
||||
Account = require('../models/account').default
|
||||
Thread = require('../models/thread').default
|
||||
Label = require('../models/label').default
|
||||
|
||||
@_caches = {}
|
||||
|
||||
labels = []
|
||||
threads = []
|
||||
messages = []
|
||||
|
||||
account = @accountForEmail('nora@nylas.com')
|
||||
unless account
|
||||
account = new Account()
|
||||
account.serverId = account.clientId
|
||||
account.emailAddress = "nora@nylas.com"
|
||||
account.organizationUnit = 'label'
|
||||
account.label = "Nora's Email"
|
||||
account.aliases = []
|
||||
account.name = "Nora"
|
||||
account.provider = "gmail"
|
||||
json = account.toJSON()
|
||||
json.token = 'nope'
|
||||
@addAccountFromJSON(json)
|
||||
|
||||
filenames = fs.readdirSync(path.join(dir, 'threads'))
|
||||
for filename in filenames
|
||||
threadJSON = fs.readFileSync(path.join(dir, 'threads', filename))
|
||||
threadMessages = JSON.parse(threadJSON).map (j) -> (new Message).fromJSON(j)
|
||||
threadLabels = []
|
||||
threadParticipants = []
|
||||
threadAttachment = false
|
||||
threadUnread = false
|
||||
|
||||
for m in threadMessages
|
||||
m.accountId = account.id
|
||||
for l in m.categories
|
||||
l.accountId = account.id
|
||||
for l in m.files
|
||||
l.accountId = account.id
|
||||
threadParticipants = threadParticipants.concat(m.participants())
|
||||
threadLabels = threadLabels.concat(m.categories)
|
||||
threadAttachment ||= m.files.length > 0
|
||||
threadUnread ||= m.unread
|
||||
|
||||
threadParticipants = _.uniq threadParticipants, (p) -> p.email
|
||||
threadLabels = _.uniq threadLabels, (l) -> l.id
|
||||
labels = _.uniq labels.concat(threadLabels), (l) -> l.id
|
||||
|
||||
lastMsg = _.last(threadMessages)
|
||||
thread = new Thread(
|
||||
accountId: account.id
|
||||
serverId: lastMsg.threadId
|
||||
clientId: lastMsg.threadId
|
||||
subject: lastMsg.subject
|
||||
lastMessageReceivedTimestamp: lastMsg.date
|
||||
hasAttachment: threadAttachment
|
||||
categories: threadLabels
|
||||
participants: threadParticipants
|
||||
unread: threadUnread
|
||||
snippet: lastMsg.snippet
|
||||
starred: lastMsg.starred
|
||||
)
|
||||
messages = messages.concat(threadMessages)
|
||||
threads.push(thread)
|
||||
|
||||
downloadsDir = path.join(dir, 'downloads')
|
||||
if fs.existsSync(downloadsDir)
|
||||
for filename in fs.readdirSync(downloadsDir)
|
||||
destPath = path.join(NylasEnv.getConfigDirPath(), 'downloads', filename)
|
||||
fs.removeSync(destPath) if fs.existsSync(destPath)
|
||||
fs.copySync(path.join(downloadsDir, filename), destPath)
|
||||
|
||||
DatabaseStore.inTransaction (t) =>
|
||||
Promise.all([
|
||||
t.persistModel(account),
|
||||
t.persistModels(labels),
|
||||
t.persistModels(messages),
|
||||
t.persistModels(threads)
|
||||
])
|
||||
.then =>
|
||||
Actions.focusDefaultMailboxPerspectiveForAccounts([account.id])
|
||||
.then -> new Promise (resolve, reject) -> setTimeout(resolve, 1000)
|
||||
|
||||
module.exports = new AccountStore()
|
434
src/flux/stores/account-store.es6
Normal file
434
src/flux/stores/account-store.es6
Normal file
|
@ -0,0 +1,434 @@
|
|||
/* eslint global-require: 0 */
|
||||
|
||||
import _ from 'underscore'
|
||||
import keytar from 'keytar'
|
||||
|
||||
import NylasStore from 'nylas-store'
|
||||
import Actions from '../actions'
|
||||
import Account from '../models/account'
|
||||
import Utils from '../models/utils'
|
||||
import DatabaseStore from './database-store'
|
||||
|
||||
let NylasAPI = null
|
||||
let NylasAPIRequest = null
|
||||
|
||||
const configAccountsKey = "nylas.accounts"
|
||||
const configVersionKey = "nylas.accountsVersion"
|
||||
const configTokensKey = "nylas.accountTokens"
|
||||
const keytarServiceName = 'Nylas'
|
||||
|
||||
|
||||
/*
|
||||
Public: The AccountStore listens to changes to the available accounts in
|
||||
the database and exposes the currently active Account via {::current}
|
||||
|
||||
Section: Stores
|
||||
*/
|
||||
class AccountStore extends NylasStore {
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this._loadAccounts()
|
||||
this.listenTo(Actions.removeAccount, this._onRemoveAccount)
|
||||
this.listenTo(Actions.updateAccount, this._onUpdateAccount)
|
||||
this.listenTo(Actions.reorderAccount, this._onReorderAccount)
|
||||
|
||||
NylasEnv.config.onDidChange(configVersionKey, (change) => {
|
||||
// If we already have this version of the accounts config, it means we
|
||||
// are the ones who saved the change, and we don't need to reload.
|
||||
if (this._version / 1 === change.newValue / 1) return
|
||||
const oldAccountIds = _.pluck(this._accounts, 'id')
|
||||
this._loadAccounts()
|
||||
const accountIds = _.pluck(this._accounts, 'id')
|
||||
const newAccountIds = _.difference(accountIds, oldAccountIds)
|
||||
|
||||
if (newAccountIds.length > 0) {
|
||||
const newId = newAccountIds[0]
|
||||
const CategoryStore = require('./category-store')
|
||||
CategoryStore.whenCategoriesReady(newId).then(() => {
|
||||
Actions.focusDefaultMailboxPerspectiveForAccounts([newId], {sidebarAccountIds: accountIds})
|
||||
// TODO: This Action is a hack, get rid of it in sidebar refactor
|
||||
// Wait until the FocusedPerspectiveStore triggers and the sidebar is
|
||||
// updated to uncollapse the inbox for the new account
|
||||
_.defer(() => {
|
||||
Actions.setCollapsedSidebarItem('Inbox', false)
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
_loadAccounts = () => {
|
||||
try {
|
||||
this._caches = {}
|
||||
this._tokens = {}
|
||||
this._version = NylasEnv.config.get(configVersionKey) || 0
|
||||
|
||||
this._accounts = []
|
||||
for (const json of NylasEnv.config.get(configAccountsKey) || []) {
|
||||
this._accounts.push((new Account()).fromJSON(json))
|
||||
}
|
||||
|
||||
// Run a few checks on account consistency. We want to display useful error
|
||||
// messages and these can result in very strange exceptions downstream otherwise.
|
||||
this._enforceAccountsValidity()
|
||||
|
||||
// Load tokens using the new keytar method
|
||||
this._tokens = {}
|
||||
for (const account of this._accounts) {
|
||||
this._tokens[account.id] = {
|
||||
n1Cloud: keytar.getPassword(keytarServiceName, `${account.emailAddress}.n1Cloud`),
|
||||
localSync: keytar.getPassword(keytarServiceName, `${account.emailAddress}.localSync`),
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
NylasEnv.reportError(error)
|
||||
}
|
||||
|
||||
this._trigger()
|
||||
}
|
||||
|
||||
_enforceAccountsValidity = () => {
|
||||
const seenIds = {}
|
||||
const seenEmails = {}
|
||||
let message = null
|
||||
|
||||
this._accounts = this._accounts.filter((account) => {
|
||||
if (!account.emailAddress) {
|
||||
message = "Assertion failure: One of the accounts in config.json did not have an emailAddress, and was removed. You should re-link the account."
|
||||
return false
|
||||
}
|
||||
if (seenIds[account.id]) {
|
||||
message = "Assertion failure: Two of the accounts in config.json had the same ID and one was removed. Please give each account a separate ID."
|
||||
return false
|
||||
}
|
||||
if (seenEmails[account.emailAddress]) {
|
||||
message = "Assertion failure: Two of the accounts in config.json had the same email address and one was removed."
|
||||
return false
|
||||
}
|
||||
|
||||
seenIds[account.id] = true
|
||||
seenEmails[account.emailAddress] = true
|
||||
return true
|
||||
})
|
||||
|
||||
if (message && NylasEnv.isMainWindow()) {
|
||||
NylasEnv.showErrorDialog(`N1 was unable to load your account preferences.\n\n${message}`)
|
||||
}
|
||||
}
|
||||
|
||||
_trigger() {
|
||||
for (const account of this._accounts) {
|
||||
if (!account || !account.id) {
|
||||
const err = new Error("An invalid account was added to `this._accounts`")
|
||||
NylasEnv.reportError(err)
|
||||
this._accounts = _.compact(this._accounts)
|
||||
}
|
||||
}
|
||||
this.trigger()
|
||||
}
|
||||
|
||||
_save = () => {
|
||||
this._version += 1
|
||||
NylasEnv.config.set(configTokensKey, null)
|
||||
NylasEnv.config.set(configAccountsKey, this._accounts)
|
||||
NylasEnv.config.set(configVersionKey, this._version)
|
||||
this._trigger()
|
||||
}
|
||||
|
||||
// Inbound Events
|
||||
|
||||
_onUpdateAccount = (id, updated) => {
|
||||
const idx = _.findIndex(this._accounts, (a) => a.id === id)
|
||||
let account = this._accounts[idx]
|
||||
if (!account) return
|
||||
account = _.extend(account, updated)
|
||||
this._caches = {}
|
||||
this._accounts[idx] = account
|
||||
this._save()
|
||||
}
|
||||
|
||||
_onRemoveAccount = (id) => {
|
||||
const account = _.findWhere(this._accounts, {id})
|
||||
if (!account) return
|
||||
keytar.deletePassword(keytarServiceName, account.emailAddress)
|
||||
|
||||
this._caches = {}
|
||||
|
||||
const remainingAccounts = _.without(this._accounts, account)
|
||||
// This action is called before saving because we need to unfocus the
|
||||
// perspective of the account that is being removed before removing the
|
||||
// account, otherwise when we trigger with the new set of accounts, the
|
||||
// current perspective will still reference a stale accountId which will
|
||||
// cause things to break
|
||||
Actions.focusDefaultMailboxPerspectiveForAccounts(remainingAccounts)
|
||||
_.defer(() => {
|
||||
Actions.setCollapsedSidebarItem('Inbox', true)
|
||||
})
|
||||
|
||||
this._accounts = remainingAccounts
|
||||
this._save()
|
||||
|
||||
if (remainingAccounts.length === 0) {
|
||||
const ipc = require('electron').ipcRenderer
|
||||
ipc.send('command', 'application:relaunch-to-initial-windows', {
|
||||
resetDatabase: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
_onReorderAccount = (id, newIdx) => {
|
||||
const existingIdx = _.findIndex(this._accounts, (a) => a.id === id)
|
||||
if (existingIdx === -1) return
|
||||
const account = this._accounts[existingIdx]
|
||||
this._caches = {}
|
||||
this._accounts.splice(existingIdx, 1)
|
||||
this._accounts.splice(newIdx, 0, account)
|
||||
this._save()
|
||||
}
|
||||
|
||||
addAccountFromJSON = (json, localToken, cloudToken) => {
|
||||
if (!json.email_address || !json.provider) {
|
||||
console.error("Returned account data is invalid", json)
|
||||
console.log(JSON.stringify(json))
|
||||
throw new Error("Returned account data is invalid")
|
||||
}
|
||||
|
||||
this._loadAccounts()
|
||||
|
||||
this._tokens[json.id] = {
|
||||
n1Cloud: cloudToken,
|
||||
localSync: localToken,
|
||||
}
|
||||
keytar.replacePassword(keytarServiceName, `${json.email_address}.n1Cloud`, cloudToken)
|
||||
keytar.replacePassword(keytarServiceName, `${json.email_address}.localSync`, localToken)
|
||||
|
||||
const existingIdx = _.findIndex(this._accounts, (a) =>
|
||||
a.id === json.id || a.emailAddress === json.email_address
|
||||
)
|
||||
|
||||
if (existingIdx === -1) {
|
||||
const account = (new Account()).fromJSON(json)
|
||||
this._accounts.push(account)
|
||||
} else {
|
||||
const account = this._accounts[existingIdx]
|
||||
account.fromJSON(json)
|
||||
}
|
||||
|
||||
this._save()
|
||||
}
|
||||
|
||||
refreshHealthOfAccounts = (accountIds) => {
|
||||
NylasAPI = require('../nylas-api').default
|
||||
NylasAPIRequest = require('../nylas-api-request').default
|
||||
Promise.all(accountIds.map((accountId) => {
|
||||
return new NylasAPIRequest({
|
||||
api: NylasAPI,
|
||||
options: {
|
||||
path: '/account',
|
||||
accountId: accountId,
|
||||
},
|
||||
}).run().then((json) => {
|
||||
if (!json) return
|
||||
const existing = this.accountForId(accountId)
|
||||
if (!existing) return // user may have deleted
|
||||
existing.fromJSON(json)
|
||||
})
|
||||
})).finally(() => {
|
||||
this._caches = {}
|
||||
this._save()
|
||||
})
|
||||
}
|
||||
|
||||
// Exposed Data
|
||||
|
||||
// Private: Helper which caches the results of getter functions often needed
|
||||
// in the middle of React render cycles. (Performance critical!)
|
||||
|
||||
_cachedGetter(key, fn) {
|
||||
this._caches[key] = this._caches[key] || fn()
|
||||
return this._caches[key]
|
||||
}
|
||||
|
||||
// Public: Returns an {Array} of {Account} objects
|
||||
accounts = () => {
|
||||
return this._accounts
|
||||
}
|
||||
|
||||
accountIds = () => {
|
||||
return _.pluck(this._accounts, 'id')
|
||||
}
|
||||
|
||||
accountsForItems = (items) => {
|
||||
const accounts = {}
|
||||
items.forEach(({accountId}) => {
|
||||
accounts[accountId] = accounts[accountId] || this.accountForId(accountId)
|
||||
})
|
||||
return _.values(accounts)
|
||||
}
|
||||
|
||||
accountForItems = (items) => {
|
||||
const accounts = this.accountsForItems(items)
|
||||
if (accounts.length > 1) return null
|
||||
return accounts[0]
|
||||
}
|
||||
|
||||
// Public: Returns the {Account} for the given email address, or null.
|
||||
accountForEmail = (email) => {
|
||||
for (const account of this.accounts()) {
|
||||
if (Utils.emailIsEquivalent(email, account.emailAddress)) {
|
||||
return account
|
||||
}
|
||||
}
|
||||
for (const alias of this.aliases()) {
|
||||
if (Utils.emailIsEquivalent(email, alias.email)) {
|
||||
return this.accountForId(alias.accountId)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// Public: Returns the {Account} for the given account id, or null.
|
||||
accountForId(id) {
|
||||
return this._cachedGetter(`accountForId:${id}`, () => _.findWhere(this._accounts, {id}))
|
||||
}
|
||||
|
||||
emailAddresses() {
|
||||
let addresses = _.pluck((this.accounts() ? this.accounts() : []), "emailAddress")
|
||||
addresses = addresses.concat(_.pluck((this.aliases() ? this.aliases() : []), "email"))
|
||||
return _.unique(addresses)
|
||||
}
|
||||
|
||||
aliases() {
|
||||
return this._cachedGetter("aliases", () => {
|
||||
const aliases = []
|
||||
for (const acc of this._accounts) {
|
||||
aliases.push(acc.me())
|
||||
for (const alias of acc.aliases) {
|
||||
const aliasContact = acc.meUsingAlias(alias)
|
||||
aliasContact.isAlias = true
|
||||
aliases.push(aliasContact)
|
||||
}
|
||||
}
|
||||
return aliases
|
||||
})
|
||||
}
|
||||
|
||||
aliasesFor(accountsOrIds) {
|
||||
const ids = accountsOrIds.map((accOrId) => {
|
||||
return accOrId instanceof Account ? accOrId.id : accOrId
|
||||
})
|
||||
return this.aliases().filter((contact) => ids.includes(contact.accountId))
|
||||
}
|
||||
|
||||
// Public: Returns the currently active {Account}.
|
||||
current() {
|
||||
throw new Error("AccountStore.current() has been deprecated.")
|
||||
}
|
||||
|
||||
// Private: This method is going away soon, do not rely on it.
|
||||
tokensForAccountId(id) {
|
||||
return this._tokens[id]
|
||||
}
|
||||
|
||||
// Private: Load fake data from a directory for taking nice screenshots
|
||||
_importFakeData = (dir) => {
|
||||
const fs = require('fs-plus')
|
||||
const path = require('path')
|
||||
const Message = require('../models/message').default
|
||||
const Thread = require('../models/thread').default
|
||||
|
||||
this._caches = {}
|
||||
|
||||
let labels = []
|
||||
const threads = []
|
||||
let messages = []
|
||||
|
||||
let account = this.accountForEmail('nora@nylas.com')
|
||||
if (!account) {
|
||||
account = new Account()
|
||||
account.serverId = account.clientId
|
||||
account.emailAddress = "nora@nylas.com"
|
||||
account.organizationUnit = 'label'
|
||||
account.label = "Nora's Email"
|
||||
account.aliases = []
|
||||
account.name = "Nora"
|
||||
account.provider = "gmail"
|
||||
const json = account.toJSON()
|
||||
json.token = 'nope'
|
||||
this.addAccountFromJSON(json)
|
||||
}
|
||||
|
||||
const filenames = fs.readdirSync(path.join(dir, 'threads'))
|
||||
for (const filename of filenames) {
|
||||
const threadJSON = fs.readFileSync(path.join(dir, 'threads', filename))
|
||||
const threadMessages = JSON.parse(threadJSON).map((j) => (new Message()).fromJSON(j))
|
||||
let threadLabels = []
|
||||
let threadParticipants = []
|
||||
let threadAttachment = false
|
||||
let threadUnread = false
|
||||
|
||||
for (const m of threadMessages) {
|
||||
m.accountId = account.id
|
||||
for (const l of m.categories) {
|
||||
l.accountId = account.id
|
||||
}
|
||||
for (const l of m.files) {
|
||||
l.accountId = account.id
|
||||
}
|
||||
threadParticipants = threadParticipants.concat(m.participants())
|
||||
threadLabels = threadLabels.concat(m.categories)
|
||||
threadAttachment = threadAttachment || m.files.length > 0
|
||||
threadUnread = threadUnread || m.unread
|
||||
}
|
||||
|
||||
threadParticipants = _.uniq(threadParticipants, (p) => p.email)
|
||||
threadLabels = _.uniq(threadLabels, (l) => l.id)
|
||||
labels = _.uniq(labels.concat(threadLabels), (l) => l.id)
|
||||
|
||||
const lastMsg = _.last(threadMessages)
|
||||
const thread = new Thread({
|
||||
accountId: account.id,
|
||||
serverId: lastMsg.threadId,
|
||||
clientId: lastMsg.threadId,
|
||||
subject: lastMsg.subject,
|
||||
lastMessageReceivedTimestamp: lastMsg.date,
|
||||
hasAttachment: threadAttachment,
|
||||
categories: threadLabels,
|
||||
participants: threadParticipants,
|
||||
unread: threadUnread,
|
||||
snippet: lastMsg.snippet,
|
||||
starred: lastMsg.starred,
|
||||
})
|
||||
messages = messages.concat(threadMessages)
|
||||
threads.push(thread)
|
||||
}
|
||||
|
||||
const downloadsDir = path.join(dir, 'downloads')
|
||||
if (fs.existsSync(downloadsDir)) {
|
||||
for (const filename of fs.readdirSync(downloadsDir)) {
|
||||
const destPath = path.join(NylasEnv.getConfigDirPath(), 'downloads', filename)
|
||||
if (fs.existsSync(destPath)) {
|
||||
fs.removeSync(destPath)
|
||||
}
|
||||
fs.copySync(path.join(downloadsDir, filename), destPath)
|
||||
}
|
||||
}
|
||||
|
||||
DatabaseStore.inTransaction((t) =>
|
||||
Promise.all([
|
||||
t.persistModel(account),
|
||||
t.persistModels(labels),
|
||||
t.persistModels(messages),
|
||||
t.persistModels(threads),
|
||||
])
|
||||
).then(() => {
|
||||
Actions.focusDefaultMailboxPerspectiveForAccounts([account.id])
|
||||
})
|
||||
.then(() => {
|
||||
return new Promise((resolve) => setTimeout(resolve, 1000))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export default new AccountStore()
|
|
@ -1,7 +1,7 @@
|
|||
_ = require 'underscore'
|
||||
Rx = require 'rx-lite'
|
||||
NylasStore = require 'nylas-store'
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
NylasSyncStatusStore = require './nylas-sync-status-store'
|
||||
Account = require('../models/account').default
|
||||
{StandardCategoryNames} = require('../models/category').default
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Rx = require 'rx-lite'
|
||||
NylasStore = require 'nylas-store'
|
||||
DatabaseStore = require('./database-store').default
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
|
||||
class ContactRankingStore extends NylasStore
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ Utils = require '../models/utils'
|
|||
NylasStore = require 'nylas-store'
|
||||
RegExpUtils = require '../../regexp-utils'
|
||||
DatabaseStore = require('./database-store').default
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
ComponentRegistry = require('../../registries/component-registry')
|
||||
ContactRankingStore = require './contact-ranking-store'
|
||||
_ = require 'underscore'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
Message = require('../models/message').default
|
||||
Actions = require('../actions').default
|
||||
NylasAPI = require '../nylas-api'
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
ContactStore = require './contact-store'
|
||||
DatabaseStore = require('./database-store').default
|
||||
UndoStack = require('../../undo-stack').default
|
||||
|
|
|
@ -2,7 +2,7 @@ _ = require 'underscore'
|
|||
|
||||
Actions = require('../actions').default
|
||||
DatabaseStore = require('./database-store').default
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
ContactStore = require './contact-store'
|
||||
MessageStore = require './message-store'
|
||||
FocusedPerspectiveStore = require('./focused-perspective-store').default
|
||||
|
|
|
@ -7,7 +7,7 @@ NylasStore = require 'nylas-store'
|
|||
Thread = require('../models/thread').default
|
||||
Contact = require('../models/contact').default
|
||||
MessageStore = require './message-store'
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
DatabaseStore = require('./database-store').default
|
||||
FocusedContentStore = require './focused-content-store'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
_ = require 'underscore'
|
||||
Reflux = require 'reflux'
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
WorkspaceStore = require './workspace-store'
|
||||
DatabaseStore = require('./database-store').default
|
||||
FocusedPerspectiveStore = require('./focused-perspective-store').default
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
NylasStore = require 'nylas-store'
|
||||
_ = require 'underscore'
|
||||
Rx = require 'rx-lite'
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
DatabaseStore = require('./database-store').default
|
||||
TaskQueueStatusStore = require './task-queue-status-store'
|
||||
ReprocessMailRulesTask = require('../tasks/reprocess-mail-rules-task').default
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
_ = require 'underscore'
|
||||
Rx = require 'rx-lite'
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
DatabaseStore = require('./database-store').default
|
||||
NylasStore = require 'nylas-store'
|
||||
NylasObservables = require 'nylas-observables'
|
||||
|
|
|
@ -2,7 +2,7 @@ _ = require 'underscore'
|
|||
Rx = require 'rx-lite'
|
||||
NylasStore = require 'nylas-store'
|
||||
DatabaseStore = require('./database-store').default
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
TaskQueue = require './task-queue'
|
||||
|
||||
# Public: The TaskQueueStatusStore allows you to inspect the task queue from
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
_ = require 'underscore'
|
||||
Actions = require('../actions').default
|
||||
AccountStore = require './account-store'
|
||||
AccountStore = require('./account-store').default
|
||||
CategoryStore = require './category-store'
|
||||
MailboxPerspective = require '../../mailbox-perspective'
|
||||
NylasStore = require 'nylas-store'
|
||||
|
|
|
@ -2,7 +2,7 @@ _ = require 'underscore'
|
|||
|
||||
Utils = require './flux/models/utils'
|
||||
TaskFactory = require('./flux/tasks/task-factory').default
|
||||
AccountStore = require './flux/stores/account-store'
|
||||
AccountStore = require('./flux/stores/account-store').default
|
||||
CategoryStore = require './flux/stores/category-store'
|
||||
DatabaseStore = require('./flux/stores/database-store').default
|
||||
OutboxStore = require('./flux/stores/outbox-store').default
|
||||
|
|
Loading…
Reference in a new issue