Skip to content

Commit

Permalink
fix: use default ACL on newly created ParseObjects (#284)
Browse files Browse the repository at this point in the history
* fix: use defaultACL if available when creating ParseObjects

* Update changeling

* Add test cases

* don't run test on linux
  • Loading branch information
cbaker6 authored Nov 19, 2021
1 parent 863781b commit b4bdfb1
Show file tree
Hide file tree
Showing 19 changed files with 645 additions and 70 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,15 @@

### main

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

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

__Fixes__
- Use default ACL automatically on newley created ParseObject's if a default ACL is available ([#283](https://github.com/parse-community/Parse-Swift/pull/283)), thanks to [Corey Baker](https://github.com/cbaker6).

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

Expand Down
8 changes: 8 additions & 0 deletions ParseSwift.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@
70170A4E2656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */; };
70170A4F2656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */; };
70170A502656EBA50070C905 /* ParseAnalyticsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */; };
7023800F2747FCCD00EFC443 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */; };
702380102747FCCD00EFC443 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */; };
702380112747FCCD00EFC443 /* ExtensionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */; };
7028373426BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };
7028373526BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };
7028373626BD8883007688C9 /* ParseObject+async.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7028373326BD8883007688C9 /* ParseObject+async.swift */; };
Expand Down Expand Up @@ -828,6 +831,7 @@
70170A432656B02C0070C905 /* ParseAnalytics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnalytics.swift; sourceTree = "<group>"; };
70170A482656E2FE0070C905 /* ParseAnalytics+combine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseAnalytics+combine.swift"; sourceTree = "<group>"; };
70170A4D2656EBA50070C905 /* ParseAnalyticsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParseAnalyticsTests.swift; sourceTree = "<group>"; };
7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionsTests.swift; sourceTree = "<group>"; };
7028373326BD8883007688C9 /* ParseObject+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseObject+async.swift"; sourceTree = "<group>"; };
7028373826BD8C89007688C9 /* ParseUser+async.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ParseUser+async.swift"; sourceTree = "<group>"; };
7033ECB025584A83009770F3 /* TestHostTV.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TestHostTV.app; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -1139,6 +1143,7 @@
children = (
4AA8076D1F794C1C008CD551 /* Info.plist */,
911DB12D24C4837E0027F3C7 /* APICommandTests.swift */,
7023800E2747FCCD00EFC443 /* ExtensionsTests.swift */,
7003957525A0EE770052CB31 /* BatchUtilsTests.swift */,
70DFEA892618E77800F8EB4B /* InitializeSDKTests.swift */,
709B40C0268F999000ED2EAC /* IOS13Tests.swift */,
Expand Down Expand Up @@ -2233,6 +2238,7 @@
705A99F9259807F900B3547F /* ParseFileManagerTests.swift in Sources */,
7044C20625C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */,
70C5508525B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */,
7023800F2747FCCD00EFC443 /* ExtensionsTests.swift in Sources */,
917BA43E2703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */,
7037DAB226384DE1005D7E62 /* TestParseEncoder.swift in Sources */,
7004C24D25B69207005E0AD9 /* ParseRoleTests.swift in Sources */,
Expand Down Expand Up @@ -2457,6 +2463,7 @@
705A99FB259807F900B3547F /* ParseFileManagerTests.swift in Sources */,
7044C20825C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */,
70C5508725B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */,
702380112747FCCD00EFC443 /* ExtensionsTests.swift in Sources */,
917BA4402703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */,
7037DAB426384DE1005D7E62 /* TestParseEncoder.swift in Sources */,
7004C26125B6920B005E0AD9 /* ParseRoleTests.swift in Sources */,
Expand Down Expand Up @@ -2544,6 +2551,7 @@
705A99FA259807F900B3547F /* ParseFileManagerTests.swift in Sources */,
7044C20725C5D6780011F6E7 /* ParseQueryCombineTests.swift in Sources */,
70C5508625B4A68700B5DBC2 /* ParseOperationTests.swift in Sources */,
702380102747FCCD00EFC443 /* ExtensionsTests.swift in Sources */,
917BA43F2703E84000F8D747 /* ParseOperationAsyncTests.swift in Sources */,
7037DAB326384DE1005D7E62 /* TestParseEncoder.swift in Sources */,
7004C25725B6920A005E0AD9 /* ParseRoleTests.swift in Sources */,
Expand Down
5 changes: 5 additions & 0 deletions Sources/ParseSwift/API/API+Command.swift
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,11 @@ internal extension API.Command {

// MARK: Saving ParseObjects - private
private static func create<T>(_ object: T) -> API.Command<T, T> where T: ParseObject {
var object = object
if object.ACL == nil,
let acl = try? ParseACL.defaultACL() {
object.ACL = acl
}
let mapper = { (data) -> T in
try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(to: object)
}
Expand Down
47 changes: 25 additions & 22 deletions Sources/ParseSwift/Coding/ParseEncoder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -318,32 +318,35 @@ private class _ParseEncoder: JSONEncoder, Encoder {
} else {
valueToEncode = pointer
}
} else if let object = value as? Objectable,
let pointer = try? PointerType(object) {
if let uniquePointer = self.uniquePointer,
uniquePointer.hasSameObjectId(as: pointer) {
throw ParseError(code: .unknownError,
message: "Found a circular dependency when encoding.")
}
if !self.collectChildren && codingPath.count > 0 {
valueToEncode = value
} else if let object = value as? Objectable {
if let pointer = try? PointerType(object) {
if let uniquePointer = self.uniquePointer,
uniquePointer.hasSameObjectId(as: pointer) {
throw ParseError(code: .unknownError,
message: "Found a circular dependency when encoding.")
}
if !self.collectChildren && codingPath.count > 0 {
valueToEncode = value
} else {
valueToEncode = pointer
}
} else {
valueToEncode = pointer
}
} else {
let hashOfCurrentObject = try BaseObjectable.createHash(value)
if self.collectChildren {
var object = object
if object.ACL == nil,
let acl = try? ParseACL.defaultACL() {
object.ACL = acl
}
let hashOfCurrentObject = try BaseObjectable.createHash(object)
valueToEncode = object
if let pointerForCurrentObject = self.objectsSavedBeforeThisOne?[hashOfCurrentObject] {
valueToEncode = pointerForCurrentObject
} else {
//New object needs to be saved before it can be pointed to
self.newObjects.append(value)
} else if self.collectChildren {
// New object needs to be saved before it can be pointed to
self.newObjects.append(object)
} else if dictionary.count > 0 {
// Only top level objects can be saved without a pointer
throw ParseError(code: .unknownError, message: "Error. Couldn't resolve unsaved object while encoding.")
}
} else if let pointerForCurrentObject = self.objectsSavedBeforeThisOne?[hashOfCurrentObject] {
valueToEncode = pointerForCurrentObject
} else if dictionary.count > 0 {
//Only top level objects can be saved without a pointer
throw ParseError(code: .unknownError, message: "Error. Couldn't resolve unsaved object while encoding.")
}
}
return valueToEncode
Expand Down
9 changes: 7 additions & 2 deletions Sources/ParseSwift/Objects/ParseInstallation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -598,12 +598,17 @@ extension ParseInstallation {

// MARK: Saving ParseObjects - private
private func createCommand() -> API.Command<Self, Self> {
var object = self
if object.ACL == nil,
let acl = try? ParseACL.defaultACL() {
object.ACL = acl
}
let mapper = { (data) -> Self in
try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(to: self)
try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(to: object)
}
return API.Command<Self, Self>(method: .POST,
path: endpoint(.POST),
body: self,
body: object,
mapper: mapper)
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/ParseSwift/Objects/ParseObject.swift
Original file line number Diff line number Diff line change
Expand Up @@ -792,10 +792,10 @@ extension ParseObject {
try waitingToBeSaved.forEach { parseType in

if let parseFile = parseType as? ParseFile {
//ParseFiles can be saved now
// ParseFiles can be saved now
savableFiles.append(parseFile)
} else if let parseObject = parseType as? Objectable {
//This is a ParseObject
// This is a ParseObject
let waitingObjectInfo = try ParseCoding
.parseEncoder()
.encode(parseObject,
Expand Down
9 changes: 7 additions & 2 deletions Sources/ParseSwift/Objects/ParseUser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -979,12 +979,17 @@ extension ParseUser {

// MARK: Saving ParseObjects - private
private func createCommand() -> API.Command<Self, Self> {
var object = self
if object.ACL == nil,
let acl = try? ParseACL.defaultACL() {
object.ACL = acl
}
let mapper = { (data) -> Self in
try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(to: self)
try ParseCoding.jsonDecoder().decode(SaveResponse.self, from: data).apply(to: object)
}
return API.Command<Self, Self>(method: .POST,
path: endpoint(.POST),
body: self,
body: object,
mapper: mapper)
}

Expand Down
2 changes: 1 addition & 1 deletion Sources/ParseSwift/ParseConstants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import Foundation

enum ParseConstants {
static let sdk = "swift"
static let version = "2.2.5"
static let version = "2.2.6"
static let fileManagementDirectory = "parse/"
static let fileManagementPrivateDocumentsDirectory = "Private Documents/"
static let fileManagementLibraryDirectory = "Library/"
Expand Down
42 changes: 24 additions & 18 deletions Sources/ParseSwift/Types/ParseACL.swift
Original file line number Diff line number Diff line change
Expand Up @@ -303,32 +303,38 @@ extension ParseACL {
*/
public static func defaultACL() throws -> Self {

let aclController: DefaultACL?
let aclController: DefaultACL!

#if !os(Linux) && !os(Android) && !os(Windows)
aclController = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.defaultACL)
if let controller: DefaultACL = try? KeychainStore.shared.get(valueFor: ParseStorage.Keys.defaultACL) {
aclController = controller
} else {
throw ParseError(code: .unknownError,
message: "Default ACL can't be found in Keychain. You should `setDefaultACL` first")
}
#else
aclController = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.defaultACL)
if let controller: DefaultACL = try? ParseStorage.shared.get(valueFor: ParseStorage.Keys.defaultACL) {
aclController = controller
} else {
throw ParseError(code: .unknownError,
message: "Default ACL can't be found in Keychain. You should `setDefaultACL` first")
}
#endif

if let acl = aclController {
if !acl.useCurrentUser {
return acl.defaultACL
} else {
guard let userObjectId = BaseParseUser.current?.objectId else {
return acl.defaultACL
}

guard let lastCurrentUserObjectId = acl.lastCurrentUserObjectId,
userObjectId == lastCurrentUserObjectId else {
return try setDefaultACL(ParseACL(), withAccessForCurrentUser: true)
}
if !aclController.useCurrentUser {
return aclController.defaultACL
} else {
guard let userObjectId = BaseParseUser.current?.objectId else {
return aclController.defaultACL
}

return acl.defaultACL
guard let lastCurrentUserObjectId = aclController.lastCurrentUserObjectId,
userObjectId == lastCurrentUserObjectId else {
return try setDefaultACL(ParseACL(), withAccessForCurrentUser: true)
}
}

return try setDefaultACL(ParseACL(), withAccessForCurrentUser: true)
return aclController.defaultACL
}
}

/**
Expand Down
42 changes: 42 additions & 0 deletions Tests/ParseSwiftTests/ExtensionsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//
// ExtensionsTests.swift
// ParseSwift
//
// Created by Corey Baker on 11/19/21.
// Copyright © 2021 Parse Community. All rights reserved.
//

import Foundation
import XCTest
@testable import ParseSwift

class ExtensionsTests: XCTestCase {
override func setUpWithError() throws {
try super.setUpWithError()
guard let url = URL(string: "http://localhost:1337/1") else {
XCTFail("Should create valid URL")
return
}
ParseSwift.initialize(applicationId: "applicationId",
clientKey: "clientKey",
masterKey: "masterKey",
serverURL: url,
testing: true)
}

override func tearDownWithError() throws {
try super.tearDownWithError()
MockURLProtocol.removeAll()
#if !os(Linux) && !os(Android) && !os(Windows)
try KeychainStore.shared.deleteAll()
#endif
try ParseStorage.shared.deleteAll()
}

#if !os(Linux) && !os(Android) && !os(Windows)
func testURLSession() throws {
ParseSwift.configuration.isTestingSDK = false
XCTAssertNotNil(URLSession.parse.configuration.urlCache)
}
#endif
}
8 changes: 5 additions & 3 deletions Tests/ParseSwiftTests/ParseACLTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ class ParseACLTests: XCTestCase {
}
}

func testNoDefaultACL() {
XCTAssertThrowsError(try ParseACL.defaultACL())
}

func testDefaultACL() {
let loginResponse = LoginSignupResponse()
let loginUserName = "hello10"
Expand Down Expand Up @@ -276,10 +280,8 @@ class ParseACLTests: XCTestCase {
newACL.publicRead = true
newACL.publicWrite = true
do {
var defaultACL = try ParseACL.defaultACL()
XCTAssertNotEqual(newACL, defaultACL)
_ = try ParseACL.setDefaultACL(newACL, withAccessForCurrentUser: true)
defaultACL = try ParseACL.defaultACL()
let defaultACL = try ParseACL.defaultACL()
XCTAssertEqual(newACL.publicRead, defaultACL.publicRead)
XCTAssertEqual(newACL.publicWrite, defaultACL.publicWrite)
XCTAssertTrue(defaultACL.getReadAccess(objectId: userObjectId))
Expand Down
1 change: 0 additions & 1 deletion Tests/ParseSwiftTests/ParseAnalyticsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,6 @@ class ParseAnalyticsTests: XCTestCase {
func testTrackAppOpenedNotAuthorized() {
if #available(macOS 11.0, iOS 14.0, macCatalyst 14.0, tvOS 14.0, *) {
ParseSwift.configuration.isTestingSDK = false //Allow authorization check

let expectation = XCTestExpectation(description: "Analytics save")
ParseAnalytics.trackAppOpened(dimensions: ["stop": "drop"]) { result in

Expand Down
4 changes: 2 additions & 2 deletions Tests/ParseSwiftTests/ParseInstallationAsyncTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,8 @@ class ParseInstallationAsyncTests: XCTestCase { // swiftlint:disable:this type_b
}

do {
let saved = try Installation.current!.save()
guard let newCurrentInstallation = Installation.current else {
guard let saved = try Installation.current?.save(),
let newCurrentInstallation = Installation.current else {
XCTFail("Should have a new current installation")
return
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/ParseSwiftTests/ParseInstallationCombineTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,8 @@ class ParseInstallationCombineTests: XCTestCase { // swiftlint:disable:this type
}

do {
let saved = try Installation.current!.save()
guard let newCurrentInstallation = Installation.current else {
guard let saved = try Installation.current?.save(),
let newCurrentInstallation = Installation.current else {
XCTFail("Should have a new current installation")
return
}
Expand Down
Loading

0 comments on commit b4bdfb1

Please sign in to comment.