Fetch conversations once, clean up ConversationController API (#1420)
* Fetch conversations once, clean up ConversationController API Race conditions around re-fetching have caused some problems recently, so this removes the need to re-fetch conversations. They are fetched once or saved once, and that is it. All interaction goes through the ConversationController, which is the central source of truth. We have two rules for Conversations: 1. If a conversation is in the ConversationController it doesn't need to be fetched, but its initial fetch/save might be in progress. You can wait for that fetch/save with conversation.initialPromise. 2. If a conversation is not already in the ConversationController, it's not yet in the database. It needs to be added to the ConversationController and saved to the database. FREEBIE * Remove Conversation.fetch() call in Message.handleDataMessage() FREEBIE * ConversationController.API cleanup: Fix two missing spots FREEBIE
This commit is contained in:
parent
51cd28bb4a
commit
d8ce198f55
|
@ -193,7 +193,7 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return ConversationController.findOrCreateById(id, 'private')
|
return ConversationController.getOrCreateAndWait(id, 'private')
|
||||||
.then(function(conversation) {
|
.then(function(conversation) {
|
||||||
return new Promise(function(resolve, reject) {
|
return new Promise(function(resolve, reject) {
|
||||||
conversation.save({
|
conversation.save({
|
||||||
|
@ -229,7 +229,7 @@
|
||||||
var details = ev.groupDetails;
|
var details = ev.groupDetails;
|
||||||
var id = details.id;
|
var id = details.id;
|
||||||
|
|
||||||
return ConversationController.findOrCreateById(id, 'group').then(function(conversation) {
|
return ConversationController.getOrCreateAndWait(id, 'group').then(function(conversation) {
|
||||||
var updates = {
|
var updates = {
|
||||||
name: details.name,
|
name: details.name,
|
||||||
members: details.members,
|
members: details.members,
|
||||||
|
@ -258,10 +258,21 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var type, id;
|
||||||
|
if (data.message.group) {
|
||||||
|
type = 'group';
|
||||||
|
id = data.message.group.id;
|
||||||
|
} else {
|
||||||
|
type = 'private';
|
||||||
|
id = data.source;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConversationController.getOrCreateAndWait(id, type).then(function() {
|
||||||
return message.handleDataMessage(data.message, ev.confirm, {
|
return message.handleDataMessage(data.message, ev.confirm, {
|
||||||
initialLoadComplete: initialLoadComplete
|
initialLoadComplete: initialLoadComplete
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSentMessage(ev) {
|
function onSentMessage(ev) {
|
||||||
|
@ -286,10 +297,21 @@
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var type, id;
|
||||||
|
if (data.message.group) {
|
||||||
|
type = 'group';
|
||||||
|
id = data.message.group.id;
|
||||||
|
} else {
|
||||||
|
type = 'private';
|
||||||
|
id = data.destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ConversationController.getOrCreateAndWait(id, type).then(function() {
|
||||||
return message.handleDataMessage(data.message, ev.confirm, {
|
return message.handleDataMessage(data.message, ev.confirm, {
|
||||||
initialLoadComplete: initialLoadComplete
|
initialLoadComplete: initialLoadComplete
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMessageDuplicate(message) {
|
function isMessageDuplicate(message) {
|
||||||
|
@ -374,7 +396,7 @@
|
||||||
|
|
||||||
return message.saveErrors(error).then(function() {
|
return message.saveErrors(error).then(function() {
|
||||||
var id = message.get('conversationId');
|
var id = message.get('conversationId');
|
||||||
return ConversationController.findOrCreateById(id, 'private').then(function(conversation) {
|
return ConversationController.getOrCreateAndWait(id, 'private').then(function(conversation) {
|
||||||
conversation.set({
|
conversation.set({
|
||||||
active_at: Date.now(),
|
active_at: Date.now(),
|
||||||
unreadCount: conversation.get('unreadCount') + 1
|
unreadCount: conversation.get('unreadCount') + 1
|
||||||
|
@ -455,7 +477,7 @@
|
||||||
console.log('got verified sync for', number, state,
|
console.log('got verified sync for', number, state,
|
||||||
ev.viaContactSync ? 'via contact sync' : '');
|
ev.viaContactSync ? 'via contact sync' : '');
|
||||||
|
|
||||||
return ConversationController.findOrCreateById(number, 'private').then(function(contact) {
|
return ConversationController.getOrCreateAndWait(number, 'private').then(function(contact) {
|
||||||
var options = {
|
var options = {
|
||||||
viaSyncMessage: true,
|
viaSyncMessage: true,
|
||||||
viaContactSync: ev.viaContactSync,
|
viaContactSync: ev.viaContactSync,
|
||||||
|
|
|
@ -85,37 +85,46 @@
|
||||||
get: function(id) {
|
get: function(id) {
|
||||||
return conversations.get(id);
|
return conversations.get(id);
|
||||||
},
|
},
|
||||||
add: function(attrs) {
|
createTemporary: function(attributes) {
|
||||||
return conversations.add(attrs, {merge: true});
|
return conversations.add(attributes);
|
||||||
},
|
},
|
||||||
create: function(attrs) {
|
getOrCreate: function(id, type) {
|
||||||
if (typeof attrs !== 'object') {
|
var conversation = conversations.get(id);
|
||||||
throw new Error('ConversationController.create requires an object, got', attrs);
|
if (conversation) {
|
||||||
}
|
|
||||||
var conversation = conversations.add(attrs, {merge: true});
|
|
||||||
return conversation;
|
return conversation;
|
||||||
},
|
}
|
||||||
findOrCreateById: function(id, type) {
|
|
||||||
var conversation = conversations.add({
|
conversation = conversations.add({
|
||||||
id: id,
|
id: id,
|
||||||
type: type
|
type: type
|
||||||
});
|
});
|
||||||
return new Promise(function(resolve, reject) {
|
conversation.initialPromise = new Promise(function(resolve, reject) {
|
||||||
conversation.fetch().then(function() {
|
|
||||||
resolve(conversation);
|
|
||||||
}, function() {
|
|
||||||
var deferred = conversation.save();
|
var deferred = conversation.save();
|
||||||
|
|
||||||
if (!deferred) {
|
if (!deferred) {
|
||||||
console.log('Conversation save failed! ', id, type);
|
console.log('Conversation save failed! ', id, type);
|
||||||
return reject(new Error('findOrCreateById: Conversation save failed'));
|
return reject(new Error('getOrCreate: Conversation save failed'));
|
||||||
}
|
}
|
||||||
|
|
||||||
deferred.then(function() {
|
deferred.then(function() {
|
||||||
resolve(conversation);
|
resolve(conversation);
|
||||||
}, reject);
|
}, reject);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return conversation;
|
||||||
|
},
|
||||||
|
getOrCreateAndWait: function(id, type) {
|
||||||
|
var conversation = this.getOrCreate(id, type);
|
||||||
|
|
||||||
|
if (conversation) {
|
||||||
|
return conversation.initialPromise.then(function() {
|
||||||
|
return conversation;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Promise.reject(
|
||||||
|
new Error('getOrCreateAndWait: did not get conversation')
|
||||||
|
);
|
||||||
},
|
},
|
||||||
getAllGroupsInvolvingId: function(id) {
|
getAllGroupsInvolvingId: function(id) {
|
||||||
var groups = new Whisper.GroupCollection();
|
var groups = new Whisper.GroupCollection();
|
||||||
|
@ -126,7 +135,7 @@
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
updateInbox: function() {
|
updateInbox: function() {
|
||||||
return conversations.fetchActive();
|
return conversations.fetch();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -13,16 +13,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
signalProtocolStore.on('keychange', function(id) {
|
signalProtocolStore.on('keychange', function(id) {
|
||||||
var conversation = ConversationController.add({id: id});
|
ConversationController.getOrCreateAndWait(id, 'private').then(function(conversation) {
|
||||||
conversation.fetch().then(function() {
|
|
||||||
conversation.addKeyChange(id);
|
conversation.addKeyChange(id);
|
||||||
});
|
|
||||||
ConversationController.getAllGroupsInvolvingId(id).then(function(groups) {
|
ConversationController.getAllGroupsInvolvingId(id).then(function(groups) {
|
||||||
_.forEach(groups, function(group) {
|
_.forEach(groups, function(group) {
|
||||||
group.addKeyChange(id);
|
group.addKeyChange(id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}());
|
}());
|
||||||
|
|
|
@ -59,6 +59,10 @@
|
||||||
this.ourNumber = textsecure.storage.user.getNumber();
|
this.ourNumber = textsecure.storage.user.getNumber();
|
||||||
this.verifiedEnum = textsecure.storage.protocol.VerifiedStatus;
|
this.verifiedEnum = textsecure.storage.protocol.VerifiedStatus;
|
||||||
|
|
||||||
|
// This may be overridden by ConversationController.getOrCreate, and signify
|
||||||
|
// our first save to the database. Or first fetch from the database.
|
||||||
|
this.initialPromise = Promise.resolve();
|
||||||
|
|
||||||
this.contactCollection = new Backbone.Collection();
|
this.contactCollection = new Backbone.Collection();
|
||||||
this.messageCollection = new Whisper.MessageCollection([], {
|
this.messageCollection = new Whisper.MessageCollection([], {
|
||||||
conversation: this
|
conversation: this
|
||||||
|
@ -87,7 +91,7 @@
|
||||||
if (this.isPrivate()) {
|
if (this.isPrivate()) {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
this.safeGetVerified(),
|
this.safeGetVerified(),
|
||||||
this.safeFetch()
|
this.initialPromise,
|
||||||
]).then(function(results) {
|
]).then(function(results) {
|
||||||
var trust = results[0];
|
var trust = results[0];
|
||||||
// we don't return here because we don't need to wait for this to finish
|
// we don't return here because we don't need to wait for this to finish
|
||||||
|
@ -103,12 +107,6 @@
|
||||||
}.bind(this)).then(this.onMemberVerifiedChange.bind(this));
|
}.bind(this)).then(this.onMemberVerifiedChange.bind(this));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
safeFetch: function() {
|
|
||||||
// new Promise necessary because a fetch will fail if convo not in db yet
|
|
||||||
return new Promise(function(resolve) {
|
|
||||||
this.fetch().always(resolve);
|
|
||||||
}.bind(this));
|
|
||||||
},
|
|
||||||
setVerifiedDefault: function(options) {
|
setVerifiedDefault: function(options) {
|
||||||
var DEFAULT = this.verifiedEnum.DEFAULT;
|
var DEFAULT = this.verifiedEnum.DEFAULT;
|
||||||
return this.queueJob(function() {
|
return this.queueJob(function() {
|
||||||
|
@ -801,28 +799,23 @@
|
||||||
return _.contains(this.get('members'), number);
|
return _.contains(this.get('members'), number);
|
||||||
},
|
},
|
||||||
fetchContacts: function(options) {
|
fetchContacts: function(options) {
|
||||||
return new Promise(function(resolve) {
|
|
||||||
if (this.isPrivate()) {
|
if (this.isPrivate()) {
|
||||||
this.contactCollection.reset([this]);
|
this.contactCollection.reset([this]);
|
||||||
resolve();
|
return Promise.resolve();
|
||||||
} else {
|
} else {
|
||||||
var promises = [];
|
|
||||||
var members = this.get('members') || [];
|
var members = this.get('members') || [];
|
||||||
|
var promises = members.map(function(number) {
|
||||||
this.contactCollection.reset(
|
return ConversationController.getOrCreateAndWait(number, 'private');
|
||||||
members.map(function(number) {
|
|
||||||
var c = ConversationController.create({
|
|
||||||
id : number,
|
|
||||||
type : 'private'
|
|
||||||
});
|
});
|
||||||
this.listenTo(c, 'change:verified', this.onMemberVerifiedChange);
|
|
||||||
promises.push(c.safeFetch());
|
return Promise.all(promises).then(function(contacts) {
|
||||||
return c;
|
_.forEach(contacts, function(contact) {
|
||||||
}.bind(this))
|
this.listenTo(contact, 'change:verified', this.onMemberVerifiedChange);
|
||||||
);
|
|
||||||
resolve(Promise.all(promises));
|
|
||||||
}
|
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
this.contactCollection.reset(contacts);
|
||||||
|
}.bind(this));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
destroyMessages: function() {
|
destroyMessages: function() {
|
||||||
|
@ -956,14 +949,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
window.drawAttention();
|
window.drawAttention();
|
||||||
var sender = ConversationController.create({
|
|
||||||
id: message.get('source'), type: 'private'
|
|
||||||
});
|
|
||||||
var conversationId = this.id;
|
var conversationId = this.id;
|
||||||
|
|
||||||
return new Promise(function(resolve, reject) {
|
ConversationController.getOrCreateAndWait(message.get('source'), 'private')
|
||||||
sender.fetch().then(function() {
|
.then(function(sender) {
|
||||||
sender.getNotificationIcon().then(function(iconUrl) {
|
return sender.getNotificationIcon().then(function(iconUrl) {
|
||||||
console.log('adding notification');
|
console.log('adding notification');
|
||||||
Whisper.Notifications.add({
|
Whisper.Notifications.add({
|
||||||
title : sender.getTitle(),
|
title : sender.getTitle(),
|
||||||
|
@ -973,10 +963,7 @@
|
||||||
conversationId : conversationId,
|
conversationId : conversationId,
|
||||||
messageId : message.id
|
messageId : message.id
|
||||||
});
|
});
|
||||||
|
});
|
||||||
return resolve();
|
|
||||||
}, reject);
|
|
||||||
}, reject);
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
hashCode: function() {
|
hashCode: function() {
|
||||||
|
@ -1054,20 +1041,6 @@
|
||||||
}
|
}
|
||||||
}).always(resolve);
|
}).always(resolve);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
},
|
|
||||||
|
|
||||||
fetchActive: function() {
|
|
||||||
// Ensures all active conversations are included in this collection,
|
|
||||||
// and updates their attributes, but removes nothing.
|
|
||||||
return this.fetch({
|
|
||||||
index: {
|
|
||||||
name: 'inbox', // 'inbox' index on active_at
|
|
||||||
order: 'desc' // ORDER timestamp DESC
|
|
||||||
// TODO pagination/infinite scroll
|
|
||||||
// limit: 10, offset: page*10,
|
|
||||||
},
|
|
||||||
remove: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -147,19 +147,12 @@
|
||||||
return this.imageUrl;
|
return this.imageUrl;
|
||||||
},
|
},
|
||||||
getConversation: function() {
|
getConversation: function() {
|
||||||
return ConversationController.add({
|
return ConversationController.get(this.get('conversationId'));
|
||||||
id: this.get('conversationId')
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
getExpirationTimerUpdateSource: function() {
|
getExpirationTimerUpdateSource: function() {
|
||||||
if (this.isExpirationTimerUpdate()) {
|
if (this.isExpirationTimerUpdate()) {
|
||||||
var conversationId = this.get('expirationTimerUpdate').source;
|
var conversationId = this.get('expirationTimerUpdate').source;
|
||||||
var c = ConversationController.get(conversationId);
|
return ConversationController.getOrCreate(conversationId, 'private');
|
||||||
if (!c) {
|
|
||||||
c = ConversationController.create({id: conversationId, type: 'private'});
|
|
||||||
c.fetch();
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
getContact: function() {
|
getContact: function() {
|
||||||
|
@ -167,21 +160,12 @@
|
||||||
if (!this.isIncoming()) {
|
if (!this.isIncoming()) {
|
||||||
conversationId = textsecure.storage.user.getNumber();
|
conversationId = textsecure.storage.user.getNumber();
|
||||||
}
|
}
|
||||||
var c = ConversationController.get(conversationId);
|
return ConversationController.getOrCreate(conversationId, 'private');
|
||||||
if (!c) {
|
|
||||||
c = ConversationController.create({id: conversationId, type: 'private'});
|
|
||||||
c.fetch();
|
|
||||||
}
|
|
||||||
return c;
|
|
||||||
},
|
},
|
||||||
getModelForKeyChange: function() {
|
getModelForKeyChange: function() {
|
||||||
var id = this.get('key_changed');
|
var id = this.get('key_changed');
|
||||||
if (!this.modelForKeyChange) {
|
if (!this.modelForKeyChange) {
|
||||||
var c = ConversationController.get(id);
|
var c = ConversationController.getOrCreate(id, 'private');
|
||||||
if (!c) {
|
|
||||||
c = ConversationController.create({ id: id, type: 'private' });
|
|
||||||
c.fetch();
|
|
||||||
}
|
|
||||||
this.modelForKeyChange = c;
|
this.modelForKeyChange = c;
|
||||||
}
|
}
|
||||||
return this.modelForKeyChange;
|
return this.modelForKeyChange;
|
||||||
|
@ -189,11 +173,7 @@
|
||||||
getModelForVerifiedChange: function() {
|
getModelForVerifiedChange: function() {
|
||||||
var id = this.get('verifiedChanged');
|
var id = this.get('verifiedChanged');
|
||||||
if (!this.modelForVerifiedChange) {
|
if (!this.modelForVerifiedChange) {
|
||||||
var c = ConversationController.get(id);
|
var c = ConversationController.getOrCreate(id, 'private');
|
||||||
if (!c) {
|
|
||||||
c = ConversationController.create({ id: id, type: 'private' });
|
|
||||||
c.fetch();
|
|
||||||
}
|
|
||||||
this.modelForVerifiedChange = c;
|
this.modelForVerifiedChange = c;
|
||||||
}
|
}
|
||||||
return this.modelForVerifiedChange;
|
return this.modelForVerifiedChange;
|
||||||
|
@ -347,9 +327,11 @@
|
||||||
options = options || {};
|
options = options || {};
|
||||||
_.defaults(options, {initialLoadComplete: true});
|
_.defaults(options, {initialLoadComplete: true});
|
||||||
|
|
||||||
// This function can be called from the background script on an
|
// This function is called from the background script in a few scenarios:
|
||||||
// incoming message or from the frontend after the user accepts an
|
// 1. on an incoming message
|
||||||
// identity key change.
|
// 2. on a sent message sync'd from another device
|
||||||
|
// 3. in rare cases, an incoming message can be retried, though it will
|
||||||
|
// still through one of the previous two codepaths.
|
||||||
var message = this;
|
var message = this;
|
||||||
var source = message.get('source');
|
var source = message.get('source');
|
||||||
var type = message.get('type');
|
var type = message.get('type');
|
||||||
|
@ -360,10 +342,9 @@
|
||||||
}
|
}
|
||||||
console.log('queuing handleDataMessage', message.idForLogging());
|
console.log('queuing handleDataMessage', message.idForLogging());
|
||||||
|
|
||||||
var conversation = ConversationController.create({id: conversationId});
|
var conversation = ConversationController.get(conversationId);
|
||||||
return conversation.queueJob(function() {
|
return conversation.queueJob(function() {
|
||||||
return new Promise(function(resolve) {
|
return new Promise(function(resolve) {
|
||||||
conversation.fetch().always(function() {
|
|
||||||
console.log('starting handleDataMessage', message.idForLogging());
|
console.log('starting handleDataMessage', message.idForLogging());
|
||||||
|
|
||||||
var now = new Date().getTime();
|
var now = new Date().getTime();
|
||||||
|
@ -531,7 +512,6 @@
|
||||||
}, handleError);
|
}, handleError);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
},
|
},
|
||||||
markRead: function(read_at) {
|
markRead: function(read_at) {
|
||||||
this.unset('unread');
|
this.unset('unread');
|
||||||
|
|
|
@ -25,9 +25,7 @@
|
||||||
openInbox();
|
openInbox();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var conversation = ConversationController.create({
|
var conversation = ConversationController.get(last.get('conversationId'));
|
||||||
id: last.get('conversationId')
|
|
||||||
});
|
|
||||||
openConversation(conversation);
|
openConversation(conversation);
|
||||||
this.clear();
|
this.clear();
|
||||||
},
|
},
|
||||||
|
|
|
@ -88,7 +88,7 @@
|
||||||
// Creates a view to display a new contact
|
// Creates a view to display a new contact
|
||||||
this.new_contact_view = new Whisper.NewContactView({
|
this.new_contact_view = new Whisper.NewContactView({
|
||||||
el: this.$new_contact,
|
el: this.$new_contact,
|
||||||
model: ConversationController.create({
|
model: ConversationController.createTemporary({
|
||||||
type: 'private'
|
type: 'private'
|
||||||
})
|
})
|
||||||
}).render();
|
}).render();
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
createConversation: function() {
|
createConversation: function() {
|
||||||
var conversation = this.new_contact_view.model;
|
var conversation = this.new_contact_view.model;
|
||||||
if (this.new_contact_view.model.isValid()) {
|
if (this.new_contact_view.model.isValid()) {
|
||||||
ConversationController.findOrCreateById(
|
ConversationController.getOrCreateAndWait(
|
||||||
this.new_contact_view.model.id,
|
this.new_contact_view.model.id,
|
||||||
'private'
|
'private'
|
||||||
).then(function(conversation) {
|
).then(function(conversation) {
|
||||||
|
|
|
@ -261,9 +261,11 @@
|
||||||
},
|
},
|
||||||
openConversation: function(e, conversation) {
|
openConversation: function(e, conversation) {
|
||||||
this.searchView.hideHints();
|
this.searchView.hideHints();
|
||||||
conversation = ConversationController.create(conversation);
|
if (conversation) {
|
||||||
|
conversation = ConversationController.get(conversation.id);
|
||||||
this.conversation_stack.open(conversation);
|
this.conversation_stack.open(conversation);
|
||||||
this.focusConversation();
|
this.focusConversation();
|
||||||
|
}
|
||||||
},
|
},
|
||||||
toggleMenu: function() {
|
toggleMenu: function() {
|
||||||
this.$('.global-menu .menu-list').toggle();
|
this.$('.global-menu .menu-list').toggle();
|
||||||
|
|
|
@ -26,7 +26,7 @@ describe('KeyChangeListener', function() {
|
||||||
describe('When we have a conversation with this contact', function() {
|
describe('When we have a conversation with this contact', function() {
|
||||||
var convo = new Whisper.Conversation({ id: phoneNumberWithKeyChange, type: 'private'});
|
var convo = new Whisper.Conversation({ id: phoneNumberWithKeyChange, type: 'private'});
|
||||||
before(function() {
|
before(function() {
|
||||||
ConversationController.add(convo);
|
ConversationController.createTemporary(convo);
|
||||||
return convo.save();
|
return convo.save();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ describe('KeyChangeListener', function() {
|
||||||
describe('When we have a group with this contact', function() {
|
describe('When we have a group with this contact', function() {
|
||||||
var convo = new Whisper.Conversation({ id: 'groupId', type: 'group', members: [phoneNumberWithKeyChange] });
|
var convo = new Whisper.Conversation({ id: 'groupId', type: 'group', members: [phoneNumberWithKeyChange] });
|
||||||
before(function() {
|
before(function() {
|
||||||
ConversationController.add(convo);
|
ConversationController.createTemporary(convo);
|
||||||
return convo.save();
|
return convo.save();
|
||||||
});
|
});
|
||||||
after(function() {
|
after(function() {
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
describe('MessageView', function() {
|
describe('MessageView', function() {
|
||||||
var conversations = new Whisper.ConversationCollection();
|
before(function() {
|
||||||
before(function(done) {
|
return storage.put('number_id', '+18088888888.1');
|
||||||
conversations.fetch().then(done);
|
|
||||||
storage.put('number_id', '+18088888888.1');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
var convo = conversations.add({id: 'foo'});
|
var convo = ConversationController.createTemporary({id: 'foo'});
|
||||||
var message = convo.messageCollection.add({
|
var message = convo.messageCollection.add({
|
||||||
conversationId: convo.id,
|
conversationId: convo.id,
|
||||||
body: 'hello world',
|
body: 'hello world',
|
||||||
|
|
Loading…
Reference in New Issue