Skip to content

Commit

Permalink
Merge pull request #1545 from NYPL-Simplified/release/simplye/3.8.5
Browse files Browse the repository at this point in the history
Merge SimplyE 3.8.5 to master
  • Loading branch information
Ernest Fan authored Mar 28, 2022
2 parents dd6344d + 23ff46f commit 098d81f
Show file tree
Hide file tree
Showing 33 changed files with 220 additions and 101 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/archive-and-upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ jobs:
with:
submodules: true
token: ${{ secrets.IOS_DEV_CI_PAT }}
- name: Update Fastlane
run: bundle update --bundler && bundle update fastlane
- name: Print Fastlane version
run: fastlane -v
- name: Add Private Repo Auth
# This ensures SPM can resolve dependencies for private repos.
# Other options included using `-usePackageSupportBuiltinSCM` (or
Expand Down
2 changes: 1 addition & 1 deletion Axis-iOS
2 changes: 1 addition & 1 deletion CardCreator-iOS
2 changes: 1 addition & 1 deletion Certificates
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
source "https://rubygems.org"

gem "fastlane"
gem "fastlane", "2.205.0"

2 changes: 1 addition & 1 deletion NYPLAEToolkit
2 changes: 1 addition & 1 deletion NYPLAudiobookToolkit
94 changes: 26 additions & 68 deletions Simplified.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"repositoryURL": "https://github.com/NYPL-Simplified/iOS-Utilities",
"state": {
"branch": "main",
"revision": "ba9e5e8e511bf6f2acc1c4f9262ff5e405bfcb1d",
"revision": "0f4dda618061dbf2a360aaed39a140c43d797248",
"version": null
}
},
Expand Down
18 changes: 12 additions & 6 deletions Simplified/Accounts/Library/Account.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import UIKit

private let userAboveAgeKey = "NYPLSettingsUserAboveAgeKey"
private let accountSyncEnabledKey = "NYPLAccountSyncEnabledKey"
Expand Down Expand Up @@ -406,7 +407,7 @@ class OPDS2SamlIDP: NSObject, Codable {
/// No guarantees are being made about whether this is called on the main
/// thread or not. This closure is not retained by `self`.
@objc(loadAuthenticationDocumentUsingSignedInStateProvider:completion:)
func loadAuthenticationDocument(using signedInStateProvider: NYPLSignedInStateProvider? = nil, completion: @escaping (Bool) -> ()) {
func loadAuthenticationDocument(using signedInStateProvider: NYPLSignedInStateProvider? = nil, completion: @escaping (Bool, Error?) -> ()) {
Log.debug(#function, "Entering...")
guard let urlString = authenticationDocumentUrl, let url = URL(string: urlString) else {
NYPLErrorLogger.logError(
Expand All @@ -415,7 +416,7 @@ class OPDS2SamlIDP: NSObject, Codable {
metadata: ["self.uuid": uuid,
"urlString": authenticationDocumentUrl ?? "N/A"]
)
completion(false)
completion(false, nil)
return
}

Expand All @@ -425,7 +426,7 @@ class OPDS2SamlIDP: NSObject, Codable {
do {
self.authenticationDocument = try
OPDS2AuthenticationDocument.fromData(serverData)
completion(true)
completion(true, nil)
if let provider = signedInStateProvider,
provider.isSignedIn(),
let announcements = self.authenticationDocument?.announcements {
Expand All @@ -444,15 +445,20 @@ class OPDS2SamlIDP: NSObject, Codable {
"url": url
]
)
completion(false)
completion(false, error)
}
case .failure(let error, _):
NYPLErrorLogger.logError(
withCode: .authDocLoadFail,
summary: "Authentication Document request failed to load",
metadata: ["loadError": error, "url": url]
metadata: [
"loadError": error,
"url": url,
"HTTPStatusCode": error.httpStatusCode
]
)
completion(false)

completion(false, error)
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion Simplified/Accounts/Library/AccountsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ let currentAccountIdentifierKey = "NYPLCurrentAccountIdentifier"
// changing the `accountsSets` dictionary will also change `currentAccount`
Log.debug(#function, "hadAccount=\(hadAccount) currentAccountID=\(currentAccountId ?? "N/A") currentAcct=\(String(describing: currentAccount))")
if hadAccount != (self.currentAccount != nil) {
self.currentAccount?.loadAuthenticationDocument(using: NYPLUserAccount.sharedAccount(), completion: { success in
self.currentAccount?.loadAuthenticationDocument(using: NYPLUserAccount.sharedAccount(), completion: { _success, _error in
DispatchQueue.main.async {
var mainFeed = URL(string: self.currentAccount?.catalogUrl ?? "")
let resolveFn = {
Expand Down
1 change: 1 addition & 0 deletions Simplified/AppInfrastructure/SimplyE-Bridging-Header.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@
#import "NYPLXML.h"
#import "UIFont+NYPLSystemFontOverride.h"
#import "UIView+NYPLViewAdditions.h"
#import "NYPLBookCellDelegate.h"
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// NYPLBookCellDelegate+AudiobookProgressSaving.swift
// Simplified
//
// Created by Ernest Fan on 2022-03-01.
// Copyright © 2022 NYPL. All rights reserved.
//
#if FEATURE_AUDIOBOOKS
import Foundation
import NYPLAudiobookToolkit
import UIKit
import NYPLUtilities

private let NYPLAudiobookProgressSavingInterval: DispatchTimeInterval = .seconds(60)

@objc extension NYPLBookCellDelegate {

private func savePosition() {
NYPLBookRegistry.shared().save()
}

// Create a timer that saves the audiobook progress periodically when the app is inactive.
// We do save the progress when app is being killed and applicationWillTerminate: is called,
// but applicationWillTerminate: is not always called when users force quit the app.
// This method is triggered when app resigns active.
@objc(scheduleProgressSavingTimerForAudiobookManager:)
func scheduleProgressSavingTimer(for manager: DefaultAudiobookManager?) {
guard let manager = manager else {
return
}

weak var weakManager = manager

let timer = NYPLRepeatingTimer(interval: NYPLAudiobookProgressSavingInterval,
queue: self.audiobookProgressSavingQueue) { [weak self] in
var isActive = false

NYPLMainThreadRun.sync {
isActive = UIApplication.shared.applicationState == .active
}

if isActive {
// DispatchSourceTimer will automatically cancel the timer if it is released.
weakManager?.cancelProgressSavingTimer()
} else {
if let manager = weakManager,
!manager.progressSavingTimerIsNil() {
self?.savePosition()
}
}
}
manager.setProgressSavingTimer(timer)
}
}
#endif
9 changes: 9 additions & 0 deletions Simplified/Book/UI/NYPLBookCellDelegate+Audiobooks.m
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@ - (void)openAudiobook:(NYPLBook *)book withJSON:(NSDictionary *)json decryptor:(

// poll audiobook player so that we can save the reading position
[self scheduleTimerForAudiobook:book manager:manager viewController:audiobookVC];

[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(scheduleAudiobookProgressSavingTimer)
name:UIApplicationWillResignActiveNotification
object:nil];
}];
}];
}
Expand Down Expand Up @@ -216,6 +221,10 @@ - (void)scheduleTimerForAudiobook:(NYPLBook *)book
}];
}

- (void)scheduleAudiobookProgressSavingTimer {
[self scheduleProgressSavingTimerForAudiobookManager:self.manager];
}

- (void)presentDRMKeyError:(NSError *) error
{
NSString *title = NSLocalizedString(@"DRM Error", nil);
Expand Down
3 changes: 2 additions & 1 deletion Simplified/Book/UI/NYPLBookCellDelegate.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#if FEATURE_AUDIOBOOKS
@import NYPLAudiobookToolkit;
@class DefaultAudiobookManager;
#endif

#import "NYPLBookDownloadFailedCell.h"
Expand All @@ -19,6 +19,7 @@ shared cover registry, shared download center, et cetera. */
@property (nonatomic) NYPLBook *book;
#if FEATURE_AUDIOBOOKS
@property DefaultAudiobookManager *manager;
@property dispatch_queue_t audiobookProgressSavingQueue;
#endif
@property (strong) NSLock *refreshAudiobookLock;

Expand Down
3 changes: 3 additions & 0 deletions Simplified/Book/UI/NYPLBookCellDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ - (instancetype)init
self = [super init];

_refreshAudiobookLock = [[NSLock alloc] init];
#if FEATURE_AUDIOBOOKS
_audiobookProgressSavingQueue = dispatch_queue_create("org.nypl.labs.SimplyE.BookCellDelegate.audiobookProgressSavingQueue", nil);
#endif

return self;
}
Expand Down
5 changes: 4 additions & 1 deletion Simplified/Catalog/NYPLCatalogNavigationController.m
Original file line number Diff line number Diff line change
Expand Up @@ -95,14 +95,17 @@ - (void)currentAccountChanged
#ifdef SIMPLYE
- (void)updateCatalogFeedSettingCurrentAccount:(Account *)account
{
[account loadAuthenticationDocumentUsingSignedInStateProvider:nil completion:^(BOOL success) {
[account loadAuthenticationDocumentUsingSignedInStateProvider:nil completion:^(BOOL success, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
if (success) {
[AccountsManager shared].currentAccount = account;
[self updateFeedAndRegistryOnAccountChange];
} else {
NSString *title = NSLocalizedString(@"Error Loading Library", @"Title for alert related to error loading library authentication doc");
NSString *msg = NSLocalizedString(@"We can’t get your library right now. Please close and reopen the app to try again.", @"Message for alert related to error loading library authentication doc");
msg = [msg stringByAppendingFormat:@" (%@: %ld)",
NSLocalizedString(@"HTTP status", "Label for HTTP error code"),
(long)error.httpStatusCode];
UIAlertController *alert = [NYPLAlertUtils
alertWithTitle:title
message:msg];
Expand Down
13 changes: 13 additions & 0 deletions Simplified/ErrorHandling/NYPLUserFriendlyError.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ protocol NYPLUserFriendlyError: Error {
/// A user-friendly short message describing the error in more detail,
/// if possible.
var userFriendlyMessage: String? { get }

/// The status code of a HTTP response, if present. Should be 0 otherwise.
var httpStatusCode: Int { get }
}

// Dummy implementation merely to ease error reporting work upstream, where
Expand All @@ -26,15 +29,21 @@ protocol NYPLUserFriendlyError: Error {
extension NYPLUserFriendlyError {
var userFriendlyTitle: String? { return nil }
var userFriendlyMessage: String? { return nil }
var httpStatusCode: Int { return 0 }
}

extension NSError: NYPLUserFriendlyError {
private static let problemDocumentKey = "problemDocument"
public static let httpResponseKey = "response"

@objc var problemDocument: NYPLProblemDocument? {
return userInfo[NSError.problemDocumentKey] as? NYPLProblemDocument
}

var httpResponse: HTTPURLResponse? {
return userInfo[NSError.httpResponseKey] as? HTTPURLResponse
}

/// Feeds off of the `problemDocument` computed property
@objc var userFriendlyTitle: String? {
return problemDocument?.title
Expand All @@ -46,6 +55,10 @@ extension NSError: NYPLUserFriendlyError {
return (problemDocument?.detail ?? userInfo[NSLocalizedDescriptionKey]) as? String
}

@objc var httpStatusCode: Int {
return httpResponse?.statusCode ?? 0
}

/// Builds an NSError using the given problem document for its user-friendly
/// messaging.
/// - Parameters:
Expand Down
16 changes: 9 additions & 7 deletions Simplified/Network/NYPLNetworkResponder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,18 @@ extension NYPLNetworkResponder: URLSessionDataDelegate {
// no problem document nor error, but response could still be a failure
if let httpResponse = task.response as? HTTPURLResponse {
guard httpResponse.isSuccess() else {
logMetadata["response"] = httpResponse
logMetadata[NSLocalizedDescriptionKey] = NSLocalizedString("UnknownRequestError", comment: "A generic error message for when a network request fails")
let err = NSError(domain: "Api call with failure HTTP status",
code: NYPLErrorCode.responseFail.rawValue,
userInfo: logMetadata)
currentTaskInfo.completion(.failure(err, task.response))
logMetadata[NSLocalizedDescriptionKey] = NSLocalizedString("Server response failure: please check your connection or try again later.", comment: "A generic error message for a HTTP response failure")
NYPLErrorLogger.logNetworkError(code: NYPLErrorCode.responseFail,
summary: "Network request failed: server error response",
request: task.originalRequest,
response: httpResponse,
metadata: logMetadata)

logMetadata[NSError.httpResponseKey] = httpResponse
let err = NSError(domain: "API call failure",
code: NYPLErrorCode.responseFail.rawValue,
userInfo: logMetadata)
currentTaskInfo.completion(.failure(err, httpResponse))
return
}
}
Expand Down Expand Up @@ -250,7 +252,7 @@ extension URLSessionTask {
userInfo["taskOriginalRequest"] = originalRequest
}
if let response = response {
userInfo["response"] = response
userInfo[NSError.httpResponseKey] = response
}

let err = NSError.makeFromProblemDocument(
Expand Down
7 changes: 5 additions & 2 deletions Simplified/OPDS/NYPLOPDSFeedFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,15 @@ import Foundation

let catalogFeed = NYPLCatalogUngroupedFeed.init(opdsFeed: feed)
if let catalogFeed = catalogFeed,
catalogFeed.books.count == 0 {
fetchCatalogUngroupedFeed(url: catalogFeed.nextURL,
catalogFeed.books.count == 0,
let nextURL = catalogFeed.nextURL {
// Returned feed contains zero supported books, but more feed is available
fetchCatalogUngroupedFeed(url: nextURL,
networkExecutor: networkExecutor,
retryCount: retryCount + 1,
completion: completion)
} else {
// Feed contains supported books or no books at all
completion(catalogFeed)
}
}
Expand Down
2 changes: 1 addition & 1 deletion Simplified/Reader2/Bookmarks/NYPLAnnotations.swift
Original file line number Diff line number Diff line change
Expand Up @@ -585,7 +585,7 @@ protocol NYPLAnnotationSyncing: AnyObject {
code: NYPLErrorCode.responseFail.rawValue,
userInfo: [
"Serializable annotation params": parameters,
"Response": response ?? "N/A"
NSError.httpResponseKey: response ?? "N/A"
])
completionHandler(.failure(err))
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ extension NYPLSignInBusinessLogic {
barcode: barcode,
metadata: [
"Request": request.loggableString,
"Response": response ?? "N/A",
NSError.httpResponseKey: response ?? "N/A",
"HTTP status code": statusCode
])
self.uiDelegate?.businessLogic(self,
Expand Down
4 changes: 3 additions & 1 deletion Simplified/SignInLogic/NYPLSignInBusinessLogic.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
// Copyright © 2020 NYPL. All rights reserved.
//

import Foundation

@objc enum NYPLAuthRequestType: Int {
case signIn = 1
case signOut = 2
Expand Down Expand Up @@ -372,7 +374,7 @@ class NYPLSignInBusinessLogic: NSObject, NYPLSignedInStateProvider, NYPLCurrentL
}

isAuthenticationDocumentLoading = true
libraryAccount?.loadAuthenticationDocument(using: self) { success in
libraryAccount?.loadAuthenticationDocument(using: self) { success, _error in
self.isAuthenticationDocumentLoading = false
completion(success)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ import PureLayout
} else {
// Show loading overlay while we load the auth document
let loadingOverlay = self.addLoadingOverlayView(toVC: self.navigationController)
account.loadAuthenticationDocument { (success) in
account.loadAuthenticationDocument { success, error in
DispatchQueue.main.async {
self.removeLoadingOverlayView(loadingOverlay)
guard success else {
Expand Down Expand Up @@ -246,7 +246,7 @@ import PureLayout
loadingOverlay = self.addLoadingOverlayView()
}
// Load the auth document for the classics library
classicsAccount.loadAuthenticationDocument { (authSuccess) in
classicsAccount.loadAuthenticationDocument { authSuccess, _error in
DispatchQueue.main.async {
self.removeLoadingOverlayView(loadingOverlay)
if authSuccess {
Expand Down
Loading

0 comments on commit 098d81f

Please sign in to comment.