Skip to content
This repository was archived by the owner on Jul 10, 2025. It is now read-only.

Commit f0c1efa

Browse files
committed
display an error when an electronic publication download fails
1 parent df8a74b commit f0c1efa

File tree

6 files changed

+79
-6
lines changed

6 files changed

+79
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
1010
* Port Dry Dock field uses the proper enumeration for display
1111
* Delete Electronic Publications which are not returned from the API
1212
* Electronic Publications now sync once a day instead of once a week
13+
* Display an error upon failed download of an Electronic Publication
1314

1415
## 1.0.1
1516
### Bug Fixes

Marlin/Marlin/DataSources/ElectronicPublication/DownloadManager.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,14 @@ final class DownloadManager: NSObject {
1313
var urlToDownloadableMap: [URL: Downloadable] = [:]
1414

1515
static let shared: DownloadManager = DownloadManager()
16+
// since it is impossible to stub http requests on a background session, this is purely to be able
17+
// to override for testing
18+
var sessionConfig: URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: ElectronicPublication.backgroundDownloadIdentifier)
1619

1720
private lazy var urlSession: URLSession = {
18-
let config = URLSessionConfiguration.background(withIdentifier: ElectronicPublication.backgroundDownloadIdentifier)
19-
config.isDiscretionary = false
20-
config.sessionSendsLaunchEvents = true
21-
return URLSession(configuration: config, delegate: self, delegateQueue: nil)
21+
sessionConfig.isDiscretionary = false
22+
sessionConfig.sessionSendsLaunchEvents = true
23+
return URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
2224
}()
2325

2426
private override init() {
@@ -121,6 +123,12 @@ extension DownloadManager: URLSessionDownloadDelegate {
121123
guard let httpResponse = downloadTask.response as? HTTPURLResponse,
122124
(200...299).contains(httpResponse.statusCode) else {
123125
print ("server error code \(downloadTask.response.debugDescription)")
126+
if let httpResponse = downloadTask.response as? HTTPURLResponse {
127+
DispatchQueue.main.async {
128+
downloadable.objectWillChange.send()
129+
downloadable.error = "Error downloading (\(httpResponse.statusCode))"
130+
}
131+
}
124132
return
125133
}
126134

Marlin/Marlin/DataSources/ElectronicPublication/ElectronicPublication+CoreDataClass.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,11 +108,14 @@ protocol Downloadable: NSManagedObject {
108108
var remoteLocation: URL? { get }
109109
var savePath: String { get }
110110
var title: String? { get }
111+
var error: String? { get set }
111112
func checkFileExists() -> Bool
112113
func deleteFile()
113114
}
114115

115116
class ElectronicPublication: NSManagedObject, Downloadable {
117+
118+
var error: String?
116119

117120
var title: String? {
118121
return sectionDisplayName ?? "Electronic Publication"
@@ -175,6 +178,7 @@ class ElectronicPublication: NSManagedObject, Downloadable {
175178
}
176179

177180
func downloadFile() {
181+
error = nil
178182
if isDownloaded && checkFileExists() {
179183
return
180184
}

Marlin/Marlin/DataSources/ElectronicPublication/Views/ElectronicPublicationActionBar.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,14 @@ struct ElectronicPublicationActionBar: View {
1919
HStack(spacing:8) {
2020
Spacer()
2121
if electronicPublication.isDownloading {
22-
ProgressView(value: electronicPublication.downloadProgress)
23-
.tint(Color.primaryColorVariant)
22+
if let error = electronicPublication.error {
23+
Text(error)
24+
.secondary()
25+
Spacer()
26+
} else {
27+
ProgressView(value: electronicPublication.downloadProgress)
28+
.tint(Color.primaryColorVariant)
29+
}
2430
}
2531
if electronicPublication.isDownloaded, electronicPublication.checkFileExists(), let url = URL(string: electronicPublication.savePath) {
2632
Button("Delete") {

Marlin/Marlin/DataSources/NTM/NoticeToMariners+CoreDataClass.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import CoreData
1010
import UIKit
1111

1212
class NoticeToMariners: NSManagedObject, Downloadable {
13+
var error: String?
1314

1415
var remoteLocation: URL? {
1516
guard let odsKey else {

Marlin/MarlinTests/DataSources/ElectronicPublication/ElectronicPublicationSummaryViewTests.swift

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ final class ElectronicPublicationSummaryViewTests: XCTestCase {
2020
.receive(on: RunLoop.main)
2121

2222
override func setUp(completion: @escaping (Error?) -> Void) {
23+
HTTPStubs.setEnabled(true)
2324
for item in DataSourceList().allTabs {
2425
UserDefaults.standard.initialDataLoaded = false
2526
UserDefaults.standard.clearLastSyncTimeSeconds(item.dataSource as! any BatchImportable.Type)
@@ -34,9 +35,11 @@ final class ElectronicPublicationSummaryViewTests: XCTestCase {
3435
}
3536
.store(in: &cancellable)
3637
persistentStore.reset()
38+
HTTPStubs.removeAllStubs()
3739
}
3840

3941
override func tearDown() {
42+
HTTPStubs.removeAllStubs()
4043
}
4144

4245
func testNotDownloaded() {
@@ -141,6 +144,56 @@ final class ElectronicPublicationSummaryViewTests: XCTestCase {
141144
XCTAssertFalse(epub.checkFileExists())
142145
}
143146

147+
func testDownloadError() {
148+
let epub = ElectronicPublication(context: persistentStore.viewContext)
149+
150+
epub.pubTypeId = 9
151+
epub.pubDownloadId = 3
152+
epub.fullPubFlag = false
153+
epub.pubDownloadOrder = 1
154+
epub.pubDownloadDisplayName = "Pub. 110 - Greenland, East Coasts of North and South America, and West Indies"
155+
epub.pubsecId = 129
156+
epub.odsEntryId = 22266
157+
epub.sectionOrder = 1
158+
epub.sectionName = "UpdatedPub110bk"
159+
epub.sectionDisplayName = "Pub 110 - Updated to NTM 44/22"
160+
epub.sectionLastModified = Date(timeIntervalSince1970: 0)
161+
epub.contentId = 16694312
162+
epub.internalPath = "NIMA_LOL/Pub110"
163+
epub.filenameBase = "UpdatedPub110bk"
164+
epub.fileExtension = "pdf"
165+
epub.s3Key = "16694312/SFH00000/NIMA_LOL/Pub110/UpdatedPub110bk.pdf"
166+
epub.fileSize = 2389496
167+
epub.uploadTime = Date(timeIntervalSince1970: 0)
168+
epub.fullFilename = "UpdatedPub110bk.pdf"
169+
epub.pubsecLastModified = Date(timeIntervalSince1970: 0)
170+
epub.isDownloaded = false
171+
172+
let summary = epub.summaryView(showMoreDetails: false)
173+
174+
let controller = UIHostingController(rootView: summary)
175+
let window = TestHelpers.getKeyWindowVisible()
176+
window.rootViewController = controller
177+
tester().waitForView(withAccessibilityLabel: epub.sectionDisplayName)
178+
tester().waitForView(withAccessibilityLabel: "File Size: 2.4 MB")
179+
tester().waitForView(withAccessibilityLabel: "Upload Time: \(epub.uploadTime?.formatted() ?? "")")
180+
181+
print("all stubs: \(HTTPStubs.allStubs())")
182+
let config = URLSessionConfiguration.default
183+
DownloadManager.shared.sessionConfig = config
184+
185+
stub(condition: isScheme("https") && pathEndsWith("api/publications/download")) { request in
186+
let response = HTTPStubsResponse()
187+
response.statusCode = 403
188+
return response
189+
}
190+
191+
tester().wait(forTimeInterval: 1)
192+
tester().waitForView(withAccessibilityLabel: "Download")
193+
tester().tapView(withAccessibilityLabel: "Download")
194+
tester().waitForView(withAccessibilityLabel: "Error downloading (403)")
195+
}
196+
144197
func testReDownload() {
145198
let epub = ElectronicPublication(context: persistentStore.viewContext)
146199

0 commit comments

Comments
 (0)