From f0645154ca2d6cbdadbc57ea6b36ae9518dc1012 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet <> Date: Tue, 6 Jun 2023 15:01:43 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Suppression=20des=20r=C3=A9f=C3=A9rences=20?= =?UTF-8?q?InviteService?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Home/AllChats/AllChatsCoordinator.swift | 120 +++--- Riot/Modules/TabBar/TabBarCoordinator.swift | 100 ++--- Tchap/Managers/Invite/InviteService.swift | 370 +++++++++--------- Tchap/Managers/Invite/InviteServiceType.swift | 50 +-- 4 files changed, 321 insertions(+), 319 deletions(-) diff --git a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift index 14e040114c..9e9646559b 100644 --- a/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift +++ b/Riot/Modules/Home/AllChats/AllChatsCoordinator.swift @@ -81,7 +81,7 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { private var indicators = [UserIndicator]() private var signOutFlowPresenter: SignOutFlowPresenter? // Tchap: Add invite service for user invitation - private var inviteService: InviteServiceType? +// private var inviteService: InviteServiceType? private var errorPresenter: ErrorPresenter? private weak var currentAlertController: UIAlertController? @@ -360,7 +360,7 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { !UserService.isExternalUser(for: userID) { subMenuActions.append(UIAction(title: TchapL10n.sideMenuActionInviteFriends, image: UIImage(systemName: "square.and.arrow.up.fill")) { [weak self] action in guard let self = self else { return } - self.showInviteFriends(from: self.avatarMenuButton) + self.allChatsViewController.startChat() }) } } @@ -644,15 +644,15 @@ class AllChatsCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { // } private func showInviteFriends(from sourceView: UIView?) { - // Tchap: Use Tchap specific mechanism. - promptUserToFillAnEmailToInvite { [weak self] email in - self?.sendEmailInvite(to: email) - } - -// let myUserId = self.parameters.userSessionsService.mainUserSession?.userId ?? "" -// -// let inviteFriendsPresenter = InviteFriendsPresenter() -// inviteFriendsPresenter.present(for: myUserId, from: self.navigationRouter.toPresentable(), sourceView: sourceView, animated: true) +// // Tchap: Use Tchap specific mechanism. +// promptUserToFillAnEmailToInvite { [weak self] email in +// self?.sendEmailInvite(to: email) +// } +// +//// let myUserId = self.parameters.userSessionsService.mainUserSession?.userId ?? "" +//// +//// let inviteFriendsPresenter = InviteFriendsPresenter() +//// inviteFriendsPresenter.present(for: myUserId, from: self.navigationRouter.toPresentable(), sourceView: sourceView, animated: true) } private func showBugReport() { @@ -911,55 +911,55 @@ extension AllChatsCoordinator { } private func sendEmailInvite(to email: String) { - guard let session = self.currentMatrixSession else { return } - if self.inviteService == nil { - self.inviteService = InviteService(session: session) - } - guard let inviteService = self.inviteService else { return } - - self.activityIndicatorPresenter.presentActivityIndicator(on: self.navigationRouter.toPresentable().view, animated: true) - inviteService.sendEmailInvite(to: email) { [weak self] (response) in - guard let sself = self else { - return - } - - sself.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true) - switch response { - case .success(let result): - var message: String - var discoveredUserID: String? - switch result { - case .inviteHasBeenSent(roomID: _): - message = TchapL10n.inviteSendingSucceeded - case .inviteAlreadySent(roomID: _): - message = TchapL10n.inviteAlreadySentByEmail(email) - case .inviteIgnoredForDiscoveredUser(userID: let userID): - discoveredUserID = userID - message = TchapL10n.inviteNotSentForDiscoveredUser - case .inviteIgnoredForUnauthorizedEmail: - message = TchapL10n.inviteNotSentForUnauthorizedEmail(email) - } - - sself.currentAlertController?.dismiss(animated: false) - - let alert = UIAlertController(title: TchapL10n.inviteInformationTitle, message: message, preferredStyle: .alert) - - let okTitle = VectorL10n.ok - let okAction = UIAlertAction(title: okTitle, style: .default, handler: { action in - if let userID = discoveredUserID { - // Open the discussion - AppDelegate.theDelegate().startDirectChat(withUserId: userID, completion: nil) - } - }) - alert.addAction(okAction) - sself.currentAlertController = alert - - sself.navigationRouter.toPresentable().present(alert, animated: true, completion: nil) - case .failure(let error): - let errorPresentable = sself.inviteErrorPresentable(from: error) - sself.errorPresenter?.present(errorPresentable: errorPresentable, animated: true) - } - } +// guard let session = self.currentMatrixSession else { return } +// if self.inviteService == nil { +// self.inviteService = InviteService(session: session) +// } +// guard let inviteService = self.inviteService else { return } +// +// self.activityIndicatorPresenter.presentActivityIndicator(on: self.navigationRouter.toPresentable().view, animated: true) +// inviteService.sendEmailInvite(to: email) { [weak self] (response) in +// guard let sself = self else { +// return +// } +// +// sself.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true) +// switch response { +// case .success(let result): +// var message: String +// var discoveredUserID: String? +// switch result { +// case .inviteHasBeenSent(roomID: _): +// message = TchapL10n.inviteSendingSucceeded +// case .inviteAlreadySent(roomID: _): +// message = TchapL10n.inviteAlreadySentByEmail(email) +// case .inviteIgnoredForDiscoveredUser(userID: let userID): +// discoveredUserID = userID +// message = TchapL10n.inviteNotSentForDiscoveredUser +// case .inviteIgnoredForUnauthorizedEmail: +// message = TchapL10n.inviteNotSentForUnauthorizedEmail(email) +// } +// +// sself.currentAlertController?.dismiss(animated: false) +// +// let alert = UIAlertController(title: TchapL10n.inviteInformationTitle, message: message, preferredStyle: .alert) +// +// let okTitle = VectorL10n.ok +// let okAction = UIAlertAction(title: okTitle, style: .default, handler: { action in +// if let userID = discoveredUserID { +// // Open the discussion +// AppDelegate.theDelegate().startDirectChat(withUserId: userID, completion: nil) +// } +// }) +// alert.addAction(okAction) +// sself.currentAlertController = alert +// +// sself.navigationRouter.toPresentable().present(alert, animated: true, completion: nil) +// case .failure(let error): +// let errorPresentable = sself.inviteErrorPresentable(from: error) +// sself.errorPresenter?.present(errorPresentable: errorPresentable, animated: true) +// } +// } } private func inviteErrorPresentable(from error: Error) -> ErrorPresentable { diff --git a/Riot/Modules/TabBar/TabBarCoordinator.swift b/Riot/Modules/TabBar/TabBarCoordinator.swift index f2e916abca..9219807277 100644 --- a/Riot/Modules/TabBar/TabBarCoordinator.swift +++ b/Riot/Modules/TabBar/TabBarCoordinator.swift @@ -71,7 +71,7 @@ final class TabBarCoordinator: NSObject, SplitViewMasterCoordinatorProtocol { private var indicators = [UserIndicator]() // Tchap: Add invite service for user invitation - private var inviteService: InviteServiceType? +// private var inviteService: InviteServiceType? private var errorPresenter: ErrorPresenter? private weak var currentAlertController: UIAlertController? @@ -1020,55 +1020,55 @@ extension TabBarCoordinator { } private func sendEmailInvite(to email: String) { - guard let session = self.currentMatrixSession else { return } - if self.inviteService == nil { - self.inviteService = InviteService(session: session) - } - guard let inviteService = self.inviteService else { return } - - self.activityIndicatorPresenter.presentActivityIndicator(on: masterTabBarController.view, animated: true) - inviteService.sendEmailInvite(to: email) { [weak self] (response) in - guard let sself = self else { - return - } - - sself.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true) - switch response { - case .success(let result): - var message: String - var discoveredUserID: String? - switch result { - case .inviteHasBeenSent(roomID: _): - message = TchapL10n.inviteSendingSucceeded - case .inviteAlreadySent(roomID: _): - message = TchapL10n.inviteAlreadySentByEmail(email) - case .inviteIgnoredForDiscoveredUser(userID: let userID): - discoveredUserID = userID - message = TchapL10n.inviteNotSentForDiscoveredUser - case .inviteIgnoredForUnauthorizedEmail: - message = TchapL10n.inviteNotSentForUnauthorizedEmail(email) - } - - sself.currentAlertController?.dismiss(animated: false) - - let alert = UIAlertController(title: TchapL10n.inviteInformationTitle, message: message, preferredStyle: .alert) - - let okTitle = VectorL10n.ok - let okAction = UIAlertAction(title: okTitle, style: .default, handler: { action in - if let userID = discoveredUserID { - // Open the discussion - AppDelegate.theDelegate().startDirectChat(withUserId: userID, completion: nil) - } - }) - alert.addAction(okAction) - sself.currentAlertController = alert - - sself.masterTabBarController.present(alert, animated: true, completion: nil) - case .failure(let error): - let errorPresentable = sself.inviteErrorPresentable(from: error) - sself.errorPresenter?.present(errorPresentable: errorPresentable, animated: true) - } - } +// guard let session = self.currentMatrixSession else { return } +// if self.inviteService == nil { +// self.inviteService = InviteService(session: session) +// } +// guard let inviteService = self.inviteService else { return } +// +// self.activityIndicatorPresenter.presentActivityIndicator(on: masterTabBarController.view, animated: true) +// inviteService.sendEmailInvite(to: email) { [weak self] (response) in +// guard let sself = self else { +// return +// } +// +// sself.activityIndicatorPresenter.removeCurrentActivityIndicator(animated: true) +// switch response { +// case .success(let result): +// var message: String +// var discoveredUserID: String? +// switch result { +// case .inviteHasBeenSent(roomID: _): +// message = TchapL10n.inviteSendingSucceeded +// case .inviteAlreadySent(roomID: _): +// message = TchapL10n.inviteAlreadySentByEmail(email) +// case .inviteIgnoredForDiscoveredUser(userID: let userID): +// discoveredUserID = userID +// message = TchapL10n.inviteNotSentForDiscoveredUser +// case .inviteIgnoredForUnauthorizedEmail: +// message = TchapL10n.inviteNotSentForUnauthorizedEmail(email) +// } +// +// sself.currentAlertController?.dismiss(animated: false) +// +// let alert = UIAlertController(title: TchapL10n.inviteInformationTitle, message: message, preferredStyle: .alert) +// +// let okTitle = VectorL10n.ok +// let okAction = UIAlertAction(title: okTitle, style: .default, handler: { action in +// if let userID = discoveredUserID { +// // Open the discussion +// AppDelegate.theDelegate().startDirectChat(withUserId: userID, completion: nil) +// } +// }) +// alert.addAction(okAction) +// sself.currentAlertController = alert +// +// sself.masterTabBarController.present(alert, animated: true, completion: nil) +// case .failure(let error): +// let errorPresentable = sself.inviteErrorPresentable(from: error) +// sself.errorPresenter?.present(errorPresentable: errorPresentable, animated: true) +// } +// } } private func inviteErrorPresentable(from error: Error) -> ErrorPresentable { diff --git a/Tchap/Managers/Invite/InviteService.swift b/Tchap/Managers/Invite/InviteService.swift index 062bf568e7..3c9950e29e 100644 --- a/Tchap/Managers/Invite/InviteService.swift +++ b/Tchap/Managers/Invite/InviteService.swift @@ -14,187 +14,189 @@ limitations under the License. */ -import Foundation -import MatrixSDK - -enum InviteServiceError: Error { - case unknown -} - -/// `InviteService` is used to invite someone to join Tchap -final class InviteService: InviteServiceType { - - // MARK: Private - private let session: MXSession - - private let discussionFinder: DiscussionFinderType - private let userService: UserServiceType - private let roomService: RoomServiceType - - private var roomInProcess: MXRoom? - - // MARK: - Public - init(session: MXSession) { - self.session = session - self.discussionFinder = DiscussionFinder(session: session) - self.userService = UserService(session: session) - self.roomService = RoomService(session: session) - } - - func sendEmailInvite(to email: String, completion: @escaping (MXResponse) -> Void) { - // Start the invite process by checking whether a Tchap account has been created for this email. - self.discoverUser(with: email, completion: { [weak self] (response) in - switch response { - case .success(let result): - switch result { - case .bound(let userID): - completion(.success(.inviteIgnoredForDiscoveredUser(userID: userID))) - case .unbound: - // Pursue the invite process by checking whether an invite has been already sent - self?.discussionFinder.getDiscussionIdentifier(for: email) { [weak self] (response) in - guard let self = self else { - return - } - - switch response { - case .success(let result): - switch result { - case .joinedDiscussion(let roomID): - // There is already a discussion with this email - // We do not re-invite the NoTchapUser except if - // the email is bound to the external instance (for which the invites may expire). - self.userService.isEmailBoundToTheExternalHost(email) { [weak self] (response) in - switch response { - case .success(let isExternal): - if isExternal { - // Revoke the pending invite and leave this empty discussion, we will invite again this email. - // We don't have a way for the moment to check if the invite expired or not... - self?.revokePendingInviteAndLeave(roomID) { [weak self] (response) in - switch response { - case .success: - // Send the new invite - self?.createDiscussion(with: email, completion: completion) - case .failure: - // Ignore the error, notify the user that the invite has been already sent - completion(.success(.inviteAlreadySent(roomID: roomID))) - } - } - } else { - // Notify the user that the invite has been already sent - completion(.success(.inviteAlreadySent(roomID: roomID))) - } - case .failure: - // Ignore the error, notify the user that the invite has been already sent - completion(.success(.inviteAlreadySent(roomID: roomID))) - } - } - case .noDiscussion: - // Send the invite if the email is authorized - self.createDiscussion(with: email, completion: completion) - default: - break - } - case .failure(let error): - MXLog.debug("[InviteService] sendEmailInvite failed") - completion(MXResponse.failure(error)) - } - } - } - case .failure(let error): - completion(MXResponse.failure(error)) - } - }) - } - - // MARK: - Private - - // Check whether a Tchap account has been created for this email. The closure returns a nil identifier when no account exists. - private func discoverUser(with email: String, completion: @escaping (MXResponse) -> Void) { - guard let identityService = self.session.identityService else { - MXLog.debug("[InviteService] discoverUser failed") - completion(MXResponse.failure(InviteServiceError.unknown)) - return - } - let pid = MX3PID(medium: .email, address: email) - _ = identityService.lookup3PIDs([pid]) { response in - if let responseValue = response.value?[pid] { - completion(MXResponse.success(.bound(userID: responseValue))) - } else { - completion(MXResponse.success(.unbound)) - } - } - } - - private func createDiscussion(with email: String, completion: @escaping (MXResponse) -> Void) { - self.userService.isEmailAuthorized(email) { [weak self] (response) in - switch response { - case .success(let isAuthorized): - if isAuthorized { - guard let identityServer = self?.session.matrixRestClient.identityServer ?? self?.session.matrixRestClient.homeserver, - let identityServerURL = URL(string: identityServer), - let identityServerHost = identityServerURL.host else { - return - } - - let thirdPartyId = MXInvite3PID() - thirdPartyId.medium = MX3PID.Medium.email.identifier - thirdPartyId.address = email - thirdPartyId.identityServer = identityServerHost - - _ = self?.roomService.createDiscussionWithThirdPartyID(thirdPartyId, completion: { (response) in - switch response { - case .success(let roomID): - completion(.success(.inviteHasBeenSent(roomID: roomID))) - case .failure(let error): - MXLog.debug("[InviteService] createDiscussion failed") - completion(MXResponse.failure(error)) - } - }) - } else { - completion(.success(.inviteIgnoredForUnauthorizedEmail)) - } - - case .failure(let error): - completion(MXResponse.failure(error)) - } - } - } - - private func revokePendingInviteAndLeave(_ roomID: String, completion: @escaping (MXResponse) -> Void) { - guard let room = self.session.room(withRoomId: roomID) else { - MXLog.debug("[InviteService] unable to revoke invite") - completion(.failure(InviteServiceError.unknown)) - return - } - - roomInProcess = room - room.state { [weak self] roomState in - guard let self = self else { - return - } - - if let thirdPartyInvite = roomState?.thirdPartyInvites?.first, - let token = thirdPartyInvite.token { - self.roomInProcess?.sendStateEvent(.roomThirdPartyInvite, content: [:], stateKey: token) { [weak self] (response) in - guard let self = self else { - return - } - - switch response { - case .success: - // Leave now the room - self.session.leaveRoom(roomID, completion: completion) - case .failure(let error): - completion(.failure(error)) - } - - self.roomInProcess = nil - } - } else { - MXLog.debug("[InviteService] unable to revoke invite (no pending invite)") - self.session.leaveRoom(roomID, completion: completion) - self.roomInProcess = nil - } - } - } -} +//import Foundation +//import MatrixSDK +// +//enum InviteServiceError: Error { +// case unknown +//} +// +///// `InviteService` is used to invite someone to join Tchap +//final class InviteService: InviteServiceType { +// +// // MARK: Private +// private let session: MXSession +// +// private let discussionFinder: DiscussionFinderType +// private let userService: UserServiceType +// private let roomService: RoomServiceType +// +// private var roomInProcess: MXRoom? +// +// // MARK: - Public +// init(session: MXSession) { +// self.session = session +// self.discussionFinder = DiscussionFinder(session: session) +// self.userService = UserService(session: session) +// self.roomService = RoomService(session: session) +// } +// +// func sendEmailInvite(to email: String, completion: @escaping (MXResponse) -> Void) { +// // Start the invite process by checking whether a Tchap account has been created for this email. +// self.discoverUser(with: email, completion: { [weak self] (response) in +// switch response { +// case .success(let result): +// switch result { +// case .bound(let userID): +// completion(.success(.inviteIgnoredForDiscoveredUser(userID: userID))) +// case .unbound: +// // Pursue the invite process by checking whether an invite has been already sent +// self?.discussionFinder.getDiscussionIdentifier(for: email) { [weak self] (response) in +// guard let self = self else { +// return +// } +// +// switch response { +// case .success(let result): +// switch result { +// case .joinedDiscussion(let roomID): +// // There is already a discussion with this email +// // We do not re-invite the NoTchapUser except if +// // the email is bound to the external instance (for which the invites may expire). +// self.userService.isEmailBoundToTheExternalHost(email) { [weak self] (response) in +// switch response { +// case .success(let isExternal): +// if isExternal { +// // Revoke the pending invite and leave this empty discussion, we will invite again this email. +// // We don't have a way for the moment to check if the invite expired or not... +// self?.revokePendingInviteAndLeave(roomID) { [weak self] (response) in +// switch response { +// case .success: +// // Send the new invite +// self?.createDiscussion(with: email, completion: completion) +// case .failure: +// // Ignore the error, notify the user that the invite has been already sent +// completion(.success(.inviteAlreadySent(roomID: roomID))) +// } +// } +// } else { +// // Notify the user that the invite has been already sent +// completion(.success(.inviteAlreadySent(roomID: roomID))) +// } +// case .failure: +// // Ignore the error, notify the user that the invite has been already sent +// completion(.success(.inviteAlreadySent(roomID: roomID))) +// } +// } +// case .noDiscussion: +// // Send the invite if the email is authorized +// self.createDiscussion(with: email, completion: completion) +// default: +// break +// } +// case .failure(let error): +// MXLog.debug("[InviteService] sendEmailInvite failed") +// completion(MXResponse.failure(error)) +// } +// } +// } +// case .failure(let error): +// completion(MXResponse.failure(error)) +// } +// }) +// } +// +// // MARK: - Private +// +// // Check whether a Tchap account has been created for this email. The closure returns a nil identifier when no account exists. +// private func discoverUser(with email: String, completion: @escaping (MXResponse) -> Void) { +// guard let identityService = self.session.identityService else { +// MXLog.debug("[InviteService] discoverUser failed") +// completion(MXResponse.failure(InviteServiceError.unknown)) +// return +// } +// let pid = MX3PID(medium: .email, address: email) +// _ = identityService.lookup3PIDs([pid]) { response in +// if let responseValue = response.value?[pid] { +// completion(MXResponse.success(.bound(userID: responseValue))) +// } else { +// completion(MXResponse.success(.unbound)) +// } +// } +// } +// +// private func createDiscussion(with email: String, completion: @escaping (MXResponse) -> Void) { +// self.userService.isEmailAuthorized(email) { [weak self] (response) in +// switch response { +// case .success(let isAuthorized): +// if isAuthorized { +// guard +// let matrixRestClient = self?.session.matrixRestClient, +// let identityServer = matrixRestClient.identityServer ?? matrixRestClient.homeserver, +// let identityServerURL = URL(string: identityServer), +// let identityServerHost = identityServerURL.host else { +// return +// } +// +// let thirdPartyId = MXInvite3PID() +// thirdPartyId.medium = MX3PID.Medium.email.identifier +// thirdPartyId.address = email +// thirdPartyId.identityServer = identityServerHost +// +// _ = self?.roomService.createDiscussionWithThirdPartyID(thirdPartyId, completion: { (response) in +// switch response { +// case .success(let roomID): +// completion(.success(.inviteHasBeenSent(roomID: roomID))) +// case .failure(let error): +// MXLog.debug("[InviteService] createDiscussion failed") +// completion(MXResponse.failure(error)) +// } +// }) +// } else { +// completion(.success(.inviteIgnoredForUnauthorizedEmail)) +// } +// +// case .failure(let error): +// completion(MXResponse.failure(error)) +// } +// } +// } +// +// private func revokePendingInviteAndLeave(_ roomID: String, completion: @escaping (MXResponse) -> Void) { +// guard let room = self.session.room(withRoomId: roomID) else { +// MXLog.debug("[InviteService] unable to revoke invite") +// completion(.failure(InviteServiceError.unknown)) +// return +// } +// +// roomInProcess = room +// room.state { [weak self] roomState in +// guard let self = self else { +// return +// } +// +// if let thirdPartyInvite = roomState?.thirdPartyInvites?.first, +// let token = thirdPartyInvite.token { +// self.roomInProcess?.sendStateEvent(.roomThirdPartyInvite, content: [:], stateKey: token) { [weak self] (response) in +// guard let self = self else { +// return +// } +// +// switch response { +// case .success: +// // Leave now the room +// self.session.leaveRoom(roomID, completion: completion) +// case .failure(let error): +// completion(.failure(error)) +// } +// +// self.roomInProcess = nil +// } +// } else { +// MXLog.debug("[InviteService] unable to revoke invite (no pending invite)") +// self.session.leaveRoom(roomID, completion: completion) +// self.roomInProcess = nil +// } +// } +// } +//} diff --git a/Tchap/Managers/Invite/InviteServiceType.swift b/Tchap/Managers/Invite/InviteServiceType.swift index ca3c5ec147..9e36b5f943 100644 --- a/Tchap/Managers/Invite/InviteServiceType.swift +++ b/Tchap/Managers/Invite/InviteServiceType.swift @@ -16,28 +16,28 @@ import Foundation -/// List the different result cases -enum InviteServiceResult { - case inviteHasBeenSent(roomID: String) - case inviteAlreadySent(roomID: String) - case inviteIgnoredForDiscoveredUser(userID: String) - case inviteIgnoredForUnauthorizedEmail -} - - -/// List the different discover user result cases -enum InviteServiceDiscoverUserResult { - case bound(userID: String) - case unbound -} - -/// Protocol describing a service used to invite someone to join Tchap. -protocol InviteServiceType { - - /// Invite a contact by inviting him in a direct chat (if this is not already done). - /// - /// - Parameters: - /// - email: an email address. - /// - completion: A closure called when the operation complete. See InviteServiceResult values. - func sendEmailInvite(to email: String, completion: @escaping (MXResponse) -> Void) -} +///// List the different result cases +//enum { +// case inviteHasBeenSent(roomID: String) +// case inviteAlreadySent(roomID: String) +// case inviteIgnoredForDiscoveredUser(userID: String) +// case inviteIgnoredForUnauthorizedEmail +//} +// +// +///// List the different discover user result cases +//enum InviteServiceDiscoverUserResult { +// case bound(userID: String) +// case unbound +//} +// +///// Protocol describing a service used to invite someone to join Tchap. +//protocol InviteServiceType { +// +// /// Invite a contact by inviting him in a direct chat (if this is not already done). +// /// +// /// - Parameters: +// /// - email: an email address. +// /// - completion: A closure called when the operation complete. See InviteServiceResult values. +// func sendEmailInvite(to email: String, completion: @escaping (MXResponse) -> Void) +//} From 0a3580266a83fbee0c3842eef4e50a490ebc42d9 Mon Sep 17 00:00:00 2001 From: Nicolas Buquet Date: Tue, 10 Oct 2023 18:35:02 +0200 Subject: [PATCH 2/2] Add changelog --- changelog.d/837.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/837.bugfix diff --git a/changelog.d/837.bugfix b/changelog.d/837.bugfix new file mode 100644 index 0000000000..3c6e5c59d5 --- /dev/null +++ b/changelog.d/837.bugfix @@ -0,0 +1 @@ +Réparer la fonctionnalité “Inviter à rejoindre Tchap”