Skip to content

Commit

Permalink
Allow custom objectIds (#100)
Browse files Browse the repository at this point in the history
* Allow custom objectIds

* Let server throw missing objectId error instead of SDK

* Fix date comparisons in new tests

* Simplify new tests

* Merge main and add missing Android

* nits

* prepare for release

* Fix anonymous user strip bug

* lower codecov patch

* more codecov

* Add missing user signup tests

* Update .codecov.yml
  • Loading branch information
cbaker6 authored Mar 22, 2021
1 parent fa74a7c commit 453ebdb
Show file tree
Hide file tree
Showing 16 changed files with 1,859 additions and 197 deletions.
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ coverage:
changes: false
project:
default:
target: 76
target: 80
comment:
require_changes: true
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
# Parse-Swift Changelog

### main
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.1...main)
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.2...main)
* _Contributing to this repo? Add info about your change here to be included in the next release_


### 1.2.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.1...1.2.2)

__New features__
- Allow custom objectIds ([#100](https://github.com/parse-community/Parse-Swift/pull/100)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add ParseTwitter and ParseFacebook authentication ([#97](https://github.com/parse-community/Parse-Swift/pull/97)), thanks to [Abdulaziz Alhomaidhi](https://github.com/abs8090).
- Add build support for Android ([#90](https://github.com/parse-community/Parse-Swift/pull/90)), thanks to [jt9897253](https://github.com/jt9897253).

__Fixes__
- There was another bug after a user first logs in anonymously and then becomes a real user. The authData sent to the server wasn't stripped, keep the user anonymous instead of making them a real user ([#100](https://github.com/parse-community/Parse-Swift/pull/100)), thanks to [Corey Baker](https://github.com/cbaker6).

### 1.2.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.0...1.2.1)
Expand Down
2 changes: 1 addition & 1 deletion ParseSwift.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "ParseSwift"
s.version = "1.2.1"
s.version = "1.2.2"
s.summary = "Parse Pure Swift SDK"
s.homepage = "https://github.com/parse-community/Parse-Swift"
s.authors = {
Expand Down
24 changes: 16 additions & 8 deletions ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@
70647E9D259E3A9A004C1004 /* ParseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseType.swift */; };
70647E9E259E3A9A004C1004 /* ParseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseType.swift */; };
70647E9F259E3A9A004C1004 /* ParseType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70647E9B259E3A9A004C1004 /* ParseType.swift */; };
70732C5A2606CCAD000CAB81 /* ParseObjectCustomObjectId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70732C592606CCAD000CAB81 /* ParseObjectCustomObjectId.swift */; };
70732C5B2606CCAD000CAB81 /* ParseObjectCustomObjectId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70732C592606CCAD000CAB81 /* ParseObjectCustomObjectId.swift */; };
70732C5C2606CCAD000CAB81 /* ParseObjectCustomObjectId.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70732C592606CCAD000CAB81 /* ParseObjectCustomObjectId.swift */; };
707A3BF125B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };
707A3BF225B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };
707A3BF325B0A4F0000D215C /* ParseAuthentication.swift in Sources */ = {isa = PBXBuildFile; fileRef = 707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */; };
Expand Down Expand Up @@ -599,6 +602,7 @@
705D950725BE4C08003EF6F8 /* SubscriptionCallback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscriptionCallback.swift; sourceTree = "<group>"; };
70647E8D259E3375004C1004 /* LocallyIdentifiable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocallyIdentifiable.swift; sourceTree = "<group>"; };
70647E9B259E3A9A004C1004 /* ParseType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseType.swift; sourceTree = "<group>"; };
70732C592606CCAD000CAB81 /* ParseObjectCustomObjectId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseObjectCustomObjectId.swift; sourceTree = "<group>"; };
707A3BF025B0A4F0000D215C /* ParseAuthentication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAuthentication.swift; sourceTree = "<group>"; };
707A3C1025B0A8E8000D215C /* ParseAnonymous.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnonymous.swift; sourceTree = "<group>"; };
707A3C1F25B14BCF000D215C /* ParseApple.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseApple.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -830,6 +834,7 @@
7003963A25A288100052CB31 /* ParseLiveQueryTests.swift */,
70C7DC2024D20F190050419B /* ParseObjectBatchTests.swift */,
7044C1DE25C5C70D0011F6E7 /* ParseObjectCombine.swift */,
70732C592606CCAD000CAB81 /* ParseObjectCustomObjectId.swift */,
911DB13524C4FC100027F3C7 /* ParseObjectTests.swift */,
7044C1EB25C5CC930011F6E7 /* ParseOperationCombineTests.swift */,
70C5508425B4A68700B5DBC2 /* ParseOperationTests.swift */,
Expand Down Expand Up @@ -1660,6 +1665,7 @@
89899D772603CF66002E2043 /* ParseFacebookTests.swift in Sources */,
70386A4625D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */,
911DB12E24C4837E0027F3C7 /* APICommandTests.swift in Sources */,
70732C5A2606CCAD000CAB81 /* ParseObjectCustomObjectId.swift in Sources */,
911DB12C24C3F7720027F3C7 /* MockURLResponse.swift in Sources */,
7044C24325C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */,
7044C1DF25C5C70D0011F6E7 /* ParseObjectCombine.swift in Sources */,
Expand Down Expand Up @@ -1810,6 +1816,7 @@
89899D822603CF67002E2043 /* ParseFacebookTests.swift in Sources */,
70386A4825D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */,
709B984C2556ECAA00507778 /* APICommandTests.swift in Sources */,
70732C5C2606CCAD000CAB81 /* ParseObjectCustomObjectId.swift in Sources */,
709B984D2556ECAA00507778 /* AnyDecodableTests.swift in Sources */,
7044C24525C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */,
7044C1E125C5C70D0011F6E7 /* ParseObjectCombine.swift in Sources */,
Expand Down Expand Up @@ -1863,6 +1870,7 @@
89899D812603CF67002E2043 /* ParseFacebookTests.swift in Sources */,
70386A4725D99C8B0048EC1B /* ParseLDAPTests.swift in Sources */,
70F2E2B5254F283000B2EA5C /* ParseEncoderTests.swift in Sources */,
70732C5B2606CCAD000CAB81 /* ParseObjectCustomObjectId.swift in Sources */,
70F2E2C2254F283000B2EA5C /* APICommandTests.swift in Sources */,
7044C24425C5EA360011F6E7 /* ParseAppleCombineTests.swift in Sources */,
7044C1E025C5C70D0011F6E7 /* ParseObjectCombine.swift in Sources */,
Expand Down Expand Up @@ -2313,7 +2321,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
PRODUCT_NAME = ParseSwift;
SKIP_INSTALL = YES;
Expand All @@ -2337,7 +2345,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
IPHONEOS_DEPLOYMENT_TARGET = 12.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
PRODUCT_NAME = ParseSwift;
SKIP_INSTALL = YES;
Expand Down Expand Up @@ -2403,7 +2411,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
PRODUCT_NAME = ParseSwift;
SDKROOT = macosx;
Expand All @@ -2429,7 +2437,7 @@
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.13;
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
PRODUCT_BUNDLE_IDENTIFIER = com.parse.ParseSwift;
PRODUCT_NAME = ParseSwift;
SDKROOT = macosx;
Expand Down Expand Up @@ -2576,7 +2584,7 @@
INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS";
Expand Down Expand Up @@ -2605,7 +2613,7 @@
INFOPLIST_FILE = "ParseSwift-watchOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-watchOS";
PRODUCT_NAME = ParseSwift;
Expand All @@ -2632,7 +2640,7 @@
INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS";
Expand Down Expand Up @@ -2660,7 +2668,7 @@
INFOPLIST_FILE = "ParseSwift-tvOS/Info.plist";
INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MARKETING_VERSION = 1.2.1;
MARKETING_VERSION = 1.2.2;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.parse.ParseSwift-tvOS";
PRODUCT_NAME = ParseSwift;
Expand Down
2 changes: 1 addition & 1 deletion Scripts/jazzy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ bundle exec jazzy \
--author_url http://parseplatform.org \
--github_url https://github.com/parse-community/Parse-Swift \
--root-url http://parseplatform.org/Parse-Swift/api/ \
--module-version 1.2.1 \
--module-version 1.2.2 \
--theme fullwidth \
--skip-undocumented \
--output ./docs/api \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,12 @@ public extension ParseUser {
static func login(_ type: String,
authData: [String: String],
options: API.Options) throws -> Self {
let body = SignupLoginBody(authData: [type: authData])
return try signupCommand(body: body).execute(options: options)
if Self.current != nil {
return try Self.link(type, authData: authData, options: options)
} else {
let body = SignupLoginBody(authData: [type: authData])
return try signupCommand(body: body).execute(options: options)
}
}

/**
Expand All @@ -238,22 +242,28 @@ public extension ParseUser {
options: API.Options,
callbackQueue: DispatchQueue = .main,
completion: @escaping (Result<Self, ParseError>) -> Void) {

let body = SignupLoginBody(authData: [type: authData])
do {
try signupCommand(body: body)
.executeAsync(options: options) { result in
callbackQueue.async {
completion(result)
if Self.current != nil {
Self.link(type, authData: authData,
options: options,
callbackQueue: callbackQueue,
completion: completion)
} else {
let body = SignupLoginBody(authData: [type: authData])
do {
try signupCommand(body: body)
.executeAsync(options: options) { result in
callbackQueue.async {
completion(result)
}
}
} catch {
callbackQueue.async {
if let parseError = error as? ParseError {
completion(.failure(parseError))
} else {
let parseError = ParseError(code: .unknownError, message: error.localizedDescription)
completion(.failure(parseError))
}
}
} catch {
callbackQueue.async {
if let parseError = error as? ParseError {
completion(.failure(parseError))
} else {
let parseError = ParseError(code: .unknownError, message: error.localizedDescription)
completion(.failure(parseError))
}
}
}
Expand Down Expand Up @@ -384,29 +394,47 @@ public extension ParseUser {
}
}

internal func linkCommand() -> API.NonParseBodyCommand<Self, Self> {
Self.current?.anonymous.strip()
return API.NonParseBodyCommand<Self, Self>(method: .PUT,
path: endpoint,
body: Self.current) { (data) -> Self in
let user = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: data)
Self.current?.updatedAt = user.updatedAt
guard let current = Self.current else {
throw ParseError(code: .unknownError, message: "Should have a current user.")
}
Self.currentUserContainer = .init(currentUser: current,
sessionToken: user.sessionToken)
Self.saveCurrentContainerToKeychain()
return current
}
}

internal func linkCommand(body: SignupLoginBody) -> API.NonParseBodyCommand<SignupLoginBody, Self> {
var body = body
Self.current?.anonymous.strip()
if var currentAuthData = Self.current?.authData {
if let bodyAuthData = body.authData {
bodyAuthData.forEach { (key, value) in
currentAuthData[key] = value
}
}
body.authData = currentAuthData
}

return API.NonParseBodyCommand<SignupLoginBody, Self>(method: .PUT,
path: endpoint,
body: body) { (data) -> Self in
let user = try ParseCoding.jsonDecoder().decode(Self.self, from: data)
if let authData = body.authData {
Self.current?.anonymous.strip()
if Self.current?.authData == nil {
Self.current?.authData = authData
} else {
authData.forEach { (key, value) in
Self.current?.authData?[key] = value
}
}
if let updatedAt = user.updatedAt {
Self.current?.updatedAt = updatedAt
}
}
Self.saveCurrentContainerToKeychain()
let user = try ParseCoding.jsonDecoder().decode(UpdateSessionTokenResponse.self, from: data)
Self.current?.updatedAt = user.updatedAt
Self.current?.authData = body.authData
guard let current = Self.current else {
throw ParseError(code: .unknownError, message: "Should have a current user.")
}
Self.currentUserContainer = .init(currentUser: current,
sessionToken: user.sessionToken)
Self.saveCurrentContainerToKeychain()
return current
}
}
Expand Down
19 changes: 17 additions & 2 deletions Sources/ParseSwift/Coding/ParseEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,16 @@ public struct ParseEncoder {
case object
case cloud
case none
case customObjectId
case custom(Set<String>)

func keys() -> Set<String> {
switch self {

case .object:
return Set(["createdAt", "updatedAt", "objectId", "className"])
case .customObjectId:
return Set(["createdAt", "updatedAt", "className"])
case .cloud:
return Set(["functionJobName"])
case .none:
Expand Down Expand Up @@ -99,7 +102,13 @@ public struct ParseEncoder {
internal func encode<T: ParseObject>(_ value: T,
objectsSavedBeforeThisOne: [String: PointerType]?,
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: Set<UniqueObject>, unsavedChildren: [Encodable]) {
let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: SkippedKeys.object.keys())
let keysToSkip: Set<String>!
if !ParseConfiguration.allowCustomObjectId {
keysToSkip = SkippedKeys.object.keys()
} else {
keysToSkip = SkippedKeys.customObjectId.keys()
}
let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: keysToSkip)
if let dateEncodingStrategy = dateEncodingStrategy {
encoder.dateEncodingStrategy = dateEncodingStrategy
}
Expand All @@ -110,7 +119,13 @@ public struct ParseEncoder {
internal func encode(_ value: ParseType, collectChildren: Bool,
objectsSavedBeforeThisOne: [String: PointerType]?,
filesSavedBeforeThisOne: [UUID: ParseFile]?) throws -> (encoded: Data, unique: Set<UniqueObject>, unsavedChildren: [Encodable]) {
let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: SkippedKeys.object.keys())
let keysToSkip: Set<String>!
if !ParseConfiguration.allowCustomObjectId {
keysToSkip = SkippedKeys.object.keys()
} else {
keysToSkip = SkippedKeys.customObjectId.keys()
}
let encoder = _ParseEncoder(codingPath: [], dictionary: NSMutableDictionary(), skippingKeys: keysToSkip)
if let dateEncodingStrategy = dateEncodingStrategy {
encoder.dateEncodingStrategy = dateEncodingStrategy
}
Expand Down
Loading

0 comments on commit 453ebdb

Please sign in to comment.