Skip to content

Commit

Permalink
PostReceiptDataOperation: print receipt data if debug logs are en…
Browse files Browse the repository at this point in the history
…abled (#1940)

For [CSDK-478].
Follow up to #1929.

### Example:
> DEBUG: ℹ️ PostReceiptDataOperation: Started
INFO: ℹ️ Receipt parsed successfully
DEBUG: ℹ️ PostReceiptDataOperation: Posting receipt: {
  "opaque_value" : "Rn\/39QYAAAA=",
  "sha1_hash" : "Ii8Z7ocZm524eJcWFOvVauNrNHs=",
  "bundle_id" : "com.revenuecat.StoreKitTestApp",
  "in_app_purchases" : [
    {
      "quantity" : 1,
      "product_id" : "com.revenuecat.monthly_4.99.1_week_intro",
      "purchase_date" : "2022-09-27T19:09:47Z",
      "transaction_id" : "0",
      "is_in_intro_offer_period" : true,
      "expires_date" : "2022-09-27T19:09:57Z"
    }
  ],
  "application_version" : "1",
  "creation_date" : "2022-09-27T19:09:47Z",
  "expiration_date" : "4001-01-01T00:00:00Z"
}
DEBUG: ℹ️ There are no requests currently running, starting request POST
receipts
DEBUG: ℹ️ API request started: POST /v1/receipts
DEBUG: ℹ️ API request completed: POST /v1/receipts 200
DEBUG: ℹ️ PostReceiptDataOperation: Finished
DEBUG: ℹ️ Serial request done: POST receipts, 0 requests left in the
queue
DEBUG: ℹ️ Sending updated CustomerInfo to delegate.
INFO: 😻💰 Purchased product - 'com.revenuecat.monthly_4.99.1_week_intro'
INFO: 💰 Finishing transaction com.revenuecat.monthly_4.99.1_week_intro 0
()

[CSDK-478]:
https://revenuecats.atlassian.net/browse/CSDK-478?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
  • Loading branch information
NachoSoto authored Sep 27, 2022
1 parent b4e095e commit b32859d
Show file tree
Hide file tree
Showing 11 changed files with 76 additions and 64 deletions.
25 changes: 25 additions & 0 deletions Sources/FoundationExtensions/JSONDecoder+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,24 @@ extension Encodable {
return result
}

/// - Throws: if encoding failed
/// - Returns: `nil` if the encoded `Data` can't be serialized into a `String`.
var prettyPrintedJSON: String? {
get throws {
return String(data: try self.prettyPrintedData, encoding: .utf8)
}
}

var prettyPrintedData: Data {
get throws {
return try JSONEncoder.prettyPrinted.encode(self)
}
}

}

// MARK: -

extension JSONEncoder {

static let `default`: JSONEncoder = {
Expand All @@ -134,6 +150,15 @@ extension JSONEncoder {
return encoder
}()

static let prettyPrinted: JSONEncoder = {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.dateEncodingStrategy = .iso8601
encoder.outputFormatting = .prettyPrinted

return encoder
}()

}

extension JSONDecoder {
Expand Down
23 changes: 7 additions & 16 deletions Sources/LocalReceiptParsing/BasicTypes/AppleReceipt.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,23 +58,14 @@ struct AppleReceipt: Equatable {
return Set(productIdentifiers)
}

var asDict: [String: Any] {
return [
"bundleId": bundleId,
"applicationVersion": applicationVersion,
"originalApplicationVersion": originalApplicationVersion ?? "<unknown>",
"opaqueValue": opaqueValue,
"sha1Hash": sha1Hash,
"creationDate": creationDate,
"expirationDate": expirationDate ?? "",
"inAppPurchases": inAppPurchases.map { $0.asDict }
]
}
}

extension AppleReceipt: Codable {}

var description: String {
return String(describing: self.asDict)
extension AppleReceipt: CustomDebugStringConvertible {

var debugDescription: String {
return (try? self.prettyPrintedJSON) ?? "<null>"
}

}

extension AppleReceipt: Codable {}
30 changes: 8 additions & 22 deletions Sources/LocalReceiptParsing/BasicTypes/InAppPurchase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,29 +40,15 @@ struct InAppPurchase: Equatable {
let webOrderLineItemId: Int64?
let promotionalOfferIdentifier: String?

var asDict: [String: Any] {
return [
"quantity": quantity,
"productId": productId,
"transactionId": transactionId,
"originalTransactionId": originalTransactionId ?? "<unknown>",
"promotionalOfferIdentifier": promotionalOfferIdentifier ?? "",
"purchaseDate": purchaseDate,
"productType": productType?.rawValue ?? "",
"originalPurchaseDate": originalPurchaseDate ?? "<unknown>",
"expiresDate": expiresDate ?? "",
"cancellationDate": cancellationDate ?? "",
"isInTrialPeriod": isInTrialPeriod ?? "",
"isInIntroOfferPeriod": isInIntroOfferPeriod ?? "<unknown>",
"webOrderLineItemId": webOrderLineItemId ?? "<unknown>"
]
}

var description: String {
return String(describing: self.asDict)
}

}

extension InAppPurchase.ProductType: Codable {}
extension InAppPurchase: Codable {}

extension InAppPurchase: CustomDebugStringConvertible {

var debugDescription: String {
return (try? self.prettyPrintedJSON) ?? "<null>"
}

}
2 changes: 2 additions & 0 deletions Sources/LocalReceiptParsing/ReceiptParser.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import Foundation

class ReceiptParser {

static let `default`: ReceiptParser = .init()

private let containerBuilder: ASN1ContainerBuilder
private let receiptBuilder: AppleReceiptBuilder

Expand Down
4 changes: 4 additions & 0 deletions Sources/Logging/Strings/ReceiptStrings.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ enum ReceiptStrings {
case parsing_receipt
case refreshing_empty_receipt
case unable_to_load_receipt
case posting_receipt(AppleReceipt)

}

Expand Down Expand Up @@ -74,6 +75,9 @@ extension ReceiptStrings: CustomStringConvertible {
case .unable_to_load_receipt:
return "Unable to load receipt, ensure you are logged in to a valid Apple account."

case let .posting_receipt(receipt):
return "Posting receipt: \(receipt.debugDescription)"

}
}

Expand Down
4 changes: 2 additions & 2 deletions Sources/Networking/Operations/NetworkOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,8 @@ class NetworkOperation: Operation {

// MARK: -

private func log(_ message: String) {
Logger.debug("\(type(of: self)): \(message)")
internal func log(_ message: CustomStringConvertible) {
Logger.debug("\(type(of: self)): \(message.description)")
}

// MARK: -
Expand Down
22 changes: 22 additions & 0 deletions Sources/Networking/Operations/PostReceiptDataOperation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,10 @@ class PostReceiptDataOperation: CacheableNetworkOperation {
}

override func begin(completion: @escaping () -> Void) {
if Logger.logLevel == .debug {
self.printReceiptData()
}

self.post(completion: completion)
}

Expand All @@ -71,6 +75,24 @@ class PostReceiptDataOperation: CacheableNetworkOperation {

}

// MARK: - Private

private extension PostReceiptDataOperation {

func printReceiptData() {
do {
self.log(Strings.receipt.posting_receipt(
try ReceiptParser.default.parse(from: self.postData.receiptData)
))
} catch {
Logger.appleError(Strings.receipt.parse_receipt_locally_error(error: error))
}
}

}

// MARK: - Request Data

extension PostReceiptDataOperation.PostData: Encodable {

private enum CodingKeys: String, CodingKey {
Expand Down
4 changes: 2 additions & 2 deletions Sources/Purchasing/Purchases/Purchases.swift
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ public typealias StartPurchaseBlock = (@escaping PurchaseCompletedBlock) -> Void
let offeringsFactory = OfferingsFactory()
let userDefaults = userDefaults ?? UserDefaults.standard
let deviceCache = DeviceCache(sandboxEnvironmentDetector: systemInfo, userDefaults: userDefaults)
let receiptParser = ReceiptParser()
let receiptParser = ReceiptParser.default
let transactionsManager = TransactionsManager(storeKit2Setting: systemInfo.storeKit2Setting,
receiptParser: receiptParser)
let customerInfoManager = CustomerInfoManager(operationDispatcher: operationDispatcher,
Expand Down Expand Up @@ -1060,7 +1060,7 @@ internal extension Purchases {
func fetchReceipt(_ policy: ReceiptRefreshPolicy) async throws -> AppleReceipt? {
let receipt = await self.receiptFetcher.receiptData(refreshPolicy: policy)

return try receipt.map { try ReceiptParser().parse(from: $0) }
return try receipt.map { try ReceiptParser.default.parse(from: $0) }
}

#endif
Expand Down
20 changes: 1 addition & 19 deletions Tests/BackendIntegrationTests/StoreKitIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -578,7 +578,7 @@ private extension StoreKit1IntegrationTests {
func printReceiptContent() async {
do {
let receipt = try await Purchases.shared.fetchReceipt(.always)
let description = receipt.map { $0.description } ?? "<null>"
let description = receipt.map { $0.debugDescription } ?? "<null>"

Logger.appleWarning("Receipt content:\n\(description)")

Expand All @@ -605,21 +605,3 @@ private extension AsyncSequence {
}

}

private extension AppleReceipt {

var prettyPrintedData: Data {
get throws {
let encoder: JSONEncoder = {
let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
encoder.outputFormatting = .prettyPrinted
encoder.dateEncodingStrategy = .iso8601

return encoder
}()

return try encoder.encode(self)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class LocalReceiptParserStoreKitTests: StoreKitConfigTestCase {
operationDispatcher: operationDispatcher,
storeKit2Setting: .disabled)
self.receiptFetcher = ReceiptFetcher(requestFetcher: self.requestFetcher, systemInfo: systemInfo)
self.parser = ReceiptParser()
self.parser = .default
}

@MainActor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class ReceiptParsingRealReceiptTests: TestCase {

func testBasicReceiptAttributesForSample1() throws {
let receiptData = sampleReceiptData(receiptName: receipt1Name)
let receipt = try ReceiptParser().parse(from: receiptData)
let receipt = try ReceiptParser.default.parse(from: receiptData)

expect(receipt.applicationVersion) == "4"
expect(receipt.bundleId) == "com.revenuecat.sampleapp"
Expand All @@ -29,7 +29,7 @@ class ReceiptParsingRealReceiptTests: TestCase {

func testInAppPurchasesAttributesForSample1() throws {
let receiptData = sampleReceiptData(receiptName: receipt1Name)
let receipt = try ReceiptParser().parse(from: receiptData)
let receipt = try ReceiptParser.default.parse(from: receiptData)
let inAppPurchases = receipt.inAppPurchases

expect(inAppPurchases.count) == 9
Expand Down

0 comments on commit b32859d

Please sign in to comment.