Replace old pending messages with new one when adding a new incoming friend request.

More refactoring.
This commit is contained in:
Mikunj 2018-11-12 16:00:36 +11:00
parent d5fafd4d78
commit fc3cb9c46d
4 changed files with 62 additions and 39 deletions

View file

@ -196,9 +196,9 @@
removeMessage();
},
addSingleMessage(message) {
addSingleMessage(message, setToExpire = true) {
const model = this.messageCollection.add(message, { merge: true });
model.setToExpire();
if (setToExpire) model.setToExpire();
return model;
},
@ -245,14 +245,16 @@
},
async getPendingFriendRequests(direction) {
// Theoretically all ouur messages could be friend requests, thus we have to unfortunately go through each one :(
// We are most likely to find the friend request in the more recent conversations first
const messages = await window.Signal.Data.getMessagesByConversation(this.id, {
MessageCollection: Whisper.MessageCollection,
limit: Number.MAX_VALUE,
}).reverse();
const messages = await window.Signal.Data.getMessagesByConversation(
this.id,
{ MessageCollection: Whisper.MessageCollection }
);
// We are most likely to find the friend request in the more recent conversations first
// Get the messages that are matching the direction and the friendStatus
return messages.filter(m => (m.direction === direction && m.friendStatus === 'pending'));
return messages.models.reverse().filter(m => {
return (m.attributes.direction === direction && m.attributes.friendStatus === 'pending')
});
},
getPropsForListItem() {
const result = {
@ -425,7 +427,7 @@
return this.get('keyExchangeCompleted') || false;
},
setKeyExchangeCompleted(completed) {
async setKeyExchangeCompleted(completed) {
if (typeof completed !== 'boolean') {
throw new Error('setKeyExchangeCompleted expects a bool');
}
@ -680,7 +682,7 @@
},
// This will add a message which will allow the user to reply to a friend request
async addFriendRequest(body, options = {}) {
const mergedOptions = {
const _options = {
status: 'pending',
direction: 'incoming',
preKeyBundle: null,
@ -714,6 +716,27 @@
Conversation: Whisper.Conversation,
});
// If we need to add new incoming friend requests
// Then we need to make sure we remove any pending requests that we may have
// This is to ensure that one user cannot spam us with multiple friend requests
if (_options.direction === 'incoming') {
const requests = await this.getPendingFriendRequests('incoming');
for (const request of requests) {
// Delete the old message if it's pending
await window.Signal.Data.removeMessage(request.id, { Message: Whisper.Message });
const existing = this.messageCollection.get(request.id);
if (existing) {
this.messageCollection.remove(request.id);
existing.trigger('destroy');
}
}
// Trigger an update if we removed messages
if (requests.length > 0)
this.trigger('change');
}
// Add the new message
const timestamp = Date.now();
const message = {
conversationId: this.id,
@ -723,10 +746,10 @@
unread: 1,
from: this.id,
to: this.ourNumber,
friendStatus: mergedOptions.status,
direction: mergedOptions.direction,
friendStatus: _options.status,
direction: _options.direction,
body,
preKeyBundle: mergedOptions.preKeyBundle,
preKeyBundle: _options.preKeyBundle,
};
const id = await window.Signal.Data.saveMessage(message, {

View file

@ -297,13 +297,13 @@
getPropsForFriendRequest() {
const source = this.get('from');
const target = this.get('to');
const status = this.get('friendStatus') || 'pending';
const type = this.get('direction') || 'incoming';
const friendStatus = this.get('friendStatus') || 'pending';
const direction = this.get('direction') || 'incoming';
const conversation = this.getConversation();
// I.e do we send a network request from the model? or call a function in the conversation to send the new status
const onAccept = async () => {
this.set({ status: 'accepted' });
this.set({ friendStatus: 'accepted' });
await window.Signal.Data.saveMessage(this.attributes, {
Message: Whisper.Message,
});
@ -315,7 +315,7 @@
};
const onDecline = async () => {
this.set({ status: 'declined' });
this.set({ friendStatus: 'declined' });
await window.Signal.Data.saveMessage(this.attributes, {
Message: Whisper.Message,
});
@ -334,8 +334,8 @@
text: this.createNonBreakingLastSeparator(this.get('body')),
source: this.findAndFormatContact(source),
target: this.findAndFormatContact(target),
status,
type,
direction,
friendStatus,
onAccept,
onDecline,
onDelete,

View file

@ -943,7 +943,7 @@ MessageReceiver.prototype.extend({
},
// A handler function for when a friend request is accepted or declined
async onFriendRequestUpdate(pubKey, message) {
if (!message || !message.requestType || !message.friendStatus) return;
if (!message || !message.direction || !message.friendStatus) return;
// Update the conversation
const conversation = ConversationController.get(pubKey);
@ -953,7 +953,7 @@ MessageReceiver.prototype.extend({
}
// Send our own prekeys as a response
if (message.requestType === 'incoming' && message.friendStatus === 'accepted') {
if (message.direction === 'incoming' && message.friendStatus === 'accepted') {
libloki.sendEmptyMessageWithPreKeys(pubKey);
// Register the preKeys used for communication

View file

@ -12,11 +12,11 @@ interface Contact {
interface Props {
text?: string;
type: 'incoming' | 'outgoing';
direction: 'incoming' | 'outgoing';
source: Contact;
target: Contact;
i18n: Localizer;
status: 'pending' | 'accepted' | 'declined';
friendStatus: 'pending' | 'accepted' | 'declined';
onAccept: () => void;
onDecline: () => void;
onDelete: () => void;
@ -24,27 +24,27 @@ interface Props {
export class FriendRequest extends React.Component<Props> {
public getStringId() {
const { status, type } = this.props;
const { friendStatus, direction } = this.props;
switch (status) {
switch (friendStatus) {
case 'pending':
return `${type}FriendRequestPending`;
return `${direction}FriendRequestPending`;
case 'accepted':
return `friendRequestAccepted`;
case 'declined':
return `friendRequestDeclined`;
default:
throw new Error(`Invalid friend request status: ${status}`);
throw new Error(`Invalid friend request status: ${friendStatus}`);
}
}
public renderContents() {
const { type, i18n, text } = this.props;
const { direction, i18n, text } = this.props;
const id = this.getStringId();
return (
<div>
<div className={`module-friend-request__title module-friend-request__title--${type}`}>{i18n(id)}</div>
<div className={`module-friend-request__title module-friend-request__title--${direction}`}>{i18n(id)}</div>
{!!text &&
<div dir="auto">
<MessageBody text={text || ''} i18n={i18n} />
@ -56,19 +56,19 @@ export class FriendRequest extends React.Component<Props> {
}
public renderButtons() {
const { status, type, onAccept, onDecline, onDelete } = this.props;
const { friendStatus, direction, onAccept, onDecline, onDelete } = this.props;
if (type === 'incoming') {
if (status === 'pending') {
if (direction === 'incoming') {
if (friendStatus === 'pending') {
return (
<div className={`module-message__metadata module-friend-request__buttonContainer module-friend-request__buttonContainer--${type}`}>
<div className={`module-message__metadata module-friend-request__buttonContainer module-friend-request__buttonContainer--${direction}`}>
<button onClick={onAccept}>Accept</button>
<button onClick={onDecline}>Decline</button>
</div>
);
} else if (status === 'declined') {
} else if (friendStatus === 'declined') {
return (
<div className={`module-message__metadata module-friend-request__buttonContainer module-friend-request__buttonContainer--${type}`}>
<div className={`module-message__metadata module-friend-request__buttonContainer module-friend-request__buttonContainer--${direction}`}>
<button onClick={onDelete}>Delete Conversation</button>
</div>
);
@ -78,12 +78,12 @@ export class FriendRequest extends React.Component<Props> {
}
public render() {
const { type} = this.props;
const { direction } = this.props;
return (
<div className={`module-message module-message--${type} module-message-friend-request`}>
<div className={`module-message__container module-message__container--${type} module-message-friend-request__container`}>
<div className={`module-message__text module-message__text--${type}`}>
<div className={`module-message module-message--${direction} module-message-friend-request`}>
<div className={`module-message__container module-message__container--${direction} module-message-friend-request__container`}>
<div className={`module-message__text module-message__text--${direction}`}>
{this.renderContents()}
{this.renderButtons()}
</div>