Skip to content

Commit

Permalink
update sessionToken on merge and non-merged users
Browse files Browse the repository at this point in the history
  • Loading branch information
cbaker6 committed Jan 12, 2024
1 parent b9302e9 commit 742e288
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 35 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.2...5.9.0), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.9.0/documentation/parseswift)

__New features__
* Cocoapods now defaults to Swift 5.9 ([#146](https://github.com/netreconlab/Parse-Swift/pull/146)), thanks to [Corey Baker](https://github.com/cbaker6).
* Add support for visionOS ([#143](https://github.com/netreconlab/Parse-Swift/pull/143)), thanks to [Corey Baker](https://github.com/cbaker6).
* Add fetchAll method to array of Parse Pointer Object's ([#141](https://github.com/netreconlab/Parse-Swift/pull/141)), thanks to [Corey Baker](https://github.com/cbaker6).

__Fixes__
* Updates to ParseUser password now persist the updated sessionToken from the server to the client Keychain ([#147](https://github.com/netreconlab/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).

### 5.8.2
[Full Changelog](https://github.com/netreconlab/Parse-Swift/compare/5.8.1...5.8.2), [Documentation](https://swiftpackageindex.com/netreconlab/Parse-Swift/5.8.2/documentation/parseswift)

Expand Down
52 changes: 17 additions & 35 deletions Sources/ParseSwift/Objects/ParseUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1216,7 +1216,6 @@ extension ParseUser {
return command
}

// swiftlint:disable:next function_body_length
func replaceCommand() async throws -> API.Command<Self, Self> {
guard self.objectId != nil else {
throw ParseError(code: .missingObjectId,
Expand All @@ -1238,38 +1237,30 @@ extension ParseUser {
ReplaceResponse.self,
from: data
)
// MARK: The lines below should be removed when server supports PATCH.
guard let originalData = self.originalData,
let originalUser = try? ParseCoding

// MARK: The if statement below should be removed when server supports PATCH.
if let originalData = self.originalData,
let originalUser = try? ParseCoding
.jsonDecoder()
.decode(
Self.self,
from: originalData
) else {
updatedUser = try userResponse.apply(to: updatedUser)
return updatedUser
}

guard originalUser.hasSameObjectId(as: updatedUser) else {
throw ParseError(
code: .otherCause,
message: "objectId's of objects do not match"
)
) {
updatedUser = try updatedUser.merge(with: originalUser)
}

var mergedUser = try updatedUser.merge(with: originalUser)
mergedUser = try userResponse.apply(to: mergedUser)
updatedUser = try userResponse.apply(to: updatedUser)
if let sessionToken = userResponse.sessionToken {
// Only need to update here because sessionToken changed.
// Any other changes will be saved to the Keychain later.
await Self.setCurrentContainer(
.init(
currentUser: mergedUser,
currentUser: updatedUser,
sessionToken: sessionToken
)
)
}
return mergedUser
return updatedUser
}
let command = API.Command<Self, Self>(
method: .PUT,
Expand All @@ -1280,7 +1271,6 @@ extension ParseUser {
return command
}

// swiftlint:disable:next function_body_length
func updateCommand() async throws -> API.Command<Self, Self> {
guard self.objectId != nil else {
throw ParseError(code: .missingObjectId,
Expand All @@ -1302,37 +1292,29 @@ extension ParseUser {
UpdateResponse.self,
from: data
)
guard let originalData = self.originalData,
let originalUser = try? ParseCoding

if let originalData = self.originalData,
let originalUser = try? ParseCoding
.jsonDecoder()
.decode(
Self.self,
from: originalData
) else {
updatedUser = userResponse.apply(to: updatedUser)
return updatedUser
}

guard originalUser.hasSameObjectId(as: updatedUser) else {
throw ParseError(
code: .otherCause,
message: "objectId's of objects do not match"
)
) {
updatedUser = try updatedUser.merge(with: originalUser)
}

var mergedUser = try updatedUser.merge(with: originalUser)
mergedUser = userResponse.apply(to: mergedUser)
updatedUser = userResponse.apply(to: updatedUser)
if let sessionToken = userResponse.sessionToken {
// Only need to update here because sessionToken changed.
// Any other changes will be saved to the Keychain later.
await Self.setCurrentContainer(
.init(
currentUser: mergedUser,
currentUser: updatedUser,
sessionToken: sessionToken
)
)
}
return mergedUser
return updatedUser
}
let command = API.Command<Self, Self>(
method: .PATCH,
Expand Down
15 changes: 15 additions & 0 deletions Tests/ParseSwiftTests/ParseObjectTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,21 @@ class ParseObjectTests: XCTestCase { // swiftlint:disable:this type_body_length
try? fileManager.removeDirectoryContents(directory2)
}

func testReplaceResponseMissingObjectId() throws {
let object = User()
let response = ReplaceResponse(
createdAt: Date(),
updatedAt: Date(),
sessionToken: "hello"
)
do {
_ = try response.setResponseProperties(on: object)
XCTFail("Should have thrown error")
} catch {
XCTAssertTrue(error.containedIn([.missingObjectId]))
}
}

func testIsEqualExtension() throws {
let score1 = GameScore(points: 2)
let score2 = GameScore(points: 3)
Expand Down
101 changes: 101 additions & 0 deletions Tests/ParseSwiftTests/ParseUserTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1768,6 +1768,73 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length
}
}

@MainActor
func testReplaceUpdateObjectIdChanged() async throws {
try await login()
MockURLProtocol.removeAll()

var user = User()
user.username = "stop"
user.objectId = "yolo"

var serverResponse = user
serverResponse.updatedAt = Date()

MockURLProtocol.mockRequests { _ in
do {
let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)
serverResponse = try serverResponse.getDecoder().decode(User.self, from: encoded)
return MockURLResponse(data: encoded, statusCode: 200)
} catch {
return nil
}
}

user = user.set(\.objectId, to: "naw")
do {
try await user.replace()
} catch let error as ParseError {
XCTAssertEqual(error.code, .otherCause)
XCTAssertTrue(error.message.contains("do not match"))
} catch {
XCTFail("Should have casted to ParseError")
}
}

@MainActor
func testReplaceUpdateSessionTokenChanged() async throws {
try await login()
MockURLProtocol.removeAll()

var loginResponse = LoginSignupResponse()
let newToken = "newToken"
XCTAssertNotEqual(loginResponse.sessionToken, newToken)
loginResponse.sessionToken = newToken

var serverResponse = loginResponse
serverResponse.updatedAt = Date()

MockURLProtocol.mockRequests { _ in
do {
let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)
serverResponse = try serverResponse.getDecoder().decode(LoginSignupResponse.self, from: encoded)
return MockURLResponse(data: encoded, statusCode: 200)
} catch {
return nil
}
}

let originalUser = try await User.current()
let originalSessionToken = try await User.sessionToken()
let newCustomKey = "modified"
let modifiedUser = originalUser.set(\.customKey, to: newCustomKey)
let newUser = try await modifiedUser.replace()
let newSessionToken = try await User.sessionToken()
XCTAssertEqual(newUser.customKey, newCustomKey)
XCTAssertNotEqual(originalSessionToken, newToken)
XCTAssertEqual(newSessionToken, newToken)
}

@MainActor
func testUpdate() async throws {
try await login()
Expand Down Expand Up @@ -1795,6 +1862,40 @@ class ParseUserTests: XCTestCase { // swiftlint:disable:this type_body_length
XCTAssertEqual(saved.updatedAt, serverResponse.updatedAt)
}

@MainActor
func testUpdateSessionTokenChanged() async throws {
try await login()
MockURLProtocol.removeAll()

var loginResponse = LoginSignupResponse()
let newToken = "newToken"
XCTAssertNotEqual(loginResponse.sessionToken, newToken)
loginResponse.sessionToken = newToken

var serverResponse = loginResponse
serverResponse.updatedAt = Date()

MockURLProtocol.mockRequests { _ in
do {
let encoded = try serverResponse.getEncoder().encode(serverResponse, skipKeys: .none)
serverResponse = try serverResponse.getDecoder().decode(LoginSignupResponse.self, from: encoded)
return MockURLResponse(data: encoded, statusCode: 200)
} catch {
return nil
}
}

let originalUser = try await User.current()
let originalSessionToken = try await User.sessionToken()
let newCustomKey = "modified"
let modifiedUser = originalUser.set(\.customKey, to: newCustomKey)
let newUser = try await modifiedUser.update()
let newSessionToken = try await User.sessionToken()
XCTAssertEqual(newUser.customKey, newCustomKey)
XCTAssertNotEqual(originalSessionToken, newToken)
XCTAssertEqual(newSessionToken, newToken)
}

@MainActor
func testUpdateDefaultMerge() async throws {
try await login()
Expand Down

0 comments on commit 742e288

Please sign in to comment.