Skip to content

Commit

Permalink
Merge pull request #1620 from NYPL-Simplified/release/simplye/3.9.3
Browse files Browse the repository at this point in the history
Merge SE 3.9.3 Release to Master
  • Loading branch information
Ernest Fan authored Jan 11, 2023
2 parents 7cae8e4 + e718519 commit db3facd
Show file tree
Hide file tree
Showing 56 changed files with 852 additions and 528 deletions.
2 changes: 1 addition & 1 deletion Axis-iOS
2 changes: 1 addition & 1 deletion NYPLAEToolkit
83 changes: 59 additions & 24 deletions Simplified.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion Simplified/Accounts/Library/Account.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ class OPDS2SamlIDP: NSObject, Codable {
func isSignedIn() -> Bool
}

@objc protocol NYPLReaderServerPermissions {
var syncPermissionGranted:Bool {get}
}

// MARK: AccountDetails
// Extra data that gets loaded from an OPDS2AuthenticationDocument,
@objcMembers final class AccountDetails: NSObject {
@objcMembers final class AccountDetails: NSObject, NYPLReaderServerPermissions {
enum AuthType: String, Codable {
/// This is used with barcode/username credentials on SimplyE. It was also
/// used for FirstBook authentication on Open eBooks versions before 2.4.0.
Expand Down
6 changes: 6 additions & 0 deletions Simplified/Accounts/Library/AccountsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -348,3 +348,9 @@ let currentAccountIdentifierKey = "NYPLCurrentAccountIdentifier"
}
}
}

extension AccountsManager: NYPLReaderServerPermissions {
var syncPermissionGranted: Bool {
return currentAccount?.details?.syncPermissionGranted ?? false
}
}
4 changes: 2 additions & 2 deletions Simplified/Accounts/User/NYPLUserAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ private enum StorageKey: String {
static func sharedAccount(libraryUUID: String?) -> NYPLUserAccount
}

@objc protocol NYPLOAuthTokenProvider {
@objc protocol NYPLOAuthTokenSource {
var authToken: String? { get }
func setAuthToken(_ token: String)
func hasOAuthClientCredentials() -> Bool
Expand All @@ -58,7 +58,7 @@ private enum StorageKey: String {
/// by storing credentials on the keychain using storage keys that contain the
/// the library UUID appended after the actual key name.
/// - seealso: StorageKey.keyForLibrary(uuid:)
@objcMembers class NYPLUserAccount : NSObject, NYPLUserAccountProvider, NYPLOAuthTokenProvider {
@objcMembers class NYPLUserAccount : NSObject, NYPLUserAccountProvider, NYPLOAuthTokenSource {
static private let shared = NYPLUserAccount()

private let accountInfoLock = NSRecursiveLock()
Expand Down
17 changes: 17 additions & 0 deletions Simplified/AppInfrastructure/NYPLRootTabBarController+Common.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//
// NYPLRootTabBarController+Common.swift
// Simplified
//
// Created by Ettore Pasquini on 11/9/22.
// Copyright © 2022 NYPL. All rights reserved.
//

import Foundation

extension NYPLRootTabBarController {
@objc func makeR2Owner() -> NYPLR2Owner {
self.annotationsSynchronizer = NYPLAnnotations()
return NYPLR2Owner(bookRegistry: NYPLBookRegistry.shared(),
annotationsSynchronizer: annotationsSynchronizer)
}
}
2 changes: 2 additions & 0 deletions Simplified/AppInfrastructure/NYPLRootTabBarController.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@class NYPLR2Owner;
@class NYPLAnnotations;
@class NYPLCatalogNavigationController;

@interface NYPLRootTabBarController : UITabBarController
Expand All @@ -11,6 +12,7 @@
+ (instancetype)sharedController;

@property (readonly) NYPLR2Owner *r2Owner;
@property NYPLAnnotations *annotationsSynchronizer;
@property(nonatomic, readonly) NYPLCatalogNavigationController *catalogNavigationController;

/// This method will present a view controller from the receiver, or from the
Expand Down
3 changes: 1 addition & 2 deletions Simplified/AppInfrastructure/NYPLRootTabBarController.m
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@ - (instancetype)init
selector:@selector(setTabViewControllers)
name:NSNotification.NYPLCurrentAccountDidChange
object:nil];

self.r2Owner = [[NYPLR2Owner alloc] init];
self.r2Owner = [self makeR2Owner];
return self;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ class NYPLAudiobookBookmarksBusinessLogic: NYPLAudiobookBookmarking {
let book: NYPLBook
private let drmDeviceID: String?
private let bookRegistry: NYPLAudiobookRegistryProvider
private let currentLibraryAccountProvider: NYPLCurrentLibraryAccountProvider
private let annotationsSynchronizer: NYPLAnnotationSyncing.Type
private let syncPermission: Bool
private let annotationsSynchronizer: NYPLAnnotationSyncing

var bookmarksCount: Int {
return bookmarks.count
Expand All @@ -50,12 +50,12 @@ class NYPLAudiobookBookmarksBusinessLogic: NYPLAudiobookBookmarking {
init(book: NYPLBook,
drmDeviceID: String?,
bookRegistryProvider: NYPLAudiobookRegistryProvider,
currentLibraryAccountProvider: NYPLCurrentLibraryAccountProvider,
annotationsSynchronizer: NYPLAnnotationSyncing.Type) {
syncPermission: Bool,
annotationsSynchronizer: NYPLAnnotationSyncing) {
self.book = book
self.drmDeviceID = drmDeviceID
self.bookRegistry = bookRegistryProvider
self.currentLibraryAccountProvider = currentLibraryAccountProvider
self.syncPermission = syncPermission
self.annotationsSynchronizer = annotationsSynchronizer
self.bookmarks = bookRegistry.audiobookBookmarks(for: book.identifier)
self.bookmarksDictionary = [String: [NYPLAudiobookBookmark]]()
Expand Down Expand Up @@ -216,10 +216,7 @@ class NYPLAudiobookBookmarksBusinessLogic: NYPLAudiobookBookmarking {
/// Store a bookmark to local storage and upload it to server if sync permission is granted
/// - Parameter bookmark: The bookmark to be stored and uploaded.
private func postBookmark(_ bookmark: NYPLAudiobookBookmark) {
guard
let currentAccount = currentLibraryAccountProvider.currentAccount,
let accountDetails = currentAccount.details,
accountDetails.syncPermissionGranted else {
guard syncPermission else {
self.bookRegistry.addAudiobookBookmark(bookmark, for: book.identifier)
return
}
Expand All @@ -239,14 +236,12 @@ class NYPLAudiobookBookmarksBusinessLogic: NYPLAudiobookBookmarking {
private func didDeleteBookmark(_ bookmark: NYPLAudiobookBookmark) {
bookRegistry.deleteAudiobookBookmark(bookmark, for: book.identifier)

guard let currentAccount = currentLibraryAccountProvider.currentAccount,
let details = currentAccount.details,
let annotationId = bookmark.annotationId else {
guard let annotationId = bookmark.annotationId else {
Log.info(#file, "Delete on Server skipped: Annotation ID did not exist for bookmark.")
return
}

if details.syncPermissionGranted && annotationId.count > 0 {
if syncPermission && annotationId.count > 0 {
annotationsSynchronizer.deleteBookmark(annotationId: annotationId) { (success) in
Log.info(#file, success ?
"Bookmark successfully deleted" :
Expand Down
125 changes: 125 additions & 0 deletions Simplified/Audiobooks/NYPLLastListenPositionSynchronizer.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
//
// NYPLLastListenPositionSynchronizer.swift
// Simplified
//
// Created by Ernest Fan on 2022-11-10.
// Copyright © 2022 NYPL. All rights reserved.
//
#if FEATURE_AUDIOBOOKS
import Foundation
import NYPLAudiobookToolkit

class NYPLLastListenPositionSynchronizer: NYPLLastListenPositionSynchronizing {
private let book: NYPLBook
private let bookRegistryProvider: NYPLBookRegistryProvider
private let annotationsSynchronizer: NYPLLastReadPositionSupportAPI
private let deviceID: String?

private let renderer: String = "NYPLAudiobookToolkit"

init(book: NYPLBook,
bookRegistryProvider: NYPLBookRegistryProvider,
annotationsSynchronizer: NYPLLastReadPositionSupportAPI,
deviceID: String?) {
self.book = book
self.bookRegistryProvider = bookRegistryProvider
self.annotationsSynchronizer = annotationsSynchronizer
self.deviceID = deviceID
}

func getLastListenPosition(completion: @escaping (_ localPosition: NYPLAudiobookBookmark?, _ serverPosition: NYPLAudiobookBookmark?) -> ()) {

// Retrieve local last-listened position
let localPosition = self.getLocalLastListenPosition(for: book.identifier)

// Retrieve last-listened position from server, return both local and server positions
self.annotationsSynchronizer.syncReadingPosition(of: NYPLAudiobookBookmark.self,
forBook: book.identifier,
publication: nil,
toURL: book.annotationsURL) { serverPosition in
guard let serverPosition = serverPosition else {
Log.info(#function, "No reading position annotation exists on the server for \(self.book.loggableShortString()).")
completion(localPosition, nil)
return
}

guard let localPosition = localPosition else {
completion(nil, serverPosition)
return
}

// Pass through without server position (meaning the server doesn't have a
// last listen position worth restoring) if:
// 1 - The most recent position on the server comes from the same device, or
// 2 - The local position is further in the audiobook than the server position
if serverPosition.device == self.deviceID ||
localPosition >= serverPosition {
completion(localPosition, nil)
return
}

completion(localPosition, serverPosition)
}
}

func updateLastListenPositionInMemory(_ location: ChapterLocation) {
let selectorValue = NYPLAudiobookBookmarkFactory.makeLocatorString(title: location.title ?? "",
part: location.part,
chapter: location.number,
audiobookId: location.audiobookID,
duration: location.duration,
time: location.playheadOffset)

let bookLocation = NYPLBookLocation.init(locationString: selectorValue, renderer: self.renderer)

bookRegistryProvider.setLocation(bookLocation, forIdentifier: self.book.identifier)
}


func syncLastListenPositionToServer() {
let bookID = self.book.identifier

guard let localPosition = getLocalLastListenPosition(for: bookID) else {
return
}

let selectorValue = NYPLAudiobookBookmarkFactory.makeLocatorString(title: localPosition.title ?? "",
part: localPosition.part,
chapter: localPosition.chapter,
audiobookId: localPosition.audiobookId,
duration: localPosition.duration,
time: localPosition.time)

annotationsSynchronizer.postReadingPosition(forBook: bookID,
selectorValue: selectorValue)
}

// MARK: - Helper

private func getLocalLastListenPosition(for bookID: String) -> NYPLAudiobookBookmark? {
guard let bookLocation = self.bookRegistryProvider.location(forIdentifier: bookID),
bookLocation.renderer == self.renderer else {
return nil
}

if let bookmark = NYPLAudiobookBookmark(selectorString: bookLocation.locationString, creationTime: Date()) {
return bookmark
}

if let chapterLocation = self.chapterLocation(from: bookLocation.locationString) {
// If the retrieved location is a ChapterLocation object,
// we should create a bookmark object from it.
return NYPLAudiobookBookmark(chapterLocation: chapterLocation, creationTime: Date())
}
return nil
}

private func chapterLocation(from locationString: String) -> ChapterLocation? {
guard let data = locationString.data(using: .utf8),
let chapterLocation = ChapterLocation.fromData(data) else {
return nil
}
return chapterLocation
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class NYPLAxisNetworkExecutor: NYPLAxisNetworkExecuting {

init() {
self.requestExecutor = NYPLNetworkExecutor(
credentialsProvider: NYPLUserAccount.sharedAccount(),
credentialsSource: NYPLUserAccount.sharedAccount(),
cachingStrategy: .ephemeral)
}

Expand Down
30 changes: 9 additions & 21 deletions Simplified/AxisService/Read/NYPLAxisBookReadingAdapter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,14 @@ import R2Shared
import R2Streamer

struct NYPLAxisBookReadingAdapter {

private let axisKeysProvider: NYPLAxisKeysProviding
private let decryptor: NYPLAxisContentDecrypting
private let downloader: NYPLAxisItemDownloading

init?(axisKeysProvider: NYPLAxisKeysProviding = NYPLAxisKeysProvider(),
decryptor: NYPLAxisContentDecrypting? = NYPLAxisContentDecryptor(),
downloader: NYPLAxisItemDownloading = NYPLAxisItemDownloader(downloader: NYPLAxisContentDownloader(), errorLogger: NYPLAxisErrorLogsAdapter())
) {


init?(decryptor: NYPLAxisContentDecrypting? = NYPLAxisContentDecryptor()) {
guard let decryptor = decryptor else {
return nil
}

self.axisKeysProvider = axisKeysProvider
self.decryptor = decryptor
self.downloader = downloader
}

/// Given an asset on disk, obtains the R2 ProtectedAsset needed to open
Expand All @@ -38,18 +29,17 @@ struct NYPLAxisBookReadingAdapter {
/// - asset: R2 book asset on disk associated to a NYPLBook
/// - completion: Returns a R2 tuple containing the PublicationAsset and
/// its Content Protection, or an error.
func openAsset(_ asset: FileAsset,
fetcher: Fetcher,
completion: @escaping ProtectedAssetCompletion) {
func open(asset: FileAsset,
fetcher: Fetcher,
completion: @escaping ProtectedAssetCompletion) {

let licenseService = NYPLAxisLicenseService(axisItemDownloader: downloader,
cypher: decryptor.cypher,
errorLogger: NYPLAxisErrorLogsAdapter(),
parentDirectory: asset.url)
let licenseService = NYPLAxisLicenseExtractService(
errorLogger: NYPLAxisErrorLogsAdapter(),
parentDirectory: asset.url)

// we decrypt the encrypted key (used to unlock content) and use that
// to get the ProtectedAsset
licenseService.extractAESKey { result in
licenseService.extractAESKeyFromDisk { result in
switch result {
case .success(let key):
// If it succeeded and returned data is nil,
Expand Down Expand Up @@ -85,6 +75,4 @@ struct NYPLAxisBookReadingAdapter {
onCreatePublication: nil)
return protectedAsset
}


}
11 changes: 6 additions & 5 deletions Simplified/Book/UI/NYPLBookCellDelegate+AudiobookBookmark.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ import UIKit
func setBookmarkBusinessLogic(for book: NYPLBook,
audiobookManager: DefaultAudiobookManager,
audiobookRegistryProvider: NYPLAudiobookRegistryProvider) {
let bizLogic = NYPLAudiobookBookmarksBusinessLogic(book: book,
drmDeviceID: NYPLUserAccount.sharedAccount().deviceID,
bookRegistryProvider: audiobookRegistryProvider,
currentLibraryAccountProvider: AccountsManager.shared,
annotationsSynchronizer: NYPLAnnotations.self)
let bizLogic = NYPLAudiobookBookmarksBusinessLogic(
book: book,
drmDeviceID: NYPLUserAccount.sharedAccount().deviceID,
bookRegistryProvider: audiobookRegistryProvider,
syncPermission: AccountsManager.shared.syncPermissionGranted,
annotationsSynchronizer: NYPLRootTabBarController.shared().annotationsSynchronizer)
audiobookManager.bookmarkBusinessLogic = bizLogic
}
}
Expand Down
Loading

0 comments on commit db3facd

Please sign in to comment.