Skip to content

Commit

Permalink
Persist ParseUser, ParseInstallation, and default ACL in Keychain (#19)
Browse files Browse the repository at this point in the history
* add ACL tests with ACL fixes

* bump codecov

* Increase timeout

* reduce test threads

* Store ParseUser and default ACL to Keychain. Additional fixes:

- Add updated badges
- Bump minimus iOS support to iOS9
- Send codecov reports for all builds

* Make logoutAsync thread test pass

* Add more code coverage

* reduce codecov

* Use BaseParseUser to get currentUser from Keychain

* Add initial documentation

* Bump minimum deployment for all OSs.

Add initial version of ParseInstallation, still needs test cases

* Fix watchOS build

* Really fix watchOS build

* Bump OS versions in podspec

* Finish Installation support with unit tests.

Also cleaned up file structure

* Add back old ParseUser threading test. Bump codecov

* Improve Keychain Installation tests

* Update installation in keychain whenever a badge update occurs

* Only persist BaseParseUser and BaseInstallation values to keychain. Added updated saving of User and Installation during fetch, find, first.

Additional updates
- updated some documentation (still more to do)
- Deleted unnecessary files

* Removed threadSafe SignUp, Login, and Logout since these are unrealistic. For example, 100 signup threads won't be created to sign up a user

* Only use ParseInstall on main thread

* Updates

* update documentation

* More updates to documentation

* Update README.md

* Use Queryable protocol

* make links point to main branch

* documentation fixes

* Change source of logo image to show in docs

* Updates with broken login

* fixed URL components contruction along with adding body. Added improved examples in playgrounds

* Add Install example to playgrounds.

Clean up Query

* Improve playgrounds and add ACL example

* Switch ACL value type name to ParseACL as it causes issues with parse-server JSON key "ACL". It also prevents you from using var ACL = ACL.defaultACL().

So we now use var ACL = ParseACL.defaultACL() instead.

* Fix ACL saving to parse-server

* Partially fixed decoding ParseError from ParseServer. Still doesn't decode message.

* Fixed decoding ParseError from server

* Updates to Query

* Added constants enum

* Update constants enum

Co-authored-by: Tom Fox <13188249+TomWFox@users.noreply.github.com>
  • Loading branch information
cbaker6 and TomWFox committed Sep 15, 2020
1 parent 2ff394d commit 5d77060
Show file tree
Hide file tree
Showing 52 changed files with 3,044 additions and 523 deletions.
2 changes: 1 addition & 1 deletion .codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ coverage:
changes: false
project:
default:
target: 52
target: 63
comment:
require_changes: true
24 changes: 21 additions & 3 deletions .github/workflows/swift.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,26 @@ jobs:
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\ \(iOS\) -destination platform\=iOS\ Simulator,name\=iPhone\ 11\ Pro\ Max build test | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_VER }}

- name: Send codecov
run: bash <(curl https://codecov.io/bash)

swift-macos:

runs-on: macos-latest

steps:
- uses: actions/checkout@v2
- name: Create and set the default keychain
run: |
security create-keychain -p "" temporary
security default-keychain -s temporary
security unlock-keychain -p "" temporary
security set-keychain-settings -lut 7200 temporary
- name: Build
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -target ParseSwift\ \(macOS\) | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_VER }}

swift-tvos:

runs-on: macos-latest
Expand All @@ -42,7 +50,9 @@ jobs:
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -target ParseSwift\ \(tvOS\) | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_VER }}

- name: Send codecov
run: bash <(curl https://codecov.io/bash)

swift-watchos:

runs-on: macos-latest
Expand All @@ -53,12 +63,20 @@ jobs:
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -target ParseSwift\ \(watchOS\) | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_VER }}
- name: Send codecov
run: bash <(curl https://codecov.io/bash)

build-test-swift:

runs-on: macos-latest
steps:
- uses: actions/checkout@v2
- name: Create and set the default keychain
run: |
security create-keychain -p "" temporary
security default-keychain -s temporary
security unlock-keychain -p "" temporary
security set-keychain-settings -lut 7200 temporary
- name: Build
run: swift build -v
env:
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,4 @@ This SDK is still in it's early phases. It's not intended as a port of the Parse

## Code of Conduct

This project adheres to the [Contributor Covenant Code of Conduct](https://github.com/parse-community/.github/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to honor this code.
This project adheres to the [Contributor Covenant Code of Conduct](https://github.com/parse-community/.github/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to honor this code.
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// swift-tools-version:5.0
// swift-tools-version:5.1

import PackageDescription

let package = Package(
name: "ParseSwift",
platforms: [.iOS(.v8), .macOS(.v10_12), .tvOS(.v9), .watchOS(.v3)],
platforms: [.iOS(.v11), .macOS(.v10_13), .tvOS(.v11), .watchOS(.v4)],
products: [
.library(
name: "ParseSwift",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
//: [Previous](@previous)

import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true

//: start parse-server with
//: npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey --mountPath /1

initializeParse()

//: Create your own ValueTyped ParseObject
struct GameScore: ParseObject {
//: Those are required for Object
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?

//: Your own properties
var score: Int

//: a custom initializer
init(score: Int) {
self.score = score
}
}

//: Define initial GameScores
let score = GameScore(score: 10)
let score2 = GameScore(score: 3)

/*: Query asynchronously (preferred way) - Performs work on background
queue and returns to designated on designated callbackQueue.
If no callbackQueue is specified it returns to main queue.
*/
score.save { result in
switch result {
case .success(let savedScore):
assert(savedScore.objectId != nil)
assert(savedScore.createdAt != nil)
assert(savedScore.updatedAt != nil)
assert(savedScore.ACL == nil)
assert(savedScore.score == 10)

/*: To modify, need to make it a var as the Value Type
was initialized as immutable
*/
var changedScore = savedScore
changedScore.score = 200
changedScore.save { result in
switch result {
case .success(var savedChangedScore):
assert(savedChangedScore.score == 200)
assert(savedScore.objectId == savedChangedScore.objectId)

/*: Note that savedChangedScore is mutable since it's
a var after success.
*/
savedChangedScore.score = 500

case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}

//: Saving multiple GameScores at once
[score, score2].saveAll { results in
switch results {
case .success(let otherResults):
otherResults.forEach { otherResult in
switch otherResult {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with score \(savedScore.score) successfully")

case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}

case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}

//: Save synchronously (not preferred - all operations on main queue)
let savedScore: GameScore?
do {
savedScore = try score.save()
} catch {
savedScore = nil
fatalError("Error saving: \(error)")
}

assert(savedScore != nil)
assert(savedScore?.objectId != nil)
assert(savedScore?.createdAt != nil)
assert(savedScore?.updatedAt != nil)
assert(savedScore?.score == 10)

/*: To modify, need to make it a var as the Value Type
was initialized as immutable
*/
guard var changedScore = savedScore else {
fatalError()
}
changedScore.score = 200

let savedChangedScore: GameScore?
do {
savedChangedScore = try changedScore.save()
} catch {
savedChangedScore = nil
fatalError("Error saving: \(error)")
}

assert(savedChangedScore != nil)
assert(savedChangedScore!.score == 200)
assert(savedScore!.objectId == savedChangedScore!.objectId)

let otherResults: [(Result<GameScore, ParseError>)]?
do {
otherResults = try [score, score2].saveAll()
} catch {
otherResults = nil
fatalError("Error saving: \(error)")
}
assert(otherResults != nil)

otherResults!.forEach { result in
switch result {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with score \(savedScore.score) successfully")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}

PlaygroundPage.current.finishExecution()

//: [Next](@next)

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//: [Previous](@previous)

import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true

initializeParse()

struct GameScore: ParseObject {
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?

var score: Int?
}

var score = GameScore()
score.score = 200
try score.save()

let afterDate = Date().addingTimeInterval(-300)
var query = GameScore.query("score" > 100, "createdAt" > afterDate)

// Query asynchronously (preferred way) - Performs work on background
// queue and returns to designated on designated callbackQueue.
// If no callbackQueue is specified it returns to main queue
query.limit(2).find(callbackQueue: .main) { results in
switch results {
case .success(let scores):

assert(scores.count >= 1)
scores.forEach { (score) in
guard let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
}

case .failure(let error):
assertionFailure("Error querying: \(error)")
}
}

// Query synchronously (not preferred - all operations on main queue)
let results = try query.limit(2).find()
assert(results.count >= 1)
results.forEach { (score) in
guard let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
}

PlaygroundPage.current.finishExecution()

//: [Next](@next)

This file was deleted.

Loading

0 comments on commit 5d77060

Please sign in to comment.