feat(contacts): add respond to request and pending contact menu options

Fixes #6251

Adds the "Respond to Contact Request" and "Contact Request Pending" options to the MessageContextMenu

Also fixes some small issues with contact verification where the state of the incoming request was not correct
This commit is contained in:
Jonathan Rainville 2022-07-07 15:44:54 -04:00
parent 03780d4875
commit 16b2ca5c2c
8 changed files with 116 additions and 46 deletions

View File

@ -321,3 +321,6 @@ proc getCommunityById*(self: Controller, communityId: string): CommunityDto =
proc getStatusForContactWithId*(self: Controller, publicKey: string): StatusUpdateDto =
return self.contactsService.getStatusForContactWithId(publicKey)
proc getVerificationRequestFrom*(self: Controller, publicKey: string): VerificationRequest =
self.contactsService.getVerificationRequestFrom(publicKey)

View File

@ -202,7 +202,8 @@ method onStatusUrlRequested*(self: AccessInterface, action: StatusUrlAction, com
url: string, userId: string, groupName: string, listOfUserIds: seq[string]) {.base.} =
raise newException(ValueError, "No implementation available")
method getVerificationRequestFrom*(self: AccessInterface, publicKey: string): VerificationRequest {.base.} =
raise newException(ValueError, "No implementation available")
# This way (using concepts) is used only for the modules managed by AppController
type

View File

@ -677,9 +677,13 @@ method communityEdited*[T](
let channelGroup = community.toChannelGroupDto()
self.view.editItem(self.createChannelGroupItem(channelGroup))
method getVerificationRequestFrom*[T](self: Module[T], publicKey: string): VerificationRequest =
self.controller.getVerificationRequestFrom(publicKey)
method getContactDetailsAsJson*[T](self: Module[T], publicKey: string): string =
let contact = self.controller.getContact(publicKey)
let (name, _, _) = self.controller.getContactNameAndImage(contact.id)
let request = self.getVerificationRequestFrom(publicKey)
let jsonObj = %* {
"displayName": name,
"displayIcon": contact.image.thumbnail,
@ -699,7 +703,9 @@ method getContactDetailsAsJson*[T](self: Module[T], publicKey: string): string =
"isSyncing": contact.isSyncing,
"removed": contact.removed,
"trustStatus": contact.trustStatus.int,
# TODO rename verificationStatus to outgoingVerificationStatus
"verificationStatus": contact.verificationStatus.int,
"incomingVerificationStatus": request.status.int,
"hasAddedUs": contact.hasAddedUs
}
return $jsonObj

View File

@ -615,8 +615,9 @@ QtObject:
return self.receivedIdentityRequests[publicKey]
let response = status_contacts.getVerificationRequestFrom(publicKey)
result = response.result.toVerificationRequest()
self.receivedIdentityRequests[publicKey] = result
if not response.result.isNil and response.result.kind == JObject:
result = response.result.toVerificationRequest()
self.receivedIdentityRequests[publicKey] = result
except Exception as e:
let errDesription = e.msg
error "error obtaining verification request", errDesription

View File

@ -32,7 +32,8 @@ StatusModal {
property string userEnsName: ""
property string userIcon: ""
property int userTrustStatus: Constants.trustStatus.unknown
property int verificationStatus: Constants.verificationStatus.unverified
property int outgoingVerificationStatus: Constants.verificationStatus.unverified
property int incomingVerificationStatus: Constants.verificationStatus.unverified
property string text: ""
property string challenge: ""
property string response: ""
@ -85,8 +86,9 @@ StatusModal {
userTrustStatus = contactDetails.trustStatus
userTrustIsUnknown = contactDetails.trustStatus === Constants.trustStatus.unknown
userIsUntrustworthy = contactDetails.trustStatus === Constants.trustStatus.untrustworthy
verificationStatus = contactDetails.verificationStatus
isVerificationSent = verificationStatus !== Constants.verificationStatus.unverified
outgoingVerificationStatus = contactDetails.verificationStatus
incomingVerificationStatus = contactDetails.incomingVerificationStatus
isVerificationSent = outgoingVerificationStatus !== Constants.verificationStatus.unverified
if (isContact && popup.contactsStore.hasReceivedVerificationRequestFrom(publicKey)) {
popup.hasReceivedVerificationRequest = true
@ -95,7 +97,7 @@ StatusModal {
if(isContact && isVerificationSent) {
let verificationDetails = popup.contactsStore.getSentVerificationDetailsAsJson(publicKey);
verificationStatus = verificationDetails.requestStatus;
outgoingVerificationStatus = verificationDetails.requestStatus;
verificationChallenge = verificationDetails.challenge;
verificationResponse = verificationDetails.response;
verificationResponseDisplayName = verificationDetails.displayName;
@ -103,8 +105,9 @@ StatusModal {
verificationRequestedAt = verificationDetails.requestedAt;
verificationRepliedAt = verificationDetails.repliedAt;
}
isTrusted = verificationStatus === Constants.verificationStatus.trusted
isVerified = verificationStatus === Constants.verificationStatus.verified
isTrusted = outgoingVerificationStatus === Constants.verificationStatus.trusted
|| incomingVerificationStatus === Constants.verificationStatus.trusted
isVerified = outgoingVerificationStatus === Constants.verificationStatus.verified
text = ""; // this is most likely unneeded
isCurrentUser = popup.profileStore.pubkey === publicKey;
@ -112,16 +115,21 @@ StatusModal {
showFooter = !isCurrentUser;
popup.open();
if (state === "openNickname") {
if (state === Constants.profilePopupStates.openNickname) {
profileView.nicknamePopup.open();
} else if (state === "contactRequest") {
} else if (state === Constants.profilePopupStates.contactRequest) {
sendContactRequestModal.open()
} else if (state === "blockUser") {
} else if (state === Constants.profilePopupStates.blockUser) {
blockUser();
} else if (state === "unblockUser") {
} else if (state === Constants.profilePopupStates.unblockUser) {
unblockUser();
} else if (state === "verifyIdentity") {
} else if (state === Constants.profilePopupStates.verifyIdentity) {
showVerifyIdentitySection = true;
} else if (state === Constants.profilePopupStates.respondToPendingRequest) {
popup.openPendingRequestPopup()
} else if (state === Constants.profilePopupStates.showVerificationPendingSection) {
popup.showVerificationPendingSection = true
profileView.wizardAnimation.running = true
}
}
@ -137,6 +145,23 @@ StatusModal {
profileView.unblockContactConfirmationDialog.open();
}
function openPendingRequestPopup() {
try {
let request = popup.contactsStore.getVerificationDetailsFromAsJson(popup.userPublicKey)
Global.openPopup(contactVerificationRequestPopupComponent, {
senderPublicKey: request.from,
senderDisplayName: request.displayName,
senderIcon: request.icon,
challengeText: request.challenge,
responseText: request.response,
messageTimestamp: request.requestedAt,
responseTimestamp: request.repliedAt
})
} catch (e) {
console.error("Error getting or parsing verification data", e)
}
}
width: 700
header.title: {
@ -186,7 +211,7 @@ StatusModal {
hasReceivedVerificationRequest: popup.hasReceivedVerificationRequest
userTrustStatus: popup.userTrustStatus
verificationStatus: popup.verificationStatus
outgoingVerificationStatus: popup.outgoingVerificationStatus
showVerifyIdentitySection: popup.showVerifyIdentitySection
showVerificationPendingSection: popup.showVerificationPendingSection
@ -354,20 +379,7 @@ StatusModal {
(hasReceivedVerificationRequest && !isTrusted)
onClicked: {
if (hasReceivedVerificationRequest) {
try {
let request = popup.contactsStore.getVerificationDetailsFromAsJson(popup.userPublicKey)
Global.openPopup(contactVerificationRequestPopupComponent, {
senderPublicKey: request.from,
senderDisplayName: request.displayName,
senderIcon: request.icon,
challengeText: request.challenge,
responseText: request.response,
messageTimestamp: request.requestedAt,
responseTimestamp: request.repliedAt
})
} catch (e) {
console.error("Error getting or parsing verification data", e)
}
popup.openPendingRequestPopup()
} else {
popup.showVerificationPendingSection = true
profileView.wizardAnimation.running = true

View File

@ -39,7 +39,7 @@ Rectangle {
property bool isAddedContact: false
property int userTrustStatus: Constants.trustStatus.unknown
property int verificationStatus: Constants.verificationStatus.unverified
property int outgoingVerificationStatus: Constants.verificationStatus.unverified
property string challenge: ""
property string response: ""
@ -140,7 +140,7 @@ Rectangle {
}
ScriptAction {
script: {
if (verificationStatus === Constants.verificationStatus.trusted) {
if (outgoingVerificationStatus === Constants.verificationStatus.trusted) {
stepsListModel.setProperty(2, "stepCompleted", true);
}
}

View File

@ -62,15 +62,19 @@ StatusPopupMenu {
return root.selectedUserPublicKey !== "" && !!contactDetails.isContact
}
readonly property bool isBlockedContact: d.contactDetails && d.contactDetails.isBlocked
readonly property bool isBlockedContact: {
return root.selectedUserPublicKey !== "" && !!contactDetails.isBlocked
}
readonly property int outgoingVerificationStatus: {
if (root.selectedUserPublicKey === "" || root.isMe || !root.isContact) {
return 0
}
return contactDetails.verificationStatus
}
readonly property int incomingVerificationStatus: {
if (root.selectedUserPublicKey === "" || root.isMe || !root.isContact) {
return 0
}
return contactDetails.incomingVerificationStatus
}
readonly property bool hasPendingContactRequest: {
return !root.isMe && root.selectedUserPublicKey !== "" &&
root.store.contactsStore.hasPendingContactRequest(root.selectedUserPublicKey);
@ -87,6 +91,13 @@ StatusPopupMenu {
}
return root.outgoingVerificationStatus !== Constants.verificationStatus.unverified
}
readonly property bool isTrusted: {
if (!root.selectedUserPublicKey || root.isMe || !root.isContact) {
return false
}
return root.verificationStatus === Constants.verificationStatus.trusted ||
root.incomingVerificationStatus === Constants.verificationStatus.trusted
}
readonly property bool userTrustIsUnknown: d.contactDetails && d.contactDetails.trustStatus === Constants.trustStatus.unknown
readonly property bool userIsUntrustworthy: d.contactDetails && d.contactDetails.trustStatus === Constants.trustStatus.untrustworthy
@ -252,17 +263,8 @@ StatusPopupMenu {
enabled: root.isProfile && !root.isMe && !root.isContact
&& !root.isBlockedContact && !root.hasPendingContactRequest
onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, "contactRequest")
root.close()
}
}
StatusMenuItem {
text: qsTr("Rename")
icon.name: "edit_pencil"
enabled: root.isProfile && !root.isMe
onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, "openNickname")
root.openProfileClicked(root.selectedUserPublicKey,
Constants.profilePopupStates.contactRequest)
root.close()
}
}
@ -274,7 +276,42 @@ StatusPopupMenu {
&& !root.isBlockedContact && !root.isVerificationRequestSent
&& !root.hasReceivedVerificationRequestFrom
onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey, "verifyIdentity")
root.openProfileClicked(root.selectedUserPublicKey,
Constants.profilePopupStates.verifyIdentity)
root.close()
}
}
StatusMenuItem {
text: isVerificationRequestSent ||
root.incomingVerificationStatus === Constants.verificationStatus.verified ?
qsTr("ID Request Pending....") :
qsTr("Respond to ID Request...")
icon.name: "checkmark-circle"
enabled: root.isProfile && !root.isMe && root.isContact
&& !root.isBlockedContact && !root.isTrusted
&& (root.hasReceivedVerificationRequestFrom
|| root.isVerificationRequestSent)
onTriggered: {
if (hasReceivedVerificationRequestFrom) {
root.openProfileClicked(root.selectedUserPublicKey,
Constants.profilePopupStates.respondToPendingRequest)
} else if (root.isVerificationRequestSent) {
root.openProfileClicked(root.selectedUserPublicKey,
Constants.profilePopupStates.showVerificationPendingSection)
}
root.close()
}
}
StatusMenuItem {
text: qsTr("Rename")
icon.name: "edit_pencil"
enabled: root.isProfile && !root.isMe
onTriggered: {
root.openProfileClicked(root.selectedUserPublicKey,
Constants.profilePopupStates.openNickname)
root.close()
}
}

View File

@ -153,6 +153,16 @@ QtObject {
readonly property int blockedContacts: 6
}
readonly property QtObject profilePopupStates: QtObject {
readonly property string openNickname: "openNickname"
readonly property string contactRequest: "contactRequest"
readonly property string blockUser: "blockUser"
readonly property string unblockUser: "unblockUser"
readonly property string verifyIdentity: "verifyIdentity"
readonly property string showVerificationPendingSection: "showVerificationPendingSection"
readonly property string respondToPendingRequest: "respondToPendingRequest"
}
readonly property QtObject validators: QtObject {
readonly property list<StatusValidator> displayName: [
StatusMinLengthValidator {