mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-21 12:05:47 +08:00
feat(babel6): Convert message.coffee to message.es6
This commit is contained in:
parent
4b6433a8cb
commit
8f4e30329c
21 changed files with 387 additions and 329 deletions
|
@ -1,6 +1,6 @@
|
||||||
_ = require 'underscore'
|
_ = require 'underscore'
|
||||||
Contact = require '../../../src/flux/models/contact'
|
Contact = require '../../../src/flux/models/contact'
|
||||||
Message = require '../../../src/flux/models/message'
|
Message = require('../../../src/flux/models/message').default
|
||||||
Thread = require('../../../src/flux/models/thread').default
|
Thread = require('../../../src/flux/models/thread').default
|
||||||
Category = require '../../../src/flux/models/category'
|
Category = require '../../../src/flux/models/category'
|
||||||
CategoryStore = require '../../../src/flux/stores/category-store'
|
CategoryStore = require '../../../src/flux/stores/category-store'
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
Reflux = require 'reflux'
|
Reflux = require 'reflux'
|
||||||
Actions = require '../src/flux/actions'
|
Actions = require '../src/flux/actions'
|
||||||
Message = require '../src/flux/models/message'
|
Message = require('../src/flux/models/message').default
|
||||||
DatabaseStore = require '../src/flux/stores/database-store'
|
DatabaseStore = require '../src/flux/stores/database-store'
|
||||||
AccountStore = require '../src/flux/stores/account-store'
|
AccountStore = require '../src/flux/stores/account-store'
|
||||||
ActionBridge = require '../src/flux/action-bridge',
|
ActionBridge = require '../src/flux/action-bridge',
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
Utils = require "../../src/flux/models/utils"
|
Utils = require "../../src/flux/models/utils"
|
||||||
Message = require "../../src/flux/models/message"
|
Message = require("../../src/flux/models/message").default
|
||||||
Contact = require "../../src/flux/models/contact"
|
Contact = require "../../src/flux/models/contact"
|
||||||
|
|
||||||
evan = new Contact
|
evan = new Contact
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
ModelQuery = require '../../src/flux/models/query'
|
ModelQuery = require '../../src/flux/models/query'
|
||||||
{Matcher} = require '../../src/flux/attributes'
|
{Matcher} = require '../../src/flux/attributes'
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
Thread = require('../../src/flux/models/thread').default
|
Thread = require('../../src/flux/models/thread').default
|
||||||
Account = require('../../src/flux/models/account').default
|
Account = require('../../src/flux/models/account').default
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
Thread = require('../../src/flux/models/thread').default
|
Thread = require('../../src/flux/models/thread').default
|
||||||
Category = require '../../src/flux/models/category'
|
Category = require '../../src/flux/models/category'
|
||||||
{Utils} = require 'nylas-exports'
|
{Utils} = require 'nylas-exports'
|
||||||
|
|
|
@ -3,7 +3,7 @@ fs = require 'fs'
|
||||||
Actions = require '../src/flux/actions'
|
Actions = require '../src/flux/actions'
|
||||||
NylasAPI = require '../src/flux/nylas-api'
|
NylasAPI = require '../src/flux/nylas-api'
|
||||||
Thread = require('../src/flux/models/thread').default
|
Thread = require('../src/flux/models/thread').default
|
||||||
Message = require '../src/flux/models/message'
|
Message = require('../src/flux/models/message').default
|
||||||
AccountStore = require '../src/flux/stores/account-store'
|
AccountStore = require '../src/flux/stores/account-store'
|
||||||
DatabaseStore = require '../src/flux/stores/database-store'
|
DatabaseStore = require '../src/flux/stores/database-store'
|
||||||
DatabaseTransaction = require '../src/flux/stores/database-transaction'
|
DatabaseTransaction = require '../src/flux/stores/database-transaction'
|
||||||
|
@ -247,7 +247,7 @@ describe "NylasAPI", ->
|
||||||
expect(models[0].id).toBe 'b'
|
expect(models[0].id).toBe 'b'
|
||||||
|
|
||||||
describe "when updating models", ->
|
describe "when updating models", ->
|
||||||
Message = require '../src/flux/models/message'
|
Message = require('../src/flux/models/message').default
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@json = [
|
@json = [
|
||||||
{id: 'a', object: 'draft', unread: true}
|
{id: 'a', object: 'draft', unread: true}
|
||||||
|
@ -305,9 +305,9 @@ describe "NylasAPI", ->
|
||||||
"label": require('../src/flux/models/label')
|
"label": require('../src/flux/models/label')
|
||||||
"folder": require('../src/flux/models/folder')
|
"folder": require('../src/flux/models/folder')
|
||||||
"thread": require('../src/flux/models/thread').default
|
"thread": require('../src/flux/models/thread').default
|
||||||
"draft": require('../src/flux/models/message')
|
"draft": require('../src/flux/models/message').default
|
||||||
"account": require('../src/flux/models/account').default
|
"account": require('../src/flux/models/account').default
|
||||||
"message": require('../src/flux/models/message')
|
"message": require('../src/flux/models/message').default
|
||||||
"contact": require('../src/flux/models/contact')
|
"contact": require('../src/flux/models/contact')
|
||||||
"calendar": require('../src/flux/models/calendar')
|
"calendar": require('../src/flux/models/calendar')
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
Actions = require '../../src/flux/actions'
|
Actions = require '../../src/flux/actions'
|
||||||
DatabaseStore = require '../../src/flux/stores/database-store'
|
DatabaseStore = require '../../src/flux/stores/database-store'
|
||||||
DatabaseTransaction = require '../../src/flux/stores/database-transaction'
|
DatabaseTransaction = require '../../src/flux/stores/database-transaction'
|
||||||
|
|
|
@ -3,7 +3,7 @@ path = require 'path'
|
||||||
{shell} = require 'electron'
|
{shell} = require 'electron'
|
||||||
NylasAPI = require '../../src/flux/nylas-api'
|
NylasAPI = require '../../src/flux/nylas-api'
|
||||||
File = require '../../src/flux/models/file'
|
File = require '../../src/flux/models/file'
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
FileDownloadStore = require '../../src/flux/stores/file-download-store'
|
FileDownloadStore = require '../../src/flux/stores/file-download-store'
|
||||||
AccountStore = require '../../src/flux/stores/account-store'
|
AccountStore = require '../../src/flux/stores/account-store'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
_ = require 'underscore'
|
_ = require 'underscore'
|
||||||
Thread = require('../../src/flux/models/thread').default
|
Thread = require('../../src/flux/models/thread').default
|
||||||
Category = require '../../src/flux/models/category'
|
Category = require '../../src/flux/models/category'
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
FocusedContentStore = require '../../src/flux/stores/focused-content-store'
|
FocusedContentStore = require '../../src/flux/stores/focused-content-store'
|
||||||
FocusedPerspectiveStore = require '../../src/flux/stores/focused-perspective-store'
|
FocusedPerspectiveStore = require '../../src/flux/stores/focused-perspective-store'
|
||||||
MessageStore = require '../../src/flux/stores/message-store'
|
MessageStore = require '../../src/flux/stores/message-store'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
_ = require 'underscore'
|
_ = require 'underscore'
|
||||||
Folder = require '../../src/flux/models/folder'
|
Folder = require '../../src/flux/models/folder'
|
||||||
Thread = require('../../src/flux/models/thread').default
|
Thread = require('../../src/flux/models/thread').default
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
Actions = require '../../src/flux/actions'
|
Actions = require '../../src/flux/actions'
|
||||||
NylasAPI = require '../../src/flux/nylas-api'
|
NylasAPI = require '../../src/flux/nylas-api'
|
||||||
Query = require '../../src/flux/models/query'
|
Query = require '../../src/flux/models/query'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
_ = require 'underscore'
|
_ = require 'underscore'
|
||||||
Label = require '../../src/flux/models/label'
|
Label = require '../../src/flux/models/label'
|
||||||
Thread = require('../../src/flux/models/thread').default
|
Thread = require('../../src/flux/models/thread').default
|
||||||
Message = require '../../src/flux/models/message'
|
Message = require('../../src/flux/models/message').default
|
||||||
Actions = require '../../src/flux/actions'
|
Actions = require '../../src/flux/actions'
|
||||||
NylasAPI = require '../../src/flux/nylas-api'
|
NylasAPI = require '../../src/flux/nylas-api'
|
||||||
DatabaseStore = require '../../src/flux/stores/database-store'
|
DatabaseStore = require '../../src/flux/stores/database-store'
|
||||||
|
|
|
@ -1,305 +0,0 @@
|
||||||
_ = require 'underscore'
|
|
||||||
moment = require 'moment'
|
|
||||||
|
|
||||||
File = require './file'
|
|
||||||
Utils = require './utils'
|
|
||||||
Event = require './event'
|
|
||||||
Category = require './category'
|
|
||||||
Contact = require './contact'
|
|
||||||
Attributes = require '../attributes'
|
|
||||||
AccountStore = require '../stores/account-store'
|
|
||||||
ModelWithMetadata = require('./model-with-metadata').default
|
|
||||||
|
|
||||||
###
|
|
||||||
Public: The Message model represents a Message object served by the Nylas Platform API.
|
|
||||||
For more information about Messages on the Nylas Platform, read the
|
|
||||||
[Messages API Documentation](https://nylas.com/docs/api#messages)
|
|
||||||
|
|
||||||
Messages are a sub-object of threads. The content of a message is immutable (with the
|
|
||||||
exception being drafts). Nylas does not support operations such as move or delete on
|
|
||||||
individual messages; those operations should be performed on the message’s thread.
|
|
||||||
All messages are part of a thread, even if that thread has only one message.
|
|
||||||
|
|
||||||
## Attributes
|
|
||||||
|
|
||||||
`to`: {AttributeCollection} A collection of {Contact} objects
|
|
||||||
|
|
||||||
`cc`: {AttributeCollection} A collection of {Contact} objects
|
|
||||||
|
|
||||||
`bcc`: {AttributeCollection} A collection of {Contact} objects
|
|
||||||
|
|
||||||
`from`: {AttributeCollection} A collection of {Contact} objects.
|
|
||||||
|
|
||||||
`replyTo`: {AttributeCollection} A collection of {Contact} objects.
|
|
||||||
|
|
||||||
`date`: {AttributeDateTime} When the message was delivered. Queryable.
|
|
||||||
|
|
||||||
`subject`: {AttributeString} The subject of the thread. Queryable.
|
|
||||||
|
|
||||||
`snippet`: {AttributeString} A short, 140-character plain-text summary of the message body.
|
|
||||||
|
|
||||||
`unread`: {AttributeBoolean} True if the message is unread. Queryable.
|
|
||||||
|
|
||||||
`starred`: {AttributeBoolean} True if the message is starred. Queryable.
|
|
||||||
|
|
||||||
`draft`: {AttributeBoolean} True if the message is a draft. Queryable.
|
|
||||||
|
|
||||||
`version`: {AttributeNumber} The version number of the message. Message
|
|
||||||
versions are used for drafts, and increment when attributes are changed.
|
|
||||||
|
|
||||||
`files`: {AttributeCollection} A set of {File} models representing
|
|
||||||
the attachments on this thread.
|
|
||||||
|
|
||||||
`body`: {AttributeJoinedData} The HTML body of the message. You must specifically
|
|
||||||
request this attribute when querying for a Message using the {{AttributeJoinedData::include}}
|
|
||||||
method.
|
|
||||||
|
|
||||||
`pristine`: {AttributeBoolean} True if the message is a draft which has not been
|
|
||||||
edited since it was created.
|
|
||||||
|
|
||||||
`threadId`: {AttributeString} The ID of the Message's parent {Thread}. Queryable.
|
|
||||||
|
|
||||||
`replyToMessageId`: {AttributeString} The ID of a {Message} that this message
|
|
||||||
is in reply to.
|
|
||||||
|
|
||||||
This class also inherits attributes from {Model}
|
|
||||||
|
|
||||||
Section: Models
|
|
||||||
###
|
|
||||||
class Message extends ModelWithMetadata
|
|
||||||
|
|
||||||
@attributes: _.extend {}, ModelWithMetadata.attributes,
|
|
||||||
|
|
||||||
'to': Attributes.Collection
|
|
||||||
modelKey: 'to'
|
|
||||||
itemClass: Contact
|
|
||||||
|
|
||||||
'cc': Attributes.Collection
|
|
||||||
modelKey: 'cc'
|
|
||||||
itemClass: Contact
|
|
||||||
|
|
||||||
'bcc': Attributes.Collection
|
|
||||||
modelKey: 'bcc'
|
|
||||||
itemClass: Contact
|
|
||||||
|
|
||||||
'from': Attributes.Collection
|
|
||||||
modelKey: 'from'
|
|
||||||
itemClass: Contact
|
|
||||||
|
|
||||||
'replyTo': Attributes.Collection
|
|
||||||
modelKey: 'replyTo'
|
|
||||||
jsonKey: 'reply_to'
|
|
||||||
itemClass: Contact
|
|
||||||
|
|
||||||
'date': Attributes.DateTime
|
|
||||||
queryable: true
|
|
||||||
modelKey: 'date'
|
|
||||||
|
|
||||||
'body': Attributes.JoinedData
|
|
||||||
modelTable: 'MessageBody'
|
|
||||||
modelKey: 'body'
|
|
||||||
|
|
||||||
'files': Attributes.Collection
|
|
||||||
modelKey: 'files'
|
|
||||||
itemClass: File
|
|
||||||
|
|
||||||
'uploads': Attributes.Object
|
|
||||||
queryable: false
|
|
||||||
modelKey: 'uploads'
|
|
||||||
|
|
||||||
'unread': Attributes.Boolean
|
|
||||||
queryable: true
|
|
||||||
modelKey: 'unread'
|
|
||||||
|
|
||||||
'events': Attributes.Collection
|
|
||||||
modelKey: 'events'
|
|
||||||
itemClass: Event
|
|
||||||
|
|
||||||
'starred': Attributes.Boolean
|
|
||||||
queryable: true
|
|
||||||
modelKey: 'starred'
|
|
||||||
|
|
||||||
'snippet': Attributes.String
|
|
||||||
modelKey: 'snippet'
|
|
||||||
|
|
||||||
'threadId': Attributes.ServerId
|
|
||||||
queryable: true
|
|
||||||
modelKey: 'threadId'
|
|
||||||
jsonKey: 'thread_id'
|
|
||||||
|
|
||||||
'subject': Attributes.String
|
|
||||||
modelKey: 'subject'
|
|
||||||
|
|
||||||
'draft': Attributes.Boolean
|
|
||||||
modelKey: 'draft'
|
|
||||||
jsonKey: 'draft'
|
|
||||||
queryable: true
|
|
||||||
|
|
||||||
'pristine': Attributes.Boolean
|
|
||||||
modelKey: 'pristine'
|
|
||||||
jsonKey: 'pristine'
|
|
||||||
queryable: false
|
|
||||||
|
|
||||||
'version': Attributes.Number
|
|
||||||
modelKey: 'version'
|
|
||||||
queryable: true
|
|
||||||
|
|
||||||
'replyToMessageId': Attributes.ServerId
|
|
||||||
modelKey: 'replyToMessageId'
|
|
||||||
jsonKey: 'reply_to_message_id'
|
|
||||||
|
|
||||||
'categories': Attributes.Collection
|
|
||||||
modelKey: 'categories'
|
|
||||||
itemClass: Category
|
|
||||||
|
|
||||||
@naturalSortOrder: ->
|
|
||||||
Message.attributes.date.ascending()
|
|
||||||
|
|
||||||
@additionalSQLiteConfig:
|
|
||||||
setup: ->
|
|
||||||
[
|
|
||||||
# For thread view
|
|
||||||
'CREATE INDEX IF NOT EXISTS MessageListThreadIndex ON Message(thread_id, date ASC)',
|
|
||||||
|
|
||||||
# For draft lookups
|
|
||||||
'CREATE UNIQUE INDEX IF NOT EXISTS MessageDraftIndex ON Message(client_id)',
|
|
||||||
|
|
||||||
# Partial indexes for draft
|
|
||||||
'CREATE INDEX IF NOT EXISTS MessageListDraftIndex ON Message(account_id, date DESC) WHERE draft = 1',
|
|
||||||
'CREATE INDEX IF NOT EXISTS MessageListUnifiedDraftIndex ON Message(date DESC) WHERE draft = 1',
|
|
||||||
|
|
||||||
# MessageBody lookups
|
|
||||||
'CREATE UNIQUE INDEX IF NOT EXISTS MessageBodyIndex ON MessageBody(id)'
|
|
||||||
]
|
|
||||||
|
|
||||||
constructor: ->
|
|
||||||
super
|
|
||||||
@subject ||= ""
|
|
||||||
@to ||= []
|
|
||||||
@cc ||= []
|
|
||||||
@bcc ||= []
|
|
||||||
@from ||= []
|
|
||||||
@replyTo ||= []
|
|
||||||
@files ||= []
|
|
||||||
@uploads ||= []
|
|
||||||
@events ||= []
|
|
||||||
@categories ||= []
|
|
||||||
@
|
|
||||||
|
|
||||||
toJSON: (options) ->
|
|
||||||
json = super(options)
|
|
||||||
json.file_ids = @fileIds()
|
|
||||||
json.object = 'draft' if @draft
|
|
||||||
json.event_id = @events[0].serverId if (@events and @events.length)
|
|
||||||
json
|
|
||||||
|
|
||||||
fromJSON: (json={}) ->
|
|
||||||
super (json)
|
|
||||||
|
|
||||||
# Only change the `draft` bit if the incoming json has an `object`
|
|
||||||
# property. Because of `DraftChangeSet`, it's common for incoming json
|
|
||||||
# to be an empty hash. In this case we want to leave the pre-existing
|
|
||||||
# draft bit alone.
|
|
||||||
if json.object?
|
|
||||||
@draft = (json.object is 'draft')
|
|
||||||
|
|
||||||
if json['folder']
|
|
||||||
@categories = @constructor.attributes.categories.fromJSON([json['folder']])
|
|
||||||
else if json['labels']
|
|
||||||
@categories = @constructor.attributes.categories.fromJSON(json['labels'])
|
|
||||||
|
|
||||||
for attr in ['to', 'from', 'cc', 'bcc', 'files', 'categories']
|
|
||||||
values = @[attr]
|
|
||||||
continue unless values and values instanceof Array
|
|
||||||
item.accountId = @accountId for item in values
|
|
||||||
|
|
||||||
return @
|
|
||||||
|
|
||||||
canReplyAll: ->
|
|
||||||
{to, cc} = @participantsForReplyAll()
|
|
||||||
to.length > 1 or cc.length > 0
|
|
||||||
|
|
||||||
# Public: Returns a set of uniqued message participants by combining the
|
|
||||||
# `to`, `cc`, and `from` fields.
|
|
||||||
participants: ->
|
|
||||||
seen = {}
|
|
||||||
all = []
|
|
||||||
for contact in [].concat(@to, @cc, @from)
|
|
||||||
continue unless contact.email
|
|
||||||
key = contact.toString().trim().toLowerCase()
|
|
||||||
continue if seen[key]
|
|
||||||
seen[key] = true
|
|
||||||
all.push(contact)
|
|
||||||
all
|
|
||||||
|
|
||||||
# Public: Returns a hash with `to` and `cc` keys for authoring a new draft in
|
|
||||||
# "reply all" to this message. This method takes into account whether the
|
|
||||||
# message is from the current user, and also looks at the replyTo field.
|
|
||||||
participantsForReplyAll: ->
|
|
||||||
excludedFroms = @from.map (c) -> Utils.toEquivalentEmailForm(c.email)
|
|
||||||
excludeMeAndFroms = (cc) ->
|
|
||||||
_.reject cc, (p) ->
|
|
||||||
p.isMe() or _.contains(excludedFroms, Utils.toEquivalentEmailForm(p.email))
|
|
||||||
|
|
||||||
to = null
|
|
||||||
cc = null
|
|
||||||
|
|
||||||
if @isFromMe()
|
|
||||||
to = @to
|
|
||||||
cc = excludeMeAndFroms(@cc)
|
|
||||||
else
|
|
||||||
if @replyTo.length
|
|
||||||
to = @replyTo
|
|
||||||
else
|
|
||||||
to = @from
|
|
||||||
cc = excludeMeAndFroms([].concat(@to, @cc))
|
|
||||||
|
|
||||||
to = _.uniq to, (p) -> Utils.toEquivalentEmailForm(p.email)
|
|
||||||
cc = _.uniq cc, (p) -> Utils.toEquivalentEmailForm(p.email)
|
|
||||||
{to, cc}
|
|
||||||
|
|
||||||
# Public: Returns a hash with `to` and `cc` keys for authoring a new draft in
|
|
||||||
# "reply" to this message. This method takes into account whether the
|
|
||||||
# message is from the current user, and also looks at the replyTo field.
|
|
||||||
participantsForReply: ->
|
|
||||||
to = []
|
|
||||||
cc = []
|
|
||||||
|
|
||||||
if @isFromMe()
|
|
||||||
to = @to
|
|
||||||
else if @replyTo.length
|
|
||||||
to = @replyTo
|
|
||||||
else
|
|
||||||
to = @from
|
|
||||||
|
|
||||||
to = _.uniq to, (p) -> Utils.toEquivalentEmailForm(p.email)
|
|
||||||
{to, cc}
|
|
||||||
|
|
||||||
# Public: Returns an {Array} of {File} IDs
|
|
||||||
fileIds: ->
|
|
||||||
_.map @files, (file) -> file.id
|
|
||||||
|
|
||||||
# Public: Returns true if this message is from the current user's email
|
|
||||||
# address. In the future, this method will take into account all of the
|
|
||||||
# user's email addresses and accounts.
|
|
||||||
isFromMe: ->
|
|
||||||
@from[0]?.isMe()
|
|
||||||
|
|
||||||
# Public: Returns a plaintext version of the message body using Chromium's
|
|
||||||
# DOMParser. Use with care.
|
|
||||||
plainTextBody: ->
|
|
||||||
if (@body ? "").trim().length is 0 then return ""
|
|
||||||
(new DOMParser()).parseFromString(@body, "text/html").body.innerText
|
|
||||||
|
|
||||||
fromContact: ->
|
|
||||||
@from?[0] ? new Contact(name: 'Unknown', email: 'Unknown')
|
|
||||||
|
|
||||||
# Public: Returns the standard attribution line for this message,
|
|
||||||
# localized for the current user.
|
|
||||||
# ie "On Dec. 12th, 2015 at 4:00PM, Ben Gotow wrote:"
|
|
||||||
replyAttributionLine: ->
|
|
||||||
"On #{@formattedDate()}, #{@fromContact().toString()} wrote:"
|
|
||||||
|
|
||||||
formattedDate: -> moment(@date).format("MMM D YYYY, [at] h:mm a")
|
|
||||||
|
|
||||||
module.exports = Message
|
|
363
src/flux/models/message.es6
Normal file
363
src/flux/models/message.es6
Normal file
|
@ -0,0 +1,363 @@
|
||||||
|
import _ from 'underscore'
|
||||||
|
import moment from 'moment'
|
||||||
|
|
||||||
|
import File from './file'
|
||||||
|
import Utils from './utils'
|
||||||
|
import Event from './event'
|
||||||
|
import Category from './category'
|
||||||
|
import Contact from './contact'
|
||||||
|
import Attributes from '../attributes'
|
||||||
|
import ModelWithMetadata from './model-with-metadata'
|
||||||
|
|
||||||
|
/**
|
||||||
|
Public: The Message model represents a Message object served by the Nylas Platform API.
|
||||||
|
For more information about Messages on the Nylas Platform, read the
|
||||||
|
[Messages API Documentation](https://nylas.com/docs/api#messages)
|
||||||
|
|
||||||
|
Messages are a sub-object of threads. The content of a message === immutable (with the
|
||||||
|
exception being drafts). Nylas does not support operations such as move || delete on
|
||||||
|
individual messages; those operations should be performed on the message’s thread.
|
||||||
|
All messages are part of a thread, even if that thread has only one message.
|
||||||
|
|
||||||
|
## Attributes
|
||||||
|
|
||||||
|
`to`: {AttributeCollection} A collection of {Contact} objects
|
||||||
|
|
||||||
|
`cc`: {AttributeCollection} A collection of {Contact} objects
|
||||||
|
|
||||||
|
`bcc`: {AttributeCollection} A collection of {Contact} objects
|
||||||
|
|
||||||
|
`from`: {AttributeCollection} A collection of {Contact} objects.
|
||||||
|
|
||||||
|
`replyTo`: {AttributeCollection} A collection of {Contact} objects.
|
||||||
|
|
||||||
|
`date`: {AttributeDateTime} When the message was delivered. Queryable.
|
||||||
|
|
||||||
|
`subject`: {AttributeString} The subject of the thread. Queryable.
|
||||||
|
|
||||||
|
`snippet`: {AttributeString} A short, 140-character plain-text summary of the message body.
|
||||||
|
|
||||||
|
`unread`: {AttributeBoolean} True if the message === unread. Queryable.
|
||||||
|
|
||||||
|
`starred`: {AttributeBoolean} True if the message === starred. Queryable.
|
||||||
|
|
||||||
|
`draft`: {AttributeBoolean} True if the message === a draft. Queryable.
|
||||||
|
|
||||||
|
`version`: {AttributeNumber} The version number of the message. Message
|
||||||
|
versions are used for drafts, && increment when attributes are changed.
|
||||||
|
|
||||||
|
`files`: {AttributeCollection} A set of {File} models representing
|
||||||
|
the attachments on this thread.
|
||||||
|
|
||||||
|
`body`: {AttributeJoinedData} The HTML body of the message. You must specifically
|
||||||
|
request this attribute when querying for a Message using the {{AttributeJoinedData::include}}
|
||||||
|
method.
|
||||||
|
|
||||||
|
`pristine`: {AttributeBoolean} True if the message === a draft which has not been
|
||||||
|
edited since it was created.
|
||||||
|
|
||||||
|
`threadId`: {AttributeString} The ID of the Message's parent {Thread}. Queryable.
|
||||||
|
|
||||||
|
`replyToMessageId`: {AttributeString} The ID of a {Message} that this message
|
||||||
|
=== in reply to.
|
||||||
|
|
||||||
|
This class also inherits attributes from {Model}
|
||||||
|
|
||||||
|
Section: Models
|
||||||
|
*/
|
||||||
|
export default class Message extends ModelWithMetadata {
|
||||||
|
|
||||||
|
static attributes = Object.assign({}, ModelWithMetadata.attributes, {
|
||||||
|
to: Attributes.Collection({
|
||||||
|
modelKey: 'to',
|
||||||
|
itemClass: Contact,
|
||||||
|
}),
|
||||||
|
|
||||||
|
cc: Attributes.Collection({
|
||||||
|
modelKey: 'cc',
|
||||||
|
itemClass: Contact,
|
||||||
|
}),
|
||||||
|
|
||||||
|
bcc: Attributes.Collection({
|
||||||
|
modelKey: 'bcc',
|
||||||
|
itemClass: Contact,
|
||||||
|
}),
|
||||||
|
|
||||||
|
from: Attributes.Collection({
|
||||||
|
modelKey: 'from',
|
||||||
|
itemClass: Contact,
|
||||||
|
}),
|
||||||
|
|
||||||
|
replyTo: Attributes.Collection({
|
||||||
|
modelKey: 'replyTo',
|
||||||
|
jsonKey: 'reply_to',
|
||||||
|
itemClass: Contact,
|
||||||
|
}),
|
||||||
|
|
||||||
|
date: Attributes.DateTime({
|
||||||
|
queryable: true,
|
||||||
|
modelKey: 'date',
|
||||||
|
}),
|
||||||
|
|
||||||
|
body: Attributes.JoinedData({
|
||||||
|
modelTable: 'MessageBody',
|
||||||
|
modelKey: 'body',
|
||||||
|
}),
|
||||||
|
|
||||||
|
files: Attributes.Collection({
|
||||||
|
modelKey: 'files',
|
||||||
|
itemClass: File,
|
||||||
|
}),
|
||||||
|
|
||||||
|
uploads: Attributes.Object({
|
||||||
|
queryable: false,
|
||||||
|
modelKey: 'uploads',
|
||||||
|
}),
|
||||||
|
|
||||||
|
unread: Attributes.Boolean({
|
||||||
|
queryable: true,
|
||||||
|
modelKey: 'unread',
|
||||||
|
}),
|
||||||
|
|
||||||
|
events: Attributes.Collection({
|
||||||
|
modelKey: 'events',
|
||||||
|
itemClass: Event,
|
||||||
|
}),
|
||||||
|
|
||||||
|
starred: Attributes.Boolean({
|
||||||
|
queryable: true,
|
||||||
|
modelKey: 'starred',
|
||||||
|
}),
|
||||||
|
|
||||||
|
snippet: Attributes.String({
|
||||||
|
modelKey: 'snippet',
|
||||||
|
}),
|
||||||
|
|
||||||
|
threadId: Attributes.ServerId({
|
||||||
|
queryable: true,
|
||||||
|
modelKey: 'threadId',
|
||||||
|
jsonKey: 'thread_id',
|
||||||
|
}),
|
||||||
|
|
||||||
|
subject: Attributes.String({
|
||||||
|
modelKey: 'subject',
|
||||||
|
}),
|
||||||
|
|
||||||
|
draft: Attributes.Boolean({
|
||||||
|
modelKey: 'draft',
|
||||||
|
jsonKey: 'draft',
|
||||||
|
queryable: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
pristine: Attributes.Boolean({
|
||||||
|
modelKey: 'pristine',
|
||||||
|
jsonKey: 'pristine',
|
||||||
|
queryable: false,
|
||||||
|
}),
|
||||||
|
|
||||||
|
version: Attributes.Number({
|
||||||
|
modelKey: 'version',
|
||||||
|
queryable: true,
|
||||||
|
}),
|
||||||
|
|
||||||
|
replyToMessageId: Attributes.ServerId({
|
||||||
|
modelKey: 'replyToMessageId',
|
||||||
|
jsonKey: 'reply_to_message_id',
|
||||||
|
}),
|
||||||
|
|
||||||
|
categories: Attributes.Collection({
|
||||||
|
modelKey: 'categories',
|
||||||
|
itemClass: Category,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
static naturalSortOrder() {
|
||||||
|
Message.attributes.date.ascending()
|
||||||
|
}
|
||||||
|
|
||||||
|
static additionalSQLiteConfig() {
|
||||||
|
return {
|
||||||
|
setup: () =>
|
||||||
|
[
|
||||||
|
`CREATE INDEX IF NOT EXISTS MessageListThreadIndex ON Message(thread_id, date ASC)`,
|
||||||
|
`CREATE UNIQUE INDEX IF NOT EXISTS MessageDraftIndex ON Message(client_id)`,
|
||||||
|
`CREATE INDEX IF NOT EXISTS MessageListDraftIndex ON \
|
||||||
|
Message(account_id, date DESC) WHERE draft = 1`,
|
||||||
|
`CREATE INDEX IF NOT EXISTS MessageListUnifiedDraftIndex ON \
|
||||||
|
Message(date DESC) WHERE draft = 1`,
|
||||||
|
`CREATE UNIQUE INDEX IF NOT EXISTS MessageBodyIndex ON MessageBody(id)`,
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.subject = this.subject || ""
|
||||||
|
this.to = this.to || []
|
||||||
|
this.cc = this.cc || []
|
||||||
|
this.bcc = this.bcc || []
|
||||||
|
this.from = this.from || []
|
||||||
|
this.replyTo = this.replyTo || []
|
||||||
|
this.files = this.files || []
|
||||||
|
this.uploads = this.uploads || []
|
||||||
|
this.events = this.events || []
|
||||||
|
this.categories = this.categories || []
|
||||||
|
}
|
||||||
|
|
||||||
|
toJSON(options) {
|
||||||
|
const json = super.toJSON(options)
|
||||||
|
json.file_ids = this.fileIds()
|
||||||
|
if (this.draft) {
|
||||||
|
json.object = 'draft'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.events && this.events.length) {
|
||||||
|
json.event_id = this.events[0].serverId
|
||||||
|
}
|
||||||
|
|
||||||
|
return json
|
||||||
|
}
|
||||||
|
|
||||||
|
fromJSON(json = {}) {
|
||||||
|
super.fromJSON(json)
|
||||||
|
|
||||||
|
// Only change the `draft` bit if the incoming json has an `object`
|
||||||
|
// property. Because of `DraftChangeSet`, it's common for incoming json
|
||||||
|
// to be an empty hash. In this case we want to leave the pre-existing
|
||||||
|
// draft bit alone.
|
||||||
|
if (json.object) {
|
||||||
|
this.draft = (json.object === 'draft')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.folder) {
|
||||||
|
this.categories = this.constructor.attributes.categories.fromJSON([json.folder])
|
||||||
|
} else if (json.labels) {
|
||||||
|
this.categories = this.constructor.attributes.categories.fromJSON(json.labels)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const attr of ['to', 'from', 'cc', 'bcc', 'files', 'categories']) {
|
||||||
|
const values = this[attr]
|
||||||
|
if (!(values && values instanceof Array)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (const item of values) {
|
||||||
|
item.accountId = this.accountId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
canReplyAll() {
|
||||||
|
const {to, cc} = this.participantsForReplyAll()
|
||||||
|
return to.length > 1 || cc.length > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns a set of uniqued message participants by combining the
|
||||||
|
// `to`, `cc`, && `from` fields.
|
||||||
|
participants() {
|
||||||
|
const seen = {}
|
||||||
|
const all = []
|
||||||
|
for (const contact of [].concat(this.to, this.cc, this.from)) {
|
||||||
|
if (!contact.email) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
const key = contact.toString().trim().toLowerCase()
|
||||||
|
if (seen[key]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
seen[key] = true
|
||||||
|
all.push(contact)
|
||||||
|
}
|
||||||
|
return all
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns a hash with `to` && `cc` keys for authoring a new draft in
|
||||||
|
// "reply all" to this message. This method takes into account whether the
|
||||||
|
// message === from the current user, && also looks at the replyTo field.
|
||||||
|
participantsForReplyAll() {
|
||||||
|
const excludedFroms = this.from.map((c) =>
|
||||||
|
Utils.toEquivalentEmailForm(c.email)
|
||||||
|
);
|
||||||
|
|
||||||
|
const excludeMeAndFroms = (cc) =>
|
||||||
|
_.reject(cc, (p) =>
|
||||||
|
p.isMe() || _.contains(excludedFroms, Utils.toEquivalentEmailForm(p.email))
|
||||||
|
);
|
||||||
|
|
||||||
|
let to = null
|
||||||
|
let cc = null
|
||||||
|
|
||||||
|
if (this.isFromMe()) {
|
||||||
|
to = this.to
|
||||||
|
cc = excludeMeAndFroms(this.cc)
|
||||||
|
} else {
|
||||||
|
if (this.replyTo.length) {
|
||||||
|
to = this.replyTo
|
||||||
|
} else {
|
||||||
|
to = this.from
|
||||||
|
}
|
||||||
|
cc = excludeMeAndFroms([].concat(this.to, this.cc))
|
||||||
|
}
|
||||||
|
|
||||||
|
to = _.uniq(to, (p) => Utils.toEquivalentEmailForm(p.email))
|
||||||
|
cc = _.uniq(cc, (p) => Utils.toEquivalentEmailForm(p.email))
|
||||||
|
return {to, cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns a hash with `to` && `cc` keys for authoring a new draft in
|
||||||
|
// "reply" to this message. This method takes into account whether the
|
||||||
|
// message === from the current user, && also looks at the replyTo field.
|
||||||
|
participantsForReply() {
|
||||||
|
let to = []
|
||||||
|
const cc = []
|
||||||
|
|
||||||
|
if (this.isFromMe()) {
|
||||||
|
to = this.to
|
||||||
|
} else if (this.replyTo.length) {
|
||||||
|
to = this.replyTo
|
||||||
|
} else {
|
||||||
|
to = this.from
|
||||||
|
}
|
||||||
|
|
||||||
|
to = _.uniq(to, (p) => Utils.toEquivalentEmailForm(p.email))
|
||||||
|
return {to, cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns an {Array} of {File} IDs
|
||||||
|
fileIds() {
|
||||||
|
return _.map(this.files, (file) => file.id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns true if this message === from the current user's email
|
||||||
|
// address. In the future, this method will take into account all of the
|
||||||
|
// user's email addresses && accounts.
|
||||||
|
isFromMe() {
|
||||||
|
return ((this.from[0] || {}).isMe || (() => {}))()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns a plaintext version of the message body using Chromium's
|
||||||
|
// DOMParser. Use with care.
|
||||||
|
plainTextBody() {
|
||||||
|
if ((this.body || "").trim().length === 0) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return (new DOMParser()).parseFromString(this.body, "text/html").body.innerText
|
||||||
|
}
|
||||||
|
|
||||||
|
fromContact() {
|
||||||
|
return ((this.from || [])[0] || new Contact({name: 'Unknown', email: 'Unknown'}))
|
||||||
|
}
|
||||||
|
|
||||||
|
// Public: Returns the standard attribution line for this message,
|
||||||
|
// localized for the current user.
|
||||||
|
// ie "On Dec. 12th, 2015 at 4:00PM, Ben Gotow wrote:"
|
||||||
|
replyAttributionLine() {
|
||||||
|
return "On #{this.formattedDate()}, #{this.fromContact().toString()} wrote:"
|
||||||
|
}
|
||||||
|
|
||||||
|
formattedDate() {
|
||||||
|
return moment(this.date).format("MMM D YYYY, [at] h:mm a")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ request = require 'request'
|
||||||
NylasLongConnection = require('./nylas-long-connection').default
|
NylasLongConnection = require('./nylas-long-connection').default
|
||||||
Utils = require './models/utils'
|
Utils = require './models/utils'
|
||||||
Account = require('./models/account').default
|
Account = require('./models/account').default
|
||||||
Message = require './models/message'
|
Message = require('./models/message').default
|
||||||
Actions = require './actions'
|
Actions = require './actions'
|
||||||
{APIError} = require './errors'
|
{APIError} = require './errors'
|
||||||
PriorityUICoordinator = require '../priority-ui-coordinator'
|
PriorityUICoordinator = require '../priority-ui-coordinator'
|
||||||
|
@ -350,9 +350,9 @@ class NylasAPI
|
||||||
"label": require('./models/label')
|
"label": require('./models/label')
|
||||||
"folder": require('./models/folder')
|
"folder": require('./models/folder')
|
||||||
"thread": require('./models/thread').default
|
"thread": require('./models/thread').default
|
||||||
"draft": require('./models/message')
|
"draft": require('./models/message').default
|
||||||
"account": require('./models/account').default
|
"account": require('./models/account').default
|
||||||
"message": require('./models/message')
|
"message": require('./models/message').default
|
||||||
"contact": require('./models/contact')
|
"contact": require('./models/contact')
|
||||||
"calendar": require('./models/calendar')
|
"calendar": require('./models/calendar')
|
||||||
|
|
||||||
|
|
|
@ -236,7 +236,7 @@ class AccountStore extends NylasStore
|
||||||
_importFakeData: (dir) =>
|
_importFakeData: (dir) =>
|
||||||
fs = require 'fs-plus'
|
fs = require 'fs-plus'
|
||||||
path = require 'path'
|
path = require 'path'
|
||||||
Message = require '../models/message'
|
Message = require('../models/message').default
|
||||||
Account = require('../models/account').default
|
Account = require('../models/account').default
|
||||||
Thread = require('../models/thread').default
|
Thread = require('../models/thread').default
|
||||||
Label = require '../models/label'
|
Label = require '../models/label'
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
Message = require '../models/message'
|
Message = require('../models/message').default
|
||||||
Actions = require '../actions'
|
Actions = require '../actions'
|
||||||
DatabaseStore = require './database-store'
|
DatabaseStore = require './database-store'
|
||||||
ExtensionRegistry = require('../../extension-registry')
|
ExtensionRegistry = require('../../extension-registry')
|
||||||
|
|
|
@ -13,7 +13,7 @@ SanitizeTransformer = require '../../services/sanitize-transformer'
|
||||||
|
|
||||||
Thread = require('../models/thread').default
|
Thread = require('../models/thread').default
|
||||||
Contact = require '../models/contact'
|
Contact = require '../models/contact'
|
||||||
Message = require '../models/message'
|
Message = require('../models/message').default
|
||||||
Utils = require '../models/utils'
|
Utils = require '../models/utils'
|
||||||
MessageUtils = require '../models/message-utils'
|
MessageUtils = require '../models/message-utils'
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ DestroyDraftTask = require('../tasks/destroy-draft-task').default
|
||||||
|
|
||||||
Thread = require('../models/thread').default
|
Thread = require('../models/thread').default
|
||||||
Contact = require '../models/contact'
|
Contact = require '../models/contact'
|
||||||
Message = require '../models/message'
|
Message = require('../models/message').default
|
||||||
Actions = require '../actions'
|
Actions = require '../actions'
|
||||||
|
|
||||||
TaskQueue = require './task-queue'
|
TaskQueue = require './task-queue'
|
||||||
|
|
|
@ -5,7 +5,7 @@ mkdirp = require 'mkdirp'
|
||||||
NylasStore = require 'nylas-store'
|
NylasStore = require 'nylas-store'
|
||||||
Actions = require '../actions'
|
Actions = require '../actions'
|
||||||
Utils = require '../models/utils'
|
Utils = require '../models/utils'
|
||||||
Message = require '../models/message'
|
Message = require('../models/message').default
|
||||||
DraftStore = require './draft-store'
|
DraftStore = require './draft-store'
|
||||||
DatabaseStore = require './database-store'
|
DatabaseStore = require './database-store'
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
NylasStore = require "nylas-store"
|
NylasStore = require "nylas-store"
|
||||||
Actions = require "../actions"
|
Actions = require "../actions"
|
||||||
Message = require "../models/message"
|
Message = require("../models/message").default
|
||||||
Thread = require("../models/thread").default
|
Thread = require("../models/thread").default
|
||||||
Utils = require '../models/utils'
|
Utils = require '../models/utils'
|
||||||
DatabaseStore = require "./database-store"
|
DatabaseStore = require "./database-store"
|
||||||
|
|
|
@ -4,7 +4,7 @@ Task = require('./flux/tasks/task').default
|
||||||
Actions = require './flux/actions'
|
Actions = require './flux/actions'
|
||||||
Category = require './flux/models/category'
|
Category = require './flux/models/category'
|
||||||
Thread = require('./flux/models/thread').default
|
Thread = require('./flux/models/thread').default
|
||||||
Message = require './flux/models/message'
|
Message = require('./flux/models/message').default
|
||||||
AccountStore = require './flux/stores/account-store'
|
AccountStore = require './flux/stores/account-store'
|
||||||
DatabaseStore = require './flux/stores/database-store'
|
DatabaseStore = require './flux/stores/database-store'
|
||||||
TaskQueueStatusStore = require './flux/stores/task-queue-status-store'
|
TaskQueueStatusStore = require './flux/stores/task-queue-status-store'
|
||||||
|
|
Loading…
Add table
Reference in a new issue