NCAPIControllerExtensions.swift 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. //
  2. // SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
  3. // SPDX-License-Identifier: GPL-3.0-or-later
  4. //
  5. import Foundation
  6. @objc extension NCAPIController {
  7. // MARK: - Rooms Controller
  8. public func getRooms(forAccount account: TalkAccount, updateStatus: Bool, modifiedSince: Int, completionBlock: @escaping (_ rooms: [[String: AnyObject]]?, _ error: Error?) -> Void) {
  9. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  10. else { return }
  11. let apiVersion = self.conversationAPIVersion(for: account)
  12. var urlString = self.getRequestURL(forEndpoint: "room", withAPIVersion: apiVersion, for: account)
  13. let serverCapabilities = NCDatabaseManager.sharedInstance().serverCapabilities(forAccountId: account.accountId)
  14. let parameters: [String: Any] = [
  15. "noStatusUpdate": !updateStatus,
  16. "modifiedSince": modifiedSince
  17. ]
  18. // Since we are using "modifiedSince" only in background fetches
  19. // we will request including user status only when getting the complete room list
  20. if serverCapabilities?.userStatus == true, modifiedSince == 0 {
  21. urlString = urlString.appending("?includeStatus=true")
  22. }
  23. apiSessionManager.getOcs(urlString, account: account, parameters: parameters) { ocs, error in
  24. // TODO: Move away from generic dictionary return type
  25. // let rooms = ocs?.dataArrayDict.compactMap { NCRoom(dictionary: $0, andAccountId: account.accountId) }
  26. completionBlock(ocs?.dataArrayDict, error)
  27. }
  28. }
  29. public func getRoom(forAccount account: TalkAccount, withToken token: String, completionBlock: @escaping (_ room: [String: AnyObject]?, _ error: Error?) -> Void) {
  30. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
  31. let encodedToken = token.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
  32. else { return }
  33. let apiVersion = self.conversationAPIVersion(for: account)
  34. let urlString = self.getRequestURL(forEndpoint: "room/\(encodedToken)", withAPIVersion: apiVersion, for: account)
  35. apiSessionManager.getOcs(urlString, account: account) { ocs, error in
  36. completionBlock(ocs?.dataDict, error)
  37. }
  38. }
  39. public func getNoteToSelfRoom(forAccount account: TalkAccount, completionBlock: @escaping (_ room: [String: AnyObject]?, _ error: Error?) -> Void) {
  40. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  41. else { return }
  42. let apiVersion = self.conversationAPIVersion(for: account)
  43. let urlString = self.getRequestURL(forEndpoint: "room/note-to-self", withAPIVersion: apiVersion, for: account)
  44. apiSessionManager.getOcs(urlString, account: account) { ocs, error in
  45. completionBlock(ocs?.dataDict, error)
  46. }
  47. }
  48. public func getListableRooms(forAccount account: TalkAccount, withSerachTerm searchTerm: String?, completionBlock: @escaping (_ rooms: [NCRoom]?, _ error: Error?) -> Void) {
  49. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  50. else { return }
  51. let apiVersion = self.conversationAPIVersion(for: account)
  52. let urlString = self.getRequestURL(forEndpoint: "listed-room", withAPIVersion: apiVersion, for: account)
  53. var parameters: [String: Any] = [:]
  54. if let searchTerm, !searchTerm.isEmpty {
  55. parameters["searchTerm"] = searchTerm
  56. }
  57. apiSessionManager.getOcs(urlString, account: account, parameters: parameters) { ocs, error in
  58. let rooms = ocs?.dataArrayDict?.compactMap { NCRoom(dictionary: $0, andAccountId: account.accountId) }
  59. completionBlock(rooms, error)
  60. }
  61. }
  62. public func createRoom(forAccount account: TalkAccount, withInvite invite: String?, ofType roomType: NCRoomType, andName roomName: String?, completionBlock: @escaping (_ room: NCRoom?, _ error: Error?) -> Void) {
  63. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  64. else { return }
  65. let apiVersion = self.conversationAPIVersion(for: account)
  66. let urlString = self.getRequestURL(forEndpoint: "room", withAPIVersion: apiVersion, for: account)
  67. var parameters: [String: Any] = ["roomType": roomType.rawValue]
  68. if let invite, !invite.isEmpty {
  69. parameters["invite"] = invite
  70. }
  71. if let roomName, !roomName.isEmpty {
  72. parameters["roomName"] = roomName
  73. }
  74. apiSessionManager.postOcs(urlString, account: account, parameters: parameters) { ocs, error in
  75. let room = NCRoom(dictionary: ocs?.dataDict, andAccountId: account.accountId)
  76. completionBlock(room, error)
  77. }
  78. }
  79. public func renameRoom(_ token: String, forAccount account: TalkAccount, withName roomName: String, completionBlock: @escaping (_ error: Error?) -> Void) {
  80. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
  81. let encodedToken = token.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
  82. else { return }
  83. let apiVersion = self.conversationAPIVersion(for: account)
  84. let urlString = self.getRequestURL(forEndpoint: "room/\(encodedToken)", withAPIVersion: apiVersion, for: account)
  85. let parameters: [String: String] = ["roomName": roomName]
  86. apiSessionManager.putOcs(urlString, account: account, parameters: parameters) { _, error in
  87. completionBlock(error)
  88. }
  89. }
  90. public func setRoomDescription(_ description: String?, forRoom token: String, forAccount account: TalkAccount, completionBlock: @escaping (_ error: Error?) -> Void) {
  91. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
  92. let encodedToken = token.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
  93. else { return }
  94. let apiVersion = self.conversationAPIVersion(for: account)
  95. let urlString = self.getRequestURL(forEndpoint: "room/\(encodedToken)/description", withAPIVersion: apiVersion, for: account)
  96. let parameters: [String: String] = ["description": description ?? ""]
  97. apiSessionManager.putOcs(urlString, account: account, parameters: parameters) { _, error in
  98. completionBlock(error)
  99. }
  100. }
  101. public func setMentionPermissions(_ permissions: NCRoomMentionPermissions, forRoom token: String, forAccount account: TalkAccount, completionBlock: @escaping (_ error: Error?) -> Void) {
  102. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
  103. let encodedToken = token.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
  104. else { return }
  105. let apiVersion = self.conversationAPIVersion(for: account)
  106. let urlString = self.getRequestURL(forEndpoint: "room/\(encodedToken)/mention-permissions", withAPIVersion: apiVersion, for: account)
  107. let parameters: [String: Int] = ["mentionPermissions": permissions.rawValue]
  108. apiSessionManager.putOcs(urlString, account: account, parameters: parameters) { _, error in
  109. completionBlock(error)
  110. }
  111. }
  112. // MARK: - Federation
  113. public func acceptFederationInvitation(for accountId: String, with invitationId: Int, completionBlock: @escaping (_ success: Bool) -> Void) {
  114. let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId)!
  115. let apiVersion = self.federationAPIVersion(for: account)
  116. let urlString = self.getRequestURL(forEndpoint: "federation/invitation/\(invitationId)", withAPIVersion: apiVersion, for: account)
  117. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  118. else {
  119. completionBlock(false)
  120. return
  121. }
  122. apiSessionManager.postOcs(urlString, account: account) { _, error in
  123. completionBlock(error == nil)
  124. }
  125. }
  126. public func rejectFederationInvitation(for accountId: String, with invitationId: Int, completionBlock: @escaping (_ success: Bool) -> Void) {
  127. let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId)!
  128. let apiVersion = self.federationAPIVersion(for: account)
  129. let urlString = self.getRequestURL(forEndpoint: "federation/invitation/\(invitationId)", withAPIVersion: apiVersion, for: account)
  130. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  131. else {
  132. completionBlock(false)
  133. return
  134. }
  135. apiSessionManager.deleteOcs(urlString, account: account) { _, error in
  136. completionBlock(error == nil)
  137. }
  138. }
  139. public func getFederationInvitations(for accountId: String, completionBlock: @escaping (_ invitations: [FederationInvitation]?) -> Void) {
  140. guard let apiSessionManager = self.apiSessionManagers.object(forKey: accountId) as? NCAPISessionManager,
  141. let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId)
  142. else {
  143. completionBlock(nil)
  144. return
  145. }
  146. let apiVersion = self.federationAPIVersion(for: account)
  147. let urlString = self.getRequestURL(forEndpoint: "federation/invitation", withAPIVersion: apiVersion, for: account)
  148. apiSessionManager.getOcs(urlString, account: account) { ocs, _ in
  149. let invitations = ocs?.dataArrayDict?.map { FederationInvitation(dictionary: $0, for: accountId) }
  150. completionBlock(invitations)
  151. NCDatabaseManager.sharedInstance().updateLastFederationInvitationUpdate(forAccountId: accountId, withTimestamp: Int(Date().timeIntervalSince1970))
  152. }
  153. }
  154. // MARK: - Room capabilities
  155. public func getRoomCapabilities(for accountId: String, token: String, completionBlock: @escaping (_ roomCapabilities: [String: AnyObject]?, _ proxyHash: String?) -> Void) {
  156. guard let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId),
  157. let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
  158. let encodedToken = token.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
  159. else {
  160. completionBlock(nil, nil)
  161. return
  162. }
  163. let apiVersion = self.conversationAPIVersion(for: account)
  164. let urlString = self.getRequestURL(forEndpoint: "room/\(encodedToken)/capabilities", withAPIVersion: apiVersion, for: account)
  165. apiSessionManager.getOcs(urlString, account: account) { ocs, _ in
  166. if let data = ocs?.dataDict,
  167. let response = ocs?.task?.response,
  168. let headers = self.getResponseHeaders(response) {
  169. // Need to use lowercase name in swift
  170. if let headerProxyHash = headers["x-nextcloud-talk-proxy-hash"] as? String {
  171. completionBlock(data, headerProxyHash)
  172. } else {
  173. completionBlock(data, nil)
  174. }
  175. } else {
  176. completionBlock(nil, nil)
  177. }
  178. }
  179. }
  180. // MARK: - Signaling
  181. @discardableResult
  182. public func getSignalingSettings(for account: TalkAccount, forRoom roomToken: String?, completionBlock: @escaping (_ signalingSettings: SignalingSettings?, _ error: (any Error)?) -> Void) -> URLSessionDataTask? {
  183. guard let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  184. else {
  185. completionBlock(nil, nil)
  186. return nil
  187. }
  188. let apiVersion = self.signalingAPIVersion(for: account)
  189. let urlString = self.getRequestURL(forEndpoint: "signaling/settings", withAPIVersion: apiVersion, for: account)
  190. var parameters: [String: Any]?
  191. if let roomToken, let encodedToken = roomToken.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) {
  192. parameters = [
  193. "token": encodedToken
  194. ]
  195. }
  196. return apiSessionManager.getOcs(urlString, account: account, parameters: parameters) { ocs, error in
  197. completionBlock(SignalingSettings(dictionary: ocs?.dataDict), error)
  198. }
  199. }
  200. // MARK: - Mentions
  201. public func getMentionSuggestions(for accountId: String, in roomToken: String, with searchString: String, completionBlock: @escaping (_ mentions: [MentionSuggestion]?) -> Void) {
  202. guard let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId),
  203. let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager,
  204. let encodedToken = roomToken.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed),
  205. let serverCapabilities = NCDatabaseManager.sharedInstance().serverCapabilities(forAccountId: account.accountId)
  206. else {
  207. completionBlock(nil)
  208. return
  209. }
  210. let apiVersion = self.chatAPIVersion(for: account)
  211. let urlString = self.getRequestURL(forEndpoint: "chat/\(encodedToken)/mentions", withAPIVersion: apiVersion, for: account)
  212. let parameters: [String: Any] = [
  213. "limit": 20,
  214. "search": searchString,
  215. "includeStatus": serverCapabilities.userStatus
  216. ]
  217. apiSessionManager.getOcs(urlString, account: account, parameters: parameters) { ocs, _ in
  218. let mentions = ocs?.dataArrayDict?.map { MentionSuggestion(dictionary: $0) }
  219. completionBlock(mentions)
  220. }
  221. }
  222. // MARK: - Ban
  223. public func banActor(for accountId: String, in roomToken: String, with actorType: String, with actorId: String, with internalNote: String?, completionBlock: @escaping (_ success: Bool) -> Void) {
  224. guard let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId),
  225. let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  226. else {
  227. completionBlock(false)
  228. return
  229. }
  230. let apiVersion = self.banAPIVersion(for: account)
  231. let urlString = self.getRequestURL(forEndpoint: "ban/\(roomToken)", withAPIVersion: apiVersion, for: account)
  232. var parameters: [String: Any] = [
  233. "actorType": actorType,
  234. "actorId": actorId
  235. ]
  236. if let internalNote, !internalNote.isEmpty {
  237. parameters["internalNote"] = internalNote
  238. }
  239. apiSessionManager.post(urlString, parameters: parameters, progress: nil) { _, _ in
  240. completionBlock(true)
  241. } failure: { _, _ in
  242. completionBlock(false)
  243. }
  244. }
  245. public func listBans(for accountId: String, in roomToken: String, completionBlock: @escaping (_ bannedActors: [BannedActor]?) -> Void) {
  246. guard let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId),
  247. let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  248. else {
  249. completionBlock(nil)
  250. return
  251. }
  252. let apiVersion = self.banAPIVersion(for: account)
  253. let urlString = self.getRequestURL(forEndpoint: "ban/\(roomToken)", withAPIVersion: apiVersion, for: account)
  254. apiSessionManager.getOcs(urlString, account: account) { ocs, _ in
  255. let actorBans = ocs?.dataArrayDict?.map { BannedActor(dictionary: $0) }
  256. completionBlock(actorBans)
  257. }
  258. }
  259. public func unbanActor(for accountId: String, in roomToken: String, with banId: Int, completionBlock: @escaping (_ success: Bool) -> Void) {
  260. guard let account = NCDatabaseManager.sharedInstance().talkAccount(forAccountId: accountId),
  261. let apiSessionManager = self.apiSessionManagers.object(forKey: account.accountId) as? NCAPISessionManager
  262. else {
  263. completionBlock(false)
  264. return
  265. }
  266. let apiVersion = self.banAPIVersion(for: account)
  267. let urlString = self.getRequestURL(forEndpoint: "ban/\(roomToken)/\(banId)", withAPIVersion: apiVersion, for: account)
  268. apiSessionManager.delete(urlString, parameters: nil) { _, _ in
  269. completionBlock(true)
  270. } failure: { _, _ in
  271. completionBlock(false)
  272. }
  273. }
  274. }