NCManageDatabase.swift 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091
  1. //
  2. // NCManageDatabase.swift
  3. // Nextcloud
  4. //
  5. // Created by Marino Faggiana on 06/05/17.
  6. // Copyright © 2017 Marino Faggiana. All rights reserved.
  7. //
  8. // Author Marino Faggiana <marino.faggiana@nextcloud.com>
  9. // Author Henrik Storch <henrik.storch@nextcloud.com>
  10. //
  11. // This program is free software: you can redistribute it and/or modify
  12. // it under the terms of the GNU General Public License as published by
  13. // the Free Software Foundation, either version 3 of the License, or
  14. // (at your option) any later version.
  15. //
  16. // This program is distributed in the hope that it will be useful,
  17. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. // GNU General Public License for more details.
  20. //
  21. // You should have received a copy of the GNU General Public License
  22. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. //
  24. import UIKit
  25. import RealmSwift
  26. import NextcloudKit
  27. import SwiftyJSON
  28. import CoreMedia
  29. import Photos
  30. class NCManageDatabase: NSObject {
  31. @objc static let shared: NCManageDatabase = {
  32. let instance = NCManageDatabase()
  33. return instance
  34. }()
  35. override init() {
  36. let dirGroup = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: NCBrandOptions.shared.capabilitiesGroups)
  37. let databaseFileUrlPath = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName)
  38. let bundleUrl: URL = Bundle.main.bundleURL
  39. let bundlePathExtension: String = bundleUrl.pathExtension
  40. let isAppex: Bool = bundlePathExtension == "appex"
  41. if let databaseFilePath = databaseFileUrlPath?.path {
  42. if FileManager.default.fileExists(atPath: databaseFilePath) {
  43. NextcloudKit.shared.nkCommonInstance.writeLog("DATABASE FOUND in " + databaseFilePath)
  44. } else {
  45. NextcloudKit.shared.nkCommonInstance.writeLog("DATABASE NOT FOUND in " + databaseFilePath)
  46. }
  47. }
  48. // Disable file protection for directory DB
  49. // https://docs.mongodb.com/realm/sdk/ios/examples/configure-and-open-a-realm/#std-label-ios-open-a-local-realm
  50. if let folderPathURL = dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud) {
  51. let folderPath = folderPathURL.path
  52. do {
  53. try FileManager.default.setAttributes([FileAttributeKey.protectionKey: FileProtectionType.completeUntilFirstUserAuthentication], ofItemAtPath: folderPath)
  54. } catch {
  55. print("Dangerous error")
  56. }
  57. }
  58. if isAppex {
  59. // App Extension config
  60. let config = Realm.Configuration(
  61. fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName),
  62. schemaVersion: databaseSchemaVersion,
  63. objectTypes: [tableMetadata.self, tableLocalFile.self, tableDirectory.self, tableTag.self, tableAccount.self, tableCapabilities.self, tablePhotoLibrary.self, tableE2eEncryption.self, tableE2eEncryptionLock.self, tableE2eMetadata.self, tableShare.self, tableChunk.self, tableAvatar.self, tableDashboardWidget.self, tableDashboardWidgetButton.self, NCDBLayoutForView.self]
  64. )
  65. Realm.Configuration.defaultConfiguration = config
  66. } else {
  67. // App config
  68. let configCompact = Realm.Configuration(
  69. fileURL: databaseFileUrlPath,
  70. schemaVersion: databaseSchemaVersion,
  71. migrationBlock: { migration, oldSchemaVersion in
  72. if oldSchemaVersion < 255 {
  73. migration.deleteData(forType: tableActivity.className())
  74. migration.deleteData(forType: tableActivityLatestId.className())
  75. migration.deleteData(forType: tableActivityPreview.className())
  76. migration.deleteData(forType: tableActivitySubjectRich.className())
  77. migration.deleteData(forType: tableDirectory.className())
  78. migration.deleteData(forType: tableMetadata.className())
  79. }
  80. if oldSchemaVersion < 292 {
  81. migration.deleteData(forType: tableVideo.className())
  82. }
  83. }, shouldCompactOnLaunch: { totalBytes, usedBytes in
  84. // totalBytes refers to the size of the file on disk in bytes (data + free space)
  85. // usedBytes refers to the number of bytes used by data in the file
  86. // Compact if the file is over 100MB in size and less than 50% 'used'
  87. let oneHundredMB = 100 * 1024 * 1024
  88. return (totalBytes > oneHundredMB) && (Double(usedBytes) / Double(totalBytes)) < 0.5
  89. }
  90. )
  91. do {
  92. _ = try Realm(configuration: configCompact)
  93. } catch let error {
  94. if let databaseFileUrlPath = databaseFileUrlPath {
  95. do {
  96. #if !EXTENSION
  97. let nkError = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: error.localizedDescription)
  98. NCContentPresenter.shared.showError(error: nkError, priority: .max)
  99. #endif
  100. NextcloudKit.shared.nkCommonInstance.writeLog("DATABASE ERROR: \(error.localizedDescription)")
  101. try FileManager.default.removeItem(at: databaseFileUrlPath)
  102. } catch {}
  103. }
  104. }
  105. let config = Realm.Configuration(
  106. fileURL: dirGroup?.appendingPathComponent(NCGlobal.shared.appDatabaseNextcloud + "/" + databaseName),
  107. schemaVersion: databaseSchemaVersion
  108. )
  109. Realm.Configuration.defaultConfiguration = config
  110. }
  111. // Verify Database, if corrupt remove it
  112. do {
  113. _ = try Realm()
  114. } catch let error {
  115. if let databaseFileUrlPath = databaseFileUrlPath {
  116. do {
  117. #if !EXTENSION
  118. let nkError = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: error.localizedDescription)
  119. NCContentPresenter.shared.showError(error: nkError, priority: .max)
  120. #endif
  121. NextcloudKit.shared.nkCommonInstance.writeLog("DATABASE ERROR: \(error.localizedDescription)")
  122. try FileManager.default.removeItem(at: databaseFileUrlPath)
  123. } catch { }
  124. }
  125. }
  126. // Open Real
  127. _ = try! Realm()
  128. }
  129. // MARK: -
  130. // MARK: Utility Database
  131. @objc func clearTable(_ table: Object.Type, account: String? = nil) {
  132. let realm = try! Realm()
  133. do {
  134. try realm.write {
  135. var results: Results<Object>
  136. if let account = account {
  137. results = realm.objects(table).filter("account == %@", account)
  138. } else {
  139. results = realm.objects(table)
  140. }
  141. realm.delete(results)
  142. }
  143. } catch let error {
  144. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  145. }
  146. }
  147. @objc func clearDatabase(account: String?, removeAccount: Bool) {
  148. self.clearTable(tableActivity.self, account: account)
  149. self.clearTable(tableActivityLatestId.self, account: account)
  150. self.clearTable(tableActivityPreview.self, account: account)
  151. self.clearTable(tableActivitySubjectRich.self, account: account)
  152. self.clearTable(tableAvatar.self)
  153. self.clearTable(tableCapabilities.self, account: account)
  154. self.clearTable(tableChunk.self, account: account)
  155. self.clearTable(tableComments.self, account: account)
  156. self.clearTable(tableDashboardWidget.self, account: account)
  157. self.clearTable(tableDashboardWidgetButton.self, account: account)
  158. self.clearTable(tableDirectEditingCreators.self, account: account)
  159. self.clearTable(tableDirectEditingEditors.self, account: account)
  160. self.clearTable(tableDirectory.self, account: account)
  161. self.clearTable(tableE2eEncryption.self, account: account)
  162. self.clearTable(tableE2eEncryptionLock.self, account: account)
  163. self.clearTable(tableE2eMetadata.self, account: account)
  164. self.clearTable(tableExternalSites.self, account: account)
  165. self.clearTable(tableGPS.self, account: nil)
  166. self.clearTable(TableGroupfolders.self, account: account)
  167. self.clearTable(TableGroupfoldersGroups.self, account: account)
  168. self.clearTable(NCDBLayoutForView.self, account: account)
  169. self.clearTable(tableLocalFile.self, account: account)
  170. self.clearTable(tableMetadata.self, account: account)
  171. self.clearTable(tablePhotoLibrary.self, account: account)
  172. self.clearTable(tableShare.self, account: account)
  173. self.clearTable(tableTag.self, account: account)
  174. self.clearTable(tableTip.self)
  175. self.clearTable(tableTrash.self, account: account)
  176. self.clearTable(tableUserStatus.self, account: account)
  177. self.clearTable(tableVideo.self, account: account)
  178. if removeAccount {
  179. self.clearTable(tableAccount.self, account: account)
  180. }
  181. }
  182. @objc func removeDB() {
  183. let realmURL = Realm.Configuration.defaultConfiguration.fileURL!
  184. let realmURLs = [
  185. realmURL,
  186. realmURL.appendingPathExtension("lock"),
  187. realmURL.appendingPathExtension("note"),
  188. realmURL.appendingPathExtension("management")
  189. ]
  190. for URL in realmURLs {
  191. do {
  192. try FileManager.default.removeItem(at: URL)
  193. } catch let error {
  194. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  195. }
  196. }
  197. }
  198. @objc func getThreadConfined(_ object: Object) -> Any {
  199. // id tradeReference = [[NCManageDatabase shared] getThreadConfined:metadata];
  200. return ThreadSafeReference(to: object)
  201. }
  202. @objc func putThreadConfined(_ tableRef: Any) -> Object? {
  203. // tableMetadata *metadataThread = (tableMetadata *)[[NCManageDatabase shared] putThreadConfined:tradeReference];
  204. let realm = try! Realm()
  205. return realm.resolve(tableRef as! ThreadSafeReference<Object>)
  206. }
  207. @objc func isTableInvalidated(_ object: Object) -> Bool {
  208. return object.isInvalidated
  209. }
  210. // MARK: -
  211. // MARK: Table Avatar
  212. // MARK: -
  213. // MARK: Table Capabilities
  214. func addCapabilitiesJSon(_ data: Data, account: String) {
  215. let realm = try! Realm()
  216. do {
  217. try realm.write {
  218. let addObject = tableCapabilities()
  219. addObject.account = account
  220. addObject.jsondata = data
  221. realm.add(addObject, update: .all)
  222. }
  223. } catch let error {
  224. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  225. }
  226. }
  227. func getCapabilities(account: String) -> String? {
  228. let realm = try! Realm()
  229. guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
  230. return nil
  231. }
  232. guard let jsondata = result.jsondata else {
  233. return nil
  234. }
  235. let json = JSON(jsondata)
  236. return json.rawString()?.replacingOccurrences(of: "\\/", with: "/")
  237. }
  238. @objc func getCapabilitiesServerString(account: String, elements: [String]) -> String? {
  239. let realm = try! Realm()
  240. guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
  241. return nil
  242. }
  243. guard let jsondata = result.jsondata else {
  244. return nil
  245. }
  246. let json = JSON(jsondata)
  247. return json[elements].string
  248. }
  249. func getCapabilitiesServerInt(account: String, elements: [String]) -> Int {
  250. let realm = try! Realm()
  251. guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first,
  252. let jsondata = result.jsondata else {
  253. return 0
  254. }
  255. let json = JSON(jsondata)
  256. return json[elements].intValue
  257. }
  258. @objc func getCapabilitiesServerBool(account: String, elements: [String], exists: Bool) -> Bool {
  259. let realm = try! Realm()
  260. guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
  261. return false
  262. }
  263. guard let jsondata = result.jsondata else {
  264. return false
  265. }
  266. let json = JSON(jsondata)
  267. if exists {
  268. return json[elements].exists()
  269. } else {
  270. return json[elements].boolValue
  271. }
  272. }
  273. func getCapabilitiesServerArray(account: String, elements: [String]) -> [String]? {
  274. let realm = try! Realm()
  275. var resultArray: [String] = []
  276. guard let result = realm.objects(tableCapabilities.self).filter("account == %@", account).first else {
  277. return nil
  278. }
  279. guard let jsondata = result.jsondata else {
  280. return nil
  281. }
  282. let json = JSON(jsondata)
  283. if let results = json[elements].array {
  284. for result in results {
  285. resultArray.append(result.string ?? "")
  286. }
  287. return resultArray
  288. }
  289. return nil
  290. }
  291. // MARK: -
  292. // MARK: Table Chunk
  293. func getChunkFolder(account: String, ocId: String) -> String {
  294. let realm = try! Realm()
  295. if let result = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).first {
  296. return result.chunkFolder
  297. }
  298. return NSUUID().uuidString
  299. }
  300. func getChunks(account: String, ocId: String) -> [String] {
  301. let realm = try! Realm()
  302. var filesNames: [String] = []
  303. let results = realm.objects(tableChunk.self).filter("account == %@ AND ocId == %@", account, ocId).sorted(byKeyPath: "fileName", ascending: true)
  304. for result in results {
  305. filesNames.append(result.fileName)
  306. }
  307. return filesNames
  308. }
  309. func addChunks(account: String, ocId: String, chunkFolder: String, fileNames: [String]) {
  310. let realm = try! Realm()
  311. var size: Int64 = 0
  312. do {
  313. try realm.write {
  314. for fileName in fileNames {
  315. let object = tableChunk()
  316. size += NCUtilityFileSystem.shared.getFileSize(filePath: CCUtility.getDirectoryProviderStorageOcId(ocId, fileNameView: fileName)!)
  317. object.account = account
  318. object.chunkFolder = chunkFolder
  319. object.fileName = fileName
  320. object.index = ocId + fileName
  321. object.ocId = ocId
  322. object.size = size
  323. realm.add(object, update: .all)
  324. }
  325. }
  326. } catch let error {
  327. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  328. }
  329. }
  330. func getChunk(account: String, fileName: String) -> tableChunk? {
  331. let realm = try! Realm()
  332. if let result = realm.objects(tableChunk.self).filter("account == %@ AND fileName == %@", account, fileName).first {
  333. return tableChunk.init(value: result)
  334. } else {
  335. return nil
  336. }
  337. }
  338. func deleteChunk(account: String, ocId: String, fileName: String) {
  339. let realm = try! Realm()
  340. do {
  341. try realm.write {
  342. let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@ AND fileName == %@", account, ocId, fileName))
  343. realm.delete(result)
  344. }
  345. } catch let error {
  346. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  347. }
  348. }
  349. func deleteChunks(account: String, ocId: String) {
  350. let realm = try! Realm()
  351. do {
  352. try realm.write {
  353. let result = realm.objects(tableChunk.self).filter(NSPredicate(format: "account == %@ AND ocId == %@", account, ocId))
  354. realm.delete(result)
  355. }
  356. } catch let error {
  357. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  358. }
  359. }
  360. // MARK: -
  361. // MARK: Table Direct Editing
  362. func addDirectEditing(account: String, editors: [NKEditorDetailsEditors], creators: [NKEditorDetailsCreators]) {
  363. let realm = try! Realm()
  364. do {
  365. try realm.write {
  366. let resultsCreators = realm.objects(tableDirectEditingCreators.self).filter("account == %@", account)
  367. realm.delete(resultsCreators)
  368. let resultsEditors = realm.objects(tableDirectEditingEditors.self).filter("account == %@", account)
  369. realm.delete(resultsEditors)
  370. for creator in creators {
  371. let addObject = tableDirectEditingCreators()
  372. addObject.account = account
  373. addObject.editor = creator.editor
  374. addObject.ext = creator.ext
  375. addObject.identifier = creator.identifier
  376. addObject.mimetype = creator.mimetype
  377. addObject.name = creator.name
  378. addObject.templates = creator.templates
  379. realm.add(addObject)
  380. }
  381. for editor in editors {
  382. let addObject = tableDirectEditingEditors()
  383. addObject.account = account
  384. for mimeType in editor.mimetypes {
  385. addObject.mimetypes.append(mimeType)
  386. }
  387. addObject.name = editor.name
  388. if editor.name.lowercased() == NCGlobal.shared.editorOnlyoffice {
  389. addObject.editor = NCGlobal.shared.editorOnlyoffice
  390. } else {
  391. addObject.editor = NCGlobal.shared.editorText
  392. }
  393. for mimeType in editor.optionalMimetypes {
  394. addObject.optionalMimetypes.append(mimeType)
  395. }
  396. addObject.secure = editor.secure
  397. realm.add(addObject)
  398. }
  399. }
  400. } catch let error {
  401. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  402. }
  403. }
  404. func getDirectEditingCreators(account: String) -> [tableDirectEditingCreators]? {
  405. let realm = try! Realm()
  406. let results = realm.objects(tableDirectEditingCreators.self).filter("account == %@", account)
  407. if results.count > 0 {
  408. return Array(results.map { tableDirectEditingCreators.init(value: $0) })
  409. } else {
  410. return nil
  411. }
  412. }
  413. func getDirectEditingCreators(predicate: NSPredicate) -> [tableDirectEditingCreators]? {
  414. let realm = try! Realm()
  415. let results = realm.objects(tableDirectEditingCreators.self).filter(predicate)
  416. if results.count > 0 {
  417. return Array(results.map { tableDirectEditingCreators.init(value: $0) })
  418. } else {
  419. return nil
  420. }
  421. }
  422. func getDirectEditingEditors(account: String) -> [tableDirectEditingEditors]? {
  423. let realm = try! Realm()
  424. let results = realm.objects(tableDirectEditingEditors.self).filter("account == %@", account)
  425. if results.count > 0 {
  426. return Array(results.map { tableDirectEditingEditors.init(value: $0) })
  427. } else {
  428. return nil
  429. }
  430. }
  431. // MARK: -
  432. // MARK: Table External Sites
  433. func addExternalSites(_ externalSite: NKExternalSite, account: String) {
  434. let realm = try! Realm()
  435. do {
  436. try realm.write {
  437. let addObject = tableExternalSites()
  438. addObject.account = account
  439. addObject.idExternalSite = externalSite.idExternalSite
  440. addObject.icon = externalSite.icon
  441. addObject.lang = externalSite.lang
  442. addObject.name = externalSite.name
  443. addObject.url = externalSite.url
  444. addObject.type = externalSite.type
  445. realm.add(addObject)
  446. }
  447. } catch let error {
  448. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  449. }
  450. }
  451. func deleteExternalSites(account: String) {
  452. let realm = try! Realm()
  453. do {
  454. try realm.write {
  455. let results = realm.objects(tableExternalSites.self).filter("account == %@", account)
  456. realm.delete(results)
  457. }
  458. } catch let error {
  459. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  460. }
  461. }
  462. func getAllExternalSites(account: String) -> [tableExternalSites]? {
  463. let realm = try! Realm()
  464. let results = realm.objects(tableExternalSites.self).filter("account == %@", account).sorted(byKeyPath: "idExternalSite", ascending: true)
  465. if results.count > 0 {
  466. return Array(results.map { tableExternalSites.init(value: $0) })
  467. } else {
  468. return nil
  469. }
  470. }
  471. // MARK: -
  472. // MARK: Table GPS
  473. @objc func addGeocoderLocation(_ location: String, placemarkAdministrativeArea: String, placemarkCountry: String, placemarkLocality: String, placemarkPostalCode: String, placemarkThoroughfare: String, latitude: String, longitude: String) {
  474. let realm = try! Realm()
  475. realm.beginWrite()
  476. // Verify if exists
  477. guard realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first == nil else {
  478. realm.cancelWrite()
  479. return
  480. }
  481. // Add new GPS
  482. let addObject = tableGPS()
  483. addObject.latitude = latitude
  484. addObject.location = location
  485. addObject.longitude = longitude
  486. addObject.placemarkAdministrativeArea = placemarkAdministrativeArea
  487. addObject.placemarkCountry = placemarkCountry
  488. addObject.placemarkLocality = placemarkLocality
  489. addObject.placemarkPostalCode = placemarkPostalCode
  490. addObject.placemarkThoroughfare = placemarkThoroughfare
  491. realm.add(addObject)
  492. do {
  493. try realm.commitWrite()
  494. } catch let error {
  495. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  496. }
  497. }
  498. @objc func getLocationFromGeoLatitude(_ latitude: String, longitude: String) -> String? {
  499. let realm = try! Realm()
  500. let result = realm.objects(tableGPS.self).filter("latitude == %@ AND longitude == %@", latitude, longitude).first
  501. return result?.location
  502. }
  503. // MARK: -
  504. // MARK: Table LocalFile
  505. func addLocalFile(metadata: tableMetadata) {
  506. let realm = try! Realm()
  507. do {
  508. try realm.write {
  509. let addObject = getTableLocalFile(predicate: NSPredicate(format: "ocId == %@", metadata.ocId)) ?? tableLocalFile()
  510. addObject.account = metadata.account
  511. addObject.etag = metadata.etag
  512. addObject.exifDate = NSDate()
  513. addObject.exifLatitude = "-1"
  514. addObject.exifLongitude = "-1"
  515. addObject.ocId = metadata.ocId
  516. addObject.fileName = metadata.fileName
  517. realm.add(addObject, update: .all)
  518. }
  519. } catch let error {
  520. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  521. }
  522. }
  523. func addLocalFile(account: String, etag: String, ocId: String, fileName: String) {
  524. let realm = try! Realm()
  525. do {
  526. try realm.write {
  527. let addObject = tableLocalFile()
  528. addObject.account = account
  529. addObject.etag = etag
  530. addObject.exifDate = NSDate()
  531. addObject.exifLatitude = "-1"
  532. addObject.exifLongitude = "-1"
  533. addObject.ocId = ocId
  534. addObject.fileName = fileName
  535. realm.add(addObject, update: .all)
  536. }
  537. } catch let error {
  538. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  539. }
  540. }
  541. func deleteLocalFile(predicate: NSPredicate) {
  542. let realm = try! Realm()
  543. do {
  544. try realm.write {
  545. let results = realm.objects(tableLocalFile.self).filter(predicate)
  546. realm.delete(results)
  547. }
  548. } catch let error {
  549. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  550. }
  551. }
  552. func setLocalFile(ocId: String, fileName: String?, etag: String?) {
  553. let realm = try! Realm()
  554. do {
  555. try realm.write {
  556. let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
  557. if let fileName = fileName {
  558. result?.fileName = fileName
  559. }
  560. if let etag = etag {
  561. result?.etag = etag
  562. }
  563. }
  564. } catch let error {
  565. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  566. }
  567. }
  568. @objc func setLocalFile(ocId: String, exifDate: NSDate?, exifLatitude: String, exifLongitude: String, exifLensModel: String?) {
  569. let realm = try! Realm()
  570. do {
  571. try realm.write {
  572. if let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first {
  573. result.exifDate = exifDate
  574. result.exifLatitude = exifLatitude
  575. result.exifLongitude = exifLongitude
  576. if exifLensModel?.count ?? 0 > 0 {
  577. result.exifLensModel = exifLensModel
  578. }
  579. }
  580. }
  581. } catch let error {
  582. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  583. }
  584. }
  585. func getTableLocalFile(account: String) -> [tableLocalFile] {
  586. let realm = try! Realm()
  587. let results = realm.objects(tableLocalFile.self).filter("account == %@", account)
  588. return Array(results.map { tableLocalFile.init(value: $0) })
  589. }
  590. func getTableLocalFile(predicate: NSPredicate) -> tableLocalFile? {
  591. let realm = try! Realm()
  592. guard let result = realm.objects(tableLocalFile.self).filter(predicate).first else {
  593. return nil
  594. }
  595. return tableLocalFile.init(value: result)
  596. }
  597. func getTableLocalFiles(predicate: NSPredicate, sorted: String, ascending: Bool) -> [tableLocalFile] {
  598. let realm = try! Realm()
  599. let results = realm.objects(tableLocalFile.self).filter(predicate).sorted(byKeyPath: sorted, ascending: ascending)
  600. return Array(results.map { tableLocalFile.init(value: $0) })
  601. }
  602. func setLocalFile(ocId: String, offline: Bool) {
  603. let realm = try! Realm()
  604. do {
  605. try realm.write {
  606. let result = realm.objects(tableLocalFile.self).filter("ocId == %@", ocId).first
  607. result?.offline = offline
  608. }
  609. } catch let error {
  610. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  611. }
  612. }
  613. // MARK: -
  614. // MARK: Table Photo Library
  615. @discardableResult
  616. func addPhotoLibrary(_ assets: [PHAsset], account: String) -> Bool {
  617. let realm = try! Realm()
  618. do {
  619. try realm.write {
  620. for asset in assets {
  621. var creationDateString = ""
  622. let addObject = tablePhotoLibrary()
  623. addObject.account = account
  624. addObject.assetLocalIdentifier = asset.localIdentifier
  625. addObject.mediaType = asset.mediaType.rawValue
  626. if let creationDate = asset.creationDate {
  627. addObject.creationDate = creationDate as NSDate
  628. creationDateString = String(describing: creationDate)
  629. }
  630. if let modificationDate = asset.modificationDate {
  631. addObject.modificationDate = modificationDate as NSDate
  632. }
  633. addObject.idAsset = account + asset.localIdentifier + creationDateString
  634. realm.add(addObject, update: .all)
  635. }
  636. }
  637. } catch let error {
  638. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  639. return false
  640. }
  641. return true
  642. }
  643. func getPhotoLibraryIdAsset(image: Bool, video: Bool, account: String) -> [String]? {
  644. let realm = try! Realm()
  645. var predicate = NSPredicate()
  646. if image && video {
  647. predicate = NSPredicate(format: "account == %@ AND (mediaType == %d OR mediaType == %d)", account, PHAssetMediaType.image.rawValue, PHAssetMediaType.video.rawValue)
  648. } else if image {
  649. predicate = NSPredicate(format: "account == %@ AND mediaType == %d", account, PHAssetMediaType.image.rawValue)
  650. } else if video {
  651. predicate = NSPredicate(format: "account == %@ AND mediaType == %d", account, PHAssetMediaType.video.rawValue)
  652. }
  653. let results = realm.objects(tablePhotoLibrary.self).filter(predicate)
  654. let idsAsset = results.map { $0.idAsset }
  655. return Array(idsAsset)
  656. }
  657. // MARK: -
  658. // MARK: Table Tag
  659. func addTag(_ ocId: String, tagIOS: Data?, account: String) {
  660. let realm = try! Realm()
  661. do {
  662. try realm.write {
  663. // Add new
  664. let addObject = tableTag()
  665. addObject.account = account
  666. addObject.ocId = ocId
  667. addObject.tagIOS = tagIOS
  668. realm.add(addObject, update: .all)
  669. }
  670. } catch let error {
  671. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  672. }
  673. }
  674. func deleteTag(_ ocId: String) {
  675. let realm = try! Realm()
  676. realm.beginWrite()
  677. let result = realm.objects(tableTag.self).filter("ocId == %@", ocId)
  678. realm.delete(result)
  679. do {
  680. try realm.commitWrite()
  681. } catch let error {
  682. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  683. }
  684. }
  685. func getTags(predicate: NSPredicate) -> [tableTag] {
  686. let realm = try! Realm()
  687. let results = realm.objects(tableTag.self).filter(predicate)
  688. return Array(results.map { tableTag.init(value: $0) })
  689. }
  690. func getTag(predicate: NSPredicate) -> tableTag? {
  691. let realm = try! Realm()
  692. guard let result = realm.objects(tableTag.self).filter(predicate).first else {
  693. return nil
  694. }
  695. return tableTag.init(value: result)
  696. }
  697. // MARK: -
  698. // MARK: Table Tip
  699. func tipExists(_ tipName: String) -> Bool {
  700. let realm = try! Realm()
  701. guard (realm.objects(tableTip.self).where {
  702. $0.tipName == tipName
  703. }.first) == nil else {
  704. return true
  705. }
  706. return false
  707. }
  708. func addTip(_ tipName: String) {
  709. let realm = try! Realm()
  710. do {
  711. try realm.write {
  712. let addObject = tableTip()
  713. addObject.tipName = tipName
  714. realm.add(addObject, update: .all)
  715. }
  716. } catch let error {
  717. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  718. }
  719. }
  720. // MARK: -
  721. // MARK: Table Trash
  722. func addTrash(account: String, items: [NKTrash]) {
  723. let realm = try! Realm()
  724. do {
  725. try realm.write {
  726. for trash in items {
  727. let object = tableTrash()
  728. object.account = account
  729. object.contentType = trash.contentType
  730. object.date = trash.date
  731. object.directory = trash.directory
  732. object.fileId = trash.fileId
  733. object.fileName = trash.fileName
  734. object.filePath = trash.filePath
  735. object.hasPreview = trash.hasPreview
  736. object.iconName = trash.iconName
  737. object.size = trash.size
  738. object.trashbinDeletionTime = trash.trashbinDeletionTime
  739. object.trashbinFileName = trash.trashbinFileName
  740. object.trashbinOriginalLocation = trash.trashbinOriginalLocation
  741. object.classFile = trash.classFile
  742. realm.add(object, update: .all)
  743. }
  744. }
  745. } catch let error {
  746. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  747. }
  748. }
  749. func deleteTrash(filePath: String?, account: String) {
  750. let realm = try! Realm()
  751. var predicate = NSPredicate()
  752. do {
  753. try realm.write {
  754. if filePath == nil {
  755. predicate = NSPredicate(format: "account == %@", account)
  756. } else {
  757. predicate = NSPredicate(format: "account == %@ AND filePath == %@", account, filePath!)
  758. }
  759. let result = realm.objects(tableTrash.self).filter(predicate)
  760. realm.delete(result)
  761. }
  762. } catch let error {
  763. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  764. }
  765. }
  766. func deleteTrash(fileId: String?, account: String) {
  767. let realm = try! Realm()
  768. var predicate = NSPredicate()
  769. do {
  770. try realm.write {
  771. if fileId == nil {
  772. predicate = NSPredicate(format: "account == %@", account)
  773. } else {
  774. predicate = NSPredicate(format: "account == %@ AND fileId == %@", account, fileId!)
  775. }
  776. let result = realm.objects(tableTrash.self).filter(predicate)
  777. realm.delete(result)
  778. }
  779. } catch let error {
  780. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  781. }
  782. }
  783. func getTrash(filePath: String, sort: String?, ascending: Bool?, account: String) -> [tableTrash]? {
  784. let realm = try! Realm()
  785. let sort = sort ?? "date"
  786. let ascending = ascending ?? false
  787. let results = realm.objects(tableTrash.self).filter("account == %@ AND filePath == %@", account, filePath).sorted(byKeyPath: sort, ascending: ascending)
  788. return Array(results.map { tableTrash.init(value: $0) })
  789. }
  790. func getTrashItem(fileId: String, account: String) -> tableTrash? {
  791. let realm = try! Realm()
  792. guard let result = realm.objects(tableTrash.self).filter("account == %@ AND fileId == %@", account, fileId).first else {
  793. return nil
  794. }
  795. return tableTrash.init(value: result)
  796. }
  797. // MARK: -
  798. // MARK: Table UserStatus
  799. func addUserStatus(_ userStatuses: [NKUserStatus], account: String, predefined: Bool) {
  800. let realm = try! Realm()
  801. do {
  802. try realm.write {
  803. let results = realm.objects(tableUserStatus.self).filter("account == %@ AND predefined == %@", account, predefined)
  804. realm.delete(results)
  805. for userStatus in userStatuses {
  806. let object = tableUserStatus()
  807. object.account = account
  808. object.clearAt = userStatus.clearAt
  809. object.clearAtTime = userStatus.clearAtTime
  810. object.clearAtType = userStatus.clearAtType
  811. object.icon = userStatus.icon
  812. object.id = userStatus.id
  813. object.message = userStatus.message
  814. object.predefined = userStatus.predefined
  815. object.status = userStatus.status
  816. object.userId = userStatus.userId
  817. realm.add(object)
  818. }
  819. }
  820. } catch let error {
  821. NextcloudKit.shared.nkCommonInstance.writeLog("Could not write to database: \(error)")
  822. }
  823. }
  824. }