Fix contact overwrite in search view (#2191)

When typing in an existing phone number into the search, clicking on it even
though there exists an existing contact will reinitialize that contact’s
database entry. This reinitialization clears that contact’s conversation’s name,
unread count, etc.

This change ensures we always reuse existing conversations using
`ConversationController.getOrCreateAndWait` when starting new conversations in
the search view.
This commit is contained in:
Daniel Gasienica 2018-03-28 14:29:33 -04:00 committed by GitHub
commit f6d0c1f171
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 35 additions and 24 deletions

View file

@ -106,6 +106,7 @@ module.exports = function(grunt) {
'!js/logging.js',
'!js/backup.js',
'!js/modules/**/*.js',
'!js/views/conversation_search_view.js',
'!js/views/debug_log_view.js',
'!js/signal_protocol_store.js',
'!js/database.js',

View file

@ -95,10 +95,18 @@
getUnsafe: function(id) {
return conversations.get(id);
},
createTemporary: function(attributes) {
dangerouslyCreateAndAdd: function(attributes) {
return conversations.add(attributes);
},
getOrCreate: function(id, type) {
if (typeof id !== 'string') {
throw new TypeError('"id" must be a string');
}
if (type !== 'private' && type !== 'group') {
throw new TypeError('"type" must be "private" or "group"; got: ' + type);
}
if (!this._initialFetchComplete) {
throw new Error('ConversationController.get() needs complete initial fetch');
}

View file

@ -89,32 +89,27 @@
this.new_contact_view.undelegateEvents();
this.new_contact_view.$el.hide();
}
// Creates a view to display a new contact
const model = new Whisper.Conversation({ type: 'private' });
this.new_contact_view = new Whisper.NewContactView({
el: this.$new_contact,
model: ConversationController.createTemporary({
type: 'private',
}),
model,
}).render();
},
createConversation() {
if (this.new_contact_view.model.isValid()) {
// NOTE: Temporarily allow `then` until we convert the entire file
// to `async` / `await`:
// eslint-disable-next-line more/no-then
ConversationController.getOrCreateAndWait(
this.new_contact_view.model.id,
'private'
).then((conversation) => {
this.trigger('open', conversation);
this.initNewContact();
this.resetTypeahead();
});
} else {
async createConversation() {
const isValidNumber = this.new_contact_view.model.isValid();
if (!isValidNumber) {
this.new_contact_view.$('.number').text(i18n('invalidNumberError'));
this.$input.focus();
return;
}
const newConversationId = this.new_contact_view.model.id;
const conversation =
await ConversationController.getOrCreateAndWait(newConversationId, 'private');
this.trigger('open', conversation);
this.initNewContact();
this.resetTypeahead();
},
reset() {

View file

@ -16,9 +16,12 @@ describe('KeyChangeListener', function() {
});
describe('When we have a conversation with this contact', function() {
var convo = new Whisper.Conversation({ id: phoneNumberWithKeyChange, type: 'private'});
let convo;
before(function() {
ConversationController.createTemporary(convo);
convo = ConversationController.dangerouslyCreateAndAdd({
id: phoneNumberWithKeyChange,
type: 'private',
});
return convo.save();
});
@ -41,9 +44,13 @@ describe('KeyChangeListener', function() {
describe('When we have a group with this contact', function() {
var convo = new Whisper.Conversation({ id: 'groupId', type: 'group', members: [phoneNumberWithKeyChange] });
let convo;
before(function() {
ConversationController.createTemporary(convo);
convo = ConversationController.dangerouslyCreateAndAdd({
id: 'groupId',
type: 'group',
members: [phoneNumberWithKeyChange],
});
return convo.save();
});
after(function() {

View file

@ -2,7 +2,7 @@ describe('MessageView', function() {
var convo, message;
before(function() {
convo = ConversationController.createTemporary({id: 'foo'});
convo = new Whisper.Conversation({id: 'foo'});
message = convo.messageCollection.add({
conversationId: convo.id,
body: 'hello world',