From 2494b3f65d45ffd9619d4f68a4790ac3d6e95f19 Mon Sep 17 00:00:00 2001 From: Corey Date: Tue, 24 Jan 2023 10:48:08 -0500 Subject: [PATCH] feat: Add a type for decoding Hook Triggers without Objects (#53) * feat: Add a type for decoding Hook Triggers without Objects * add getters to new type * nits * add changelog --- CHANGELOG.md | 1 + ParseSwift.xcodeproj/project.pbxproj | 40 +++- Sources/ParseSwift/ParseConstants.swift | 2 +- .../Protocols/ParseHookRequestable.swift | 4 +- .../ParseHookTriggerRequestable.swift | 23 ++ .../Protocols/ParseHookTriggerable.swift | 2 +- .../Types/ParseHookFunctionRequest.swift | 1 + .../Types/ParseHookTriggerObjectRequest.swift | 87 +++++++ .../Types/ParseHookTriggerRequest.swift | 40 +--- .../ParseHookTriggerRequestCombineTests.swift | 36 +-- .../ParseHookTriggerRequestTests.swift | 220 ++++++++++++------ 11 files changed, 319 insertions(+), 137 deletions(-) create mode 100644 Sources/ParseSwift/Protocols/ParseHookTriggerRequestable.swift create mode 100644 Sources/ParseSwift/Types/ParseHookTriggerObjectRequest.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e46a1f74..45f05f13c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ [Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/4.16.2...5.0.0), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.0.0/documentation/parseswift) __Breaking Changes__ +* ParseHookTriggerRequest has been renamed to ParseHookTriggerObjectRequest as it is used for decoding triggers related to ParseObjects. The new ParseHookTriggerRequest is similar but used for decoding requests not related to ParseObjects like ParseFile ([#53](https://github.com/netreconlab/Parse-Swift/pull/53)), thanks to [Corey Baker](https://github.com/cbaker6). * ParseVersion now supports pre-release versions of the SDK ([#49](https://github.com/netreconlab/Parse-Swift/pull/49)), thanks to [Corey Baker](https://github.com/cbaker6). * Added a new ParseHealth.Status enum to support new feature in Parse Server 6.0.0. Developers can now receive intermediate status updates (Status.initialized, Status.starting) diff --git a/ParseSwift.xcodeproj/project.pbxproj b/ParseSwift.xcodeproj/project.pbxproj index 54bc1e1ee..2b4f34d49 100644 --- a/ParseSwift.xcodeproj/project.pbxproj +++ b/ParseSwift.xcodeproj/project.pbxproj @@ -538,6 +538,14 @@ 70A98D832794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; }; 70A98D842794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; }; 70A98D852794AB3C009B58F2 /* ParseQueryScorable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */; }; + 70B412B429801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B329801AFB00F706EA /* ParseHookTriggerRequest.swift */; }; + 70B412B529801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B329801AFB00F706EA /* ParseHookTriggerRequest.swift */; }; + 70B412B629801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B329801AFB00F706EA /* ParseHookTriggerRequest.swift */; }; + 70B412B729801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B329801AFB00F706EA /* ParseHookTriggerRequest.swift */; }; + 70B412B929801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B829801B8B00F706EA /* ParseHookTriggerRequestable.swift */; }; + 70B412BA29801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B829801B8B00F706EA /* ParseHookTriggerRequestable.swift */; }; + 70B412BB29801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B829801B8B00F706EA /* ParseHookTriggerRequestable.swift */; }; + 70B412BC29801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B412B829801B8B00F706EA /* ParseHookTriggerRequestable.swift */; }; 70B4E0BC2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; }; 70B4E0BD2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; }; 70B4E0BE2762F1D5004C9757 /* QueryConstraint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */; }; @@ -618,10 +626,10 @@ 70CE0AAE28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; }; 70CE0AAF28595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; }; 70CE0AB028595FDE00DAEA86 /* ParseHookRequestable+combine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */; }; - 70CE0AB2285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; }; - 70CE0AB3285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; }; - 70CE0AB4285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; }; - 70CE0AB5285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */; }; + 70CE0AB2285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift */; }; + 70CE0AB3285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift */; }; + 70CE0AB4285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift */; }; + 70CE0AB5285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB1285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift */; }; 70CE0AB7285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; }; 70CE0AB8285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; }; 70CE0AB9285A83B100DAEA86 /* ParseHookable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */; }; @@ -1316,6 +1324,8 @@ 70A2D86A25B3ADB6001BEB7D /* ParseAnonymousTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymousTests.swift; sourceTree = ""; }; 70A8B5FE2971029D00AE0087 /* InMemoryPrimitiveStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InMemoryPrimitiveStore.swift; sourceTree = ""; }; 70A98D812794AB3C009B58F2 /* ParseQueryScorable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseQueryScorable.swift; sourceTree = ""; }; + 70B412B329801AFB00F706EA /* ParseHookTriggerRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerRequest.swift; sourceTree = ""; }; + 70B412B829801B8B00F706EA /* ParseHookTriggerRequestable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerRequestable.swift; sourceTree = ""; }; 70B4E0BB2762F1D5004C9757 /* QueryConstraint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryConstraint.swift; sourceTree = ""; }; 70B4E0C02762F313004C9757 /* QueryWhere.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryWhere.swift; sourceTree = ""; }; 70BC0B32251903D1001556DB /* ParseGeoPointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseGeoPointTests.swift; sourceTree = ""; }; @@ -1340,7 +1350,7 @@ 70CE0AA228595E5E00DAEA86 /* ParseHookRequestable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookRequestable.swift; sourceTree = ""; }; 70CE0AA728595FCE00DAEA86 /* ParseHookRequestable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseHookRequestable+async.swift"; sourceTree = ""; }; 70CE0AAC28595FDE00DAEA86 /* ParseHookRequestable+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseHookRequestable+combine.swift"; sourceTree = ""; }; - 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerRequest.swift; sourceTree = ""; }; + 70CE0AB1285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookTriggerObjectRequest.swift; sourceTree = ""; }; 70CE0AB6285A83B100DAEA86 /* ParseHookable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseHookable.swift; sourceTree = ""; }; 70CE0ABB285F8FF900DAEA86 /* ParseTypeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseTypeable.swift; sourceTree = ""; }; 70CE0AC0285FD59B00DAEA86 /* ParseHookFunctionable+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseHookFunctionable+async.swift"; sourceTree = ""; }; @@ -1838,6 +1848,7 @@ 70385E702858D2DD0084D306 /* ParseHookTriggerable.swift */, 70CE0ACA285FD5CB00DAEA86 /* ParseHookTriggerable+async.swift */, 70CE0ACF285FD5D700DAEA86 /* ParseHookTriggerable+combine.swift */, + 70B412B829801B8B00F706EA /* ParseHookTriggerRequestable.swift */, 705025EA285153BC008D6624 /* ParsePushApplePayloadable.swift */, 705025EF2851542D008D6624 /* ParsePushFirebasePayloadable.swift */, 705025CB284CE4C2008D6624 /* ParsePushPayloadable.swift */, @@ -2167,7 +2178,8 @@ 7085DDA226CC8A470033B977 /* ParseHealth+combine.swift */, 70385E7F2858EAA90084D306 /* ParseHookFunctionRequest.swift */, 70CE0A9328590A0A00DAEA86 /* ParseHookResponse.swift */, - 70CE0AB1285963A300DAEA86 /* ParseHookTriggerRequest.swift */, + 70CE0AB1285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift */, + 70B412B329801AFB00F706EA /* ParseHookTriggerRequest.swift */, 70D41D7F28B520E200613510 /* ParseKeychainAccessGroup.swift */, F97B464024D9C78B00F4A88B /* ParseOperation.swift */, 703B091026BD992E005A112F /* ParseOperation+async.swift */, @@ -2700,6 +2712,7 @@ 703B090726BD9764005A112F /* ParseCloudable+async.swift in Sources */, 918CED592684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */, 70386A0625D9718C0048EC1B /* Data.swift in Sources */, + 70B412B929801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */, F97B465F24D9C7B500F4A88B /* KeychainStore.swift in Sources */, 70B4E0C12762F313004C9757 /* QueryWhere.swift in Sources */, 70170A442656B02D0070C905 /* ParseAnalytics.swift in Sources */, @@ -2718,6 +2731,7 @@ 91679D64268E596300F71809 /* ParseVersion.swift in Sources */, 91285B1C26990D7F0051B544 /* ParsePolygon.swift in Sources */, 91BB8FCA2690AC99005A6BA5 /* QueryViewModel.swift in Sources */, + 70B412B429801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */, 7085DD9426CBF3A70033B977 /* Documentation.docc in Sources */, 705025EB285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */, 705025A928441C96008D6624 /* ParseFieldOptions.swift in Sources */, @@ -2782,7 +2796,7 @@ F97B45E224D9C6F200F4A88B /* AnyEncodable.swift in Sources */, 700396EA25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */, 9116F66F26A35D610082F6D6 /* URLCache.swift in Sources */, - 70CE0AB2285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */, + 70CE0AB2285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */, 709A148728396B1D00BF85E5 /* ParseField.swift in Sources */, 70572671259033A700F0ADD5 /* ParseFileManager.swift in Sources */, 70F03A342780CA4300E5AFB4 /* ParseGitHub.swift in Sources */, @@ -3016,6 +3030,7 @@ 703B090826BD9764005A112F /* ParseCloudable+async.swift in Sources */, 918CED5A2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */, 70386A0725D9718C0048EC1B /* Data.swift in Sources */, + 70B412BA29801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */, F97B466024D9C7B500F4A88B /* KeychainStore.swift in Sources */, 70B4E0C22762F313004C9757 /* QueryWhere.swift in Sources */, 70170A452656B02D0070C905 /* ParseAnalytics.swift in Sources */, @@ -3034,6 +3049,7 @@ 91679D65268E596300F71809 /* ParseVersion.swift in Sources */, 91285B1D26990D7F0051B544 /* ParsePolygon.swift in Sources */, 91BB8FCB2690AC99005A6BA5 /* QueryViewModel.swift in Sources */, + 70B412B529801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */, 7085DD9526CBF3A70033B977 /* Documentation.docc in Sources */, 705025EC285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */, 705025AA28441C96008D6624 /* ParseFieldOptions.swift in Sources */, @@ -3098,7 +3114,7 @@ 700396EB25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */, 9116F67026A35D610082F6D6 /* URLCache.swift in Sources */, 70572672259033A700F0ADD5 /* ParseFileManager.swift in Sources */, - 70CE0AB3285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */, + 70CE0AB3285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */, 709A148828396B1D00BF85E5 /* ParseField.swift in Sources */, 707A3C2125B14BD0000D215C /* ParseApple.swift in Sources */, 70F03A352780CA4D00E5AFB4 /* ParseGitHub.swift in Sources */, @@ -3466,6 +3482,7 @@ 70D1BE7625BB43EB00A42E7C /* BaseConfig.swift in Sources */, 703B090A26BD9764005A112F /* ParseCloudable+async.swift in Sources */, 918CED5C2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */, + 70B412BC29801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */, 70386A0925D9718C0048EC1B /* Data.swift in Sources */, 70B4E0C42762F313004C9757 /* QueryWhere.swift in Sources */, F97B460524D9C6F200F4A88B /* NoBody.swift in Sources */, @@ -3484,6 +3501,7 @@ 91B79ACB26EE3C5D00073F2C /* API+BatchCommand.swift in Sources */, 91679D67268E596300F71809 /* ParseVersion.swift in Sources */, 91285B1F26990D7F0051B544 /* ParsePolygon.swift in Sources */, + 70B412B729801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */, 91BB8FCD2690AC99005A6BA5 /* QueryViewModel.swift in Sources */, 705025EE285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */, 705025AC28441C96008D6624 /* ParseFieldOptions.swift in Sources */, @@ -3548,7 +3566,7 @@ 700396ED25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */, 9116F67226A35D620082F6D6 /* URLCache.swift in Sources */, 70572674259033A700F0ADD5 /* ParseFileManager.swift in Sources */, - 70CE0AB5285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */, + 70CE0AB5285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */, 709A148A28396B1D00BF85E5 /* ParseField.swift in Sources */, 707A3C2325B14BD0000D215C /* ParseApple.swift in Sources */, 70F03A372780CA4E00E5AFB4 /* ParseGitHub.swift in Sources */, @@ -3657,6 +3675,7 @@ 70D1BE7525BB43EB00A42E7C /* BaseConfig.swift in Sources */, 703B090926BD9764005A112F /* ParseCloudable+async.swift in Sources */, 918CED5B2684C74000CFDC83 /* ParseLiveQuery+combine.swift in Sources */, + 70B412BB29801B8B00F706EA /* ParseHookTriggerRequestable.swift in Sources */, 70386A0825D9718C0048EC1B /* Data.swift in Sources */, 70B4E0C32762F313004C9757 /* QueryWhere.swift in Sources */, F97B460424D9C6F200F4A88B /* NoBody.swift in Sources */, @@ -3675,6 +3694,7 @@ 91B79ACA26EE3C5D00073F2C /* API+BatchCommand.swift in Sources */, 91679D66268E596300F71809 /* ParseVersion.swift in Sources */, 91285B1E26990D7F0051B544 /* ParsePolygon.swift in Sources */, + 70B412B629801AFB00F706EA /* ParseHookTriggerRequest.swift in Sources */, 91BB8FCC2690AC99005A6BA5 /* QueryViewModel.swift in Sources */, 705025ED285153BC008D6624 /* ParsePushApplePayloadable.swift in Sources */, 705025AB28441C96008D6624 /* ParseFieldOptions.swift in Sources */, @@ -3739,7 +3759,7 @@ 700396EC25A3892D0052CB31 /* LiveQuerySocketDelegate.swift in Sources */, 9116F67126A35D620082F6D6 /* URLCache.swift in Sources */, 70572673259033A700F0ADD5 /* ParseFileManager.swift in Sources */, - 70CE0AB4285963A300DAEA86 /* ParseHookTriggerRequest.swift in Sources */, + 70CE0AB4285963A300DAEA86 /* ParseHookTriggerObjectRequest.swift in Sources */, 709A148928396B1D00BF85E5 /* ParseField.swift in Sources */, 707A3C2225B14BD0000D215C /* ParseApple.swift in Sources */, 70F03A362780CA4D00E5AFB4 /* ParseGitHub.swift in Sources */, diff --git a/Sources/ParseSwift/ParseConstants.swift b/Sources/ParseSwift/ParseConstants.swift index 635557bef..e0ad83794 100644 --- a/Sources/ParseSwift/ParseConstants.swift +++ b/Sources/ParseSwift/ParseConstants.swift @@ -10,7 +10,7 @@ import Foundation enum ParseConstants { static let sdk = "swift" - static let version = "5.0.0-beta.5" + static let version = "5.0.0-beta.6" static let fileManagementDirectory = "parse/" static let fileManagementPrivateDocumentsDirectory = "Private Documents/" static let fileManagementLibraryDirectory = "Library/" diff --git a/Sources/ParseSwift/Protocols/ParseHookRequestable.swift b/Sources/ParseSwift/Protocols/ParseHookRequestable.swift index 75ca7df16..6d1bd9e52 100644 --- a/Sources/ParseSwift/Protocols/ParseHookRequestable.swift +++ b/Sources/ParseSwift/Protocols/ParseHookRequestable.swift @@ -10,7 +10,7 @@ import Foundation /** Conforming to `ParseHookRequestable` allows you to create types that - can decode requests when `ParseHookFunctionable` functions are called. + can decode requests. - requires: `.usePrimaryKey` has to be available. It is recommended to only use the master key in server-side applications where the key is kept secure and not exposed to the public. @@ -18,7 +18,7 @@ import Foundation public protocol ParseHookRequestable: ParseTypeable { associatedtype UserType: ParseCloudUser /** - Specifies if the **masterKey** was used in the + Specifies if the **primaryKey** was used in the Parse hook call. */ var primaryKey: Bool? { get } diff --git a/Sources/ParseSwift/Protocols/ParseHookTriggerRequestable.swift b/Sources/ParseSwift/Protocols/ParseHookTriggerRequestable.swift new file mode 100644 index 000000000..85a836d6f --- /dev/null +++ b/Sources/ParseSwift/Protocols/ParseHookTriggerRequestable.swift @@ -0,0 +1,23 @@ +// +// ParseHookTriggerRequestable.swift +// ParseSwift +// +// Created by Corey Baker on 1/24/23. +// Copyright © 2023 Network Reconnaissance Lab. All rights reserved. +// + +import Foundation + +/** + Conforming to `ParseHookTriggerRequestable` allows you to create types that + can decode requests when `ParseHookTriggerable` triggers are called. + - requires: `.usePrimaryKey` has to be available. It is recommended to only + use the master key in server-side applications where the key is kept secure and not + exposed to the public. + */ +public protocol ParseHookTriggerRequestable: ParseHookRequestable { + /// The types of Parse Hook Trigger. + var triggerName: String? { get } + /// The number of clients connected. + var clients: Int? { get } +} diff --git a/Sources/ParseSwift/Protocols/ParseHookTriggerable.swift b/Sources/ParseSwift/Protocols/ParseHookTriggerable.swift index a865f5d62..4bff378a7 100644 --- a/Sources/ParseSwift/Protocols/ParseHookTriggerable.swift +++ b/Sources/ParseSwift/Protocols/ParseHookTriggerable.swift @@ -9,7 +9,7 @@ import Foundation /** - Conforming to `ParseHookFunctionable` allows the creation of hooks which + Conforming to `ParseHookTriggerable` allows the creation of hooks which are Cloud Code triggers. - requires: `.usePrimaryKey` has to be available. It is recommended to only use the master key in server-side applications where the key is kept secure and not diff --git a/Sources/ParseSwift/Types/ParseHookFunctionRequest.swift b/Sources/ParseSwift/Types/ParseHookFunctionRequest.swift index 388507901..6d92b6ca5 100644 --- a/Sources/ParseSwift/Types/ParseHookFunctionRequest.swift +++ b/Sources/ParseSwift/Types/ParseHookFunctionRequest.swift @@ -67,4 +67,5 @@ extension ParseHookFunctionRequest { } return context } + } diff --git a/Sources/ParseSwift/Types/ParseHookTriggerObjectRequest.swift b/Sources/ParseSwift/Types/ParseHookTriggerObjectRequest.swift new file mode 100644 index 000000000..801e56aef --- /dev/null +++ b/Sources/ParseSwift/Types/ParseHookTriggerObjectRequest.swift @@ -0,0 +1,87 @@ +// +// ParseHookTriggerRequest.swift +// ParseSwift +// +// Created by Corey Baker on 6/14/22. +// Copyright © 2022 Parse Community. All rights reserved. +// + +import Foundation + +/** + A type that can decode requests when `ParseHookTriggerable` triggers are called. + - requires: `.usePrimaryKey` has to be available. It is recommended to only + use the master key in server-side applications where the key is kept secure and not + exposed to the public. + */ +public struct ParseHookTriggerObjectRequest: ParseHookTriggerRequestable { + public typealias UserType = U + public var primaryKey: Bool? + public var user: U? + public var installationId: String? + public var ipAddress: String? + public var headers: [String: String]? + public var triggerName: String? + public var clients: Int? + /// An object from the hook call. + public var object: T? + /// The results the query yielded.. + public var objects: [T]? + /// If set, the object, as currently stored. + public var original: T? + /// The query from the hook call. + public var query: Query? + /// Whether the query a **get** or a **find**. + public var isGet: Bool? + /// The number of subscriptions connected. + public var subscriptions: Int? + /** + If the LiveQuery event should be sent to the client. Set to false to prevent + LiveQuery from pushing to the client. + */ + public var sendEvent: Bool? + /// The live query event that triggered the request. + public var event: String? + var log: AnyCodable? + var context: AnyCodable? + + enum CodingKeys: String, CodingKey { + case primaryKey = "master" + case ipAddress = "ip" + case user, installationId, headers, + log, context, triggerName, + object, objects, original, query, + isGet, clients, subscriptions, + sendEvent + } +} + +extension ParseHookTriggerObjectRequest { + + /** + Get the Parse Server logger using any type that conforms to `Codable`. + - returns: The sound casted to the inferred type. + - throws: An error of type `ParseError`. + */ + public func getLog() throws -> V where V: Codable { + guard let log = log?.value as? V else { + throw ParseError(code: .otherCause, + message: "Cannot be casted to the inferred type") + } + return log + } + + /** + Get the context using any type that conforms to `Codable`. + - returns: The sound casted to the inferred type. + - throws: An error of type `ParseError`. + */ + public func getContext() throws -> V where V: Codable { + guard let context = context?.value as? V else { + throw ParseError(code: .otherCause, + message: "Cannot be casted to the inferred type") + } + return context + } + +} diff --git a/Sources/ParseSwift/Types/ParseHookTriggerRequest.swift b/Sources/ParseSwift/Types/ParseHookTriggerRequest.swift index 2fef8d8fe..25b04de13 100644 --- a/Sources/ParseSwift/Types/ParseHookTriggerRequest.swift +++ b/Sources/ParseSwift/Types/ParseHookTriggerRequest.swift @@ -2,8 +2,8 @@ // ParseHookTriggerRequest.swift // ParseSwift // -// Created by Corey Baker on 6/14/22. -// Copyright © 2022 Parse Community. All rights reserved. +// Created by Corey Baker on 1/24/23. +// Copyright © 2023 Network Reconnaissance Lab. All rights reserved. // import Foundation @@ -14,42 +14,19 @@ import Foundation use the master key in server-side applications where the key is kept secure and not exposed to the public. */ -public struct ParseHookTriggerRequest: ParseHookRequestable { +public struct ParseHookTriggerRequest: ParseHookTriggerRequestable { public typealias UserType = U - public var primaryKey: Bool? public var user: U? + public var primaryKey: Bool? public var installationId: String? public var ipAddress: String? public var headers: [String: String]? - /// The types of Parse Hook Trigger. public var triggerName: String? - /// An object from the hook call. - public var object: T? - /// The results the query yielded.. - public var objects: [T]? - /// If set, the object, as currently stored. - public var original: T? - /// The query from the hook call. - public var query: Query? - /// Whether the query a **get** or a **find**. - public var isGet: Bool? + public var clients: Int? /// The from the hook call. public var file: ParseFile? /// The size of the file in bytes. public var fileSize: Int? - /// The value from Content-Length header. - public var contentLength: Int? - /// The number of clients connected. - public var clients: Int? - /// The number of subscriptions connected. - public var subscriptions: Int? - /** - If the LiveQuery event should be sent to the client. Set to false to prevent - LiveQuery from pushing to the client. - */ - public var sendEvent: Bool? - /// The live query event that triggered the request. - public var event: String? var log: AnyCodable? var context: AnyCodable? @@ -57,10 +34,8 @@ public struct ParseHookTriggerRequest: ParseH case primaryKey = "master" case ipAddress = "ip" case user, installationId, headers, - log, context, object, objects, - original, query, file, fileSize, - isGet, contentLength, clients, - subscriptions, sendEvent, triggerName + log, context, file, fileSize, + clients, triggerName } } @@ -91,4 +66,5 @@ extension ParseHookTriggerRequest { } return context } + } diff --git a/Tests/ParseSwiftTests/ParseHookTriggerRequestCombineTests.swift b/Tests/ParseSwiftTests/ParseHookTriggerRequestCombineTests.swift index 49f36c68b..e83bfae17 100644 --- a/Tests/ParseSwiftTests/ParseHookTriggerRequestCombineTests.swift +++ b/Tests/ParseSwiftTests/ParseHookTriggerRequestCombineTests.swift @@ -91,18 +91,18 @@ class ParseHookTriggerRequestCombineTests: XCTestCase { let object = User(objectId: "geez") let installationId = "cat" - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - user: user, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) - let requestHydrated = ParseHookTriggerRequest(primaryKey: true, - user: server, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + user: user, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) + let requestHydrated = ParseHookTriggerObjectRequest(primaryKey: true, + user: server, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let publisher = triggerRequest.hydrateUserPublisher() .sink(receiveCompletion: { result in @@ -133,12 +133,12 @@ class ParseHookTriggerRequestCombineTests: XCTestCase { let object = User(objectId: "geez") let installationId = "cat" - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - user: user, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + user: user, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let publisher = triggerRequest.hydrateUserPublisher() .sink(receiveCompletion: { result in diff --git a/Tests/ParseSwiftTests/ParseHookTriggerRequestTests.swift b/Tests/ParseSwiftTests/ParseHookTriggerRequestTests.swift index c5560d9dc..1c06830e5 100644 --- a/Tests/ParseSwiftTests/ParseHookTriggerRequestTests.swift +++ b/Tests/ParseSwiftTests/ParseHookTriggerRequestTests.swift @@ -14,6 +14,7 @@ import FoundationNetworking import XCTest @testable import ParseSwift +// swiftlint:disable:next type_body_length class ParseHookTriggerRequestTests: XCTestCase { struct User: ParseCloudUser { @@ -74,40 +75,93 @@ class ParseHookTriggerRequestTests: XCTestCase { } func testCoding() async throws { + let triggerRequest = ParseHookTriggerRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + triggerName: "beforeDelete", + file: ParseFile(data: Data()), + fileSize: 0) + // swiftlint:disable:next line_length + let expected = "{\"file\":{\"__type\":\"File\",\"name\":\"file\"},\"fileSize\":0,\"headers\":{\"yolo\":\"me\"},\"ip\":\"1.1.1.1\",\"master\":true,\"triggerName\":\"beforeDelete\"}" + XCTAssertEqual(triggerRequest.description, expected) + } + + func testCodingObject() async throws { let object = User(objectId: "geez") - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - triggerName: "beforeDelete", - object: object) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + triggerName: "beforeDelete", + object: object) // swiftlint:disable:next line_length let expected = "{\"headers\":{\"yolo\":\"me\"},\"ip\":\"1.1.1.1\",\"master\":true,\"object\":{\"objectId\":\"geez\"},\"triggerName\":\"beforeDelete\"}" XCTAssertEqual(triggerRequest.description, expected) - let triggerRequest2 = ParseHookTriggerRequest(ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest2 = ParseHookTriggerObjectRequest(ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let expected2 = "{\"headers\":{\"yolo\":\"me\"},\"ip\":\"1.1.1.1\",\"object\":{\"objectId\":\"geez\"}}" XCTAssertEqual(triggerRequest2.description, expected2) } + func testGetLogObject() async throws { + let object = User(objectId: "geez") + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object, + log: AnyCodable("peace")) + let log: String = try triggerRequest.getLog() + XCTAssertEqual(log, "peace") + } + + func testGetLogErrorObject() async throws { + let object = User(objectId: "geez") + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object, + log: AnyCodable("peace")) + do { + let _: Double = try triggerRequest.getLog() + XCTFail("Should have failed") + } catch { + guard let parseError = error as? ParseError else { + XCTFail("Should have casted") + return + } + XCTAssertTrue(parseError.message.contains("inferred")) + } + } + + func testGetContextObject() async throws { + let object = User(objectId: "geez") + let context = ["peace": "out"] + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object, + context: AnyCodable(context)) + let requestContext: [String: String] = try triggerRequest.getContext() + XCTAssertEqual(requestContext, context) + } + func testGetLog() async throws { let object = User(objectId: "geez") - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object, - log: AnyCodable("peace")) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object, + log: AnyCodable("peace")) let log: String = try triggerRequest.getLog() XCTAssertEqual(log, "peace") } func testGetLogError() async throws { - let object = User(objectId: "geez") - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object, - log: AnyCodable("peace")) + let triggerRequest = ParseHookTriggerRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + file: ParseFile(data: Data()), + log: AnyCodable("peace")) do { let _: Double = try triggerRequest.getLog() XCTFail("Should have failed") @@ -123,11 +177,11 @@ class ParseHookTriggerRequestTests: XCTestCase { func testGetContext() async throws { let object = User(objectId: "geez") let context = ["peace": "out"] - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object, - context: AnyCodable(context)) + let triggerRequest = ParseHookTriggerRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + file: ParseFile(data: Data()), + context: AnyCodable(context)) let requestContext: [String: String] = try triggerRequest.getContext() XCTAssertEqual(requestContext, context) } @@ -135,11 +189,31 @@ class ParseHookTriggerRequestTests: XCTestCase { func testGetContextError() async throws { let object = User(objectId: "geez") let context = ["peace": "out"] - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object, - context: AnyCodable(context)) + let triggerRequest = ParseHookTriggerRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + file: ParseFile(data: Data()), + context: AnyCodable(context)) + do { + let _: Double = try triggerRequest.getContext() + XCTFail("Should have failed") + } catch { + guard let parseError = error as? ParseError else { + XCTFail("Should have casted") + return + } + XCTAssertTrue(parseError.message.contains("inferred")) + } + } + + func testGetContextErrorObject() async throws { + let object = User(objectId: "geez") + let context = ["peace": "out"] + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object, + context: AnyCodable(context)) do { let _: Double = try triggerRequest.getContext() XCTFail("Should have failed") @@ -157,45 +231,45 @@ class ParseHookTriggerRequestTests: XCTestCase { let sessionToken = "dog" let installationId = "cat" let user = User(sessionToken: sessionToken) - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - user: user, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + user: user, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let options = API.Options([.usePrimaryKey]) let requestOptions = triggerRequest.options() XCTAssertEqual(requestOptions, options) - let triggerRequest2 = ParseHookTriggerRequest(primaryKey: false, - user: user, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest2 = ParseHookTriggerObjectRequest(primaryKey: false, + user: user, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let options2 = API.Options([.sessionToken(sessionToken), .installationId(installationId)]) let requestOptions2 = triggerRequest2.options() XCTAssertEqual(requestOptions2, options2) - let triggerRequest3 = ParseHookTriggerRequest(primaryKey: false, - user: user, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest3 = ParseHookTriggerObjectRequest(primaryKey: false, + user: user, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let options3 = API.Options([.sessionToken(sessionToken)]) let requestOptions3 = triggerRequest3.options() XCTAssertEqual(requestOptions3, options3) - let triggerRequest4 = ParseHookTriggerRequest(primaryKey: false, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest4 = ParseHookTriggerObjectRequest(primaryKey: false, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let options4 = API.Options([.installationId(installationId)]) let requestOptions4 = triggerRequest4.options() XCTAssertEqual(requestOptions4, options4) - let triggerRequest5 = ParseHookTriggerRequest(primaryKey: false, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest5 = ParseHookTriggerObjectRequest(primaryKey: false, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let options5 = API.Options() let requestOptions5 = triggerRequest5.options() XCTAssertEqual(requestOptions5, options5) @@ -218,18 +292,18 @@ class ParseHookTriggerRequestTests: XCTestCase { let object = User(objectId: "geez") let installationId = "cat" - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - user: user, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) - let requestHydrated = ParseHookTriggerRequest(primaryKey: true, - user: server, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + user: user, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) + let requestHydrated = ParseHookTriggerObjectRequest(primaryKey: true, + user: server, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) let hydrated = try await triggerRequest.hydrateUser() XCTAssertEqual(hydrated, requestHydrated) } @@ -246,12 +320,12 @@ class ParseHookTriggerRequestTests: XCTestCase { let object = User(objectId: "geez") let installationId = "cat" - let triggerRequest = ParseHookTriggerRequest(primaryKey: true, - user: user, - installationId: installationId, - ipAddress: "1.1.1.1", - headers: ["yolo": "me"], - object: object) + let triggerRequest = ParseHookTriggerObjectRequest(primaryKey: true, + user: user, + installationId: installationId, + ipAddress: "1.1.1.1", + headers: ["yolo": "me"], + object: object) do { _ = try await triggerRequest.hydrateUser() XCTFail("Should have thrown error")