diff --git a/CHDataManagement/Generator/Results/GenerationResults.swift b/CHDataManagement/Generator/Results/GenerationResults.swift index ecfca78..b9913d3 100644 --- a/CHDataManagement/Generator/Results/GenerationResults.swift +++ b/CHDataManagement/Generator/Results/GenerationResults.swift @@ -46,6 +46,15 @@ final class GenerationResults: ObservableObject { @Published var emptyPages: Set = [] + /** + The url redirects to install to prevent broken links. + + The key is the original url, and the value the new url of the content, relative to the output folder. + The dictionary is used to create a map of redirects for Nginx. + */ + @Published + var redirects: [String : String] = [:] + /// The cache of previously used GenerationResults private var cache: [ItemId : PageGenerationResults] = [:] @@ -114,6 +123,8 @@ final class GenerationResults: ObservableObject { update { self.warnings = warnings } let unsavedOutputFiles = cache.values.map { $0.unsavedOutputFiles.keys }.union() update { self.unsavedOutputFiles = unsavedOutputFiles } + let redirects = cache.values.compactMap { $0.redirect }.reduce(into: [:]) { $0[$1.originalUrl] = $1.newUrl } + update { self.redirects = redirects } } private func update(_ operation: @escaping () -> Void) { @@ -185,7 +196,11 @@ final class GenerationResults: ObservableObject { } func empty(_ page: LocalizedPageId) { - update {self.emptyPages.insert(page) } + update { self.emptyPages.insert(page) } + } + + func redirect(from originalUrl: String, to newUrl: String) { + update { self.redirects[originalUrl] = newUrl } } } diff --git a/CHDataManagement/Generator/Results/PageGenerationResults.swift b/CHDataManagement/Generator/Results/PageGenerationResults.swift index e920857..424a748 100644 --- a/CHDataManagement/Generator/Results/PageGenerationResults.swift +++ b/CHDataManagement/Generator/Results/PageGenerationResults.swift @@ -77,6 +77,8 @@ final class PageGenerationResults: ObservableObject { private(set) var pageIsEmpty: Bool + private(set) var redirect: (originalUrl: String, newUrl: String)? + init(itemId: ItemId, delegate: GenerationResults) { self.itemId = itemId self.delegate = delegate @@ -100,6 +102,7 @@ final class PageGenerationResults: ObservableObject { warnings = [] unsavedOutputFiles = [:] pageIsEmpty = false + redirect = nil } func reset() { @@ -123,6 +126,7 @@ final class PageGenerationResults: ObservableObject { warnings = [] unsavedOutputFiles = [:] pageIsEmpty = false + redirect = nil } // MARK: Adding entries @@ -251,5 +255,10 @@ final class PageGenerationResults: ObservableObject { pageIsEmpty = true delegate.empty(.init(language: itemId.language, pageId: page.id)) } + + func redirect(from originalUrl: String, to newUrl: String) { + redirect = (originalUrl, newUrl) + delegate.redirect(from: originalUrl, to: newUrl) + } } diff --git a/CHDataManagement/Model/Content+Generation.swift b/CHDataManagement/Model/Content+Generation.swift index 4c449f3..aacd0a2 100644 --- a/CHDataManagement/Model/Content+Generation.swift +++ b/CHDataManagement/Model/Content+Generation.swift @@ -13,6 +13,7 @@ extension Content { self.generateRequiredImages() self.results.recalculate() self.generateListOfExternalFiles() + self.generateListOfUrlMappings() self.status("Generation completed") } } @@ -240,6 +241,10 @@ extension Content { tag: tag) let generator = PostListPageGenerator(source: source) generator.createPages(for: posts) + + if let originalUrl = tag.localized(in: language).originalUrl { + results.redirect(from: originalUrl, to: tag.absoluteUrl(in: language)) + } } } @@ -274,11 +279,16 @@ extension Content { return } - let path = page.absoluteUrl(in: language) + ".html" - guard storage.write(content, to: path) else { + let pageUrl = page.absoluteUrl(in: language) + let filePath = pageUrl + ".html" + guard storage.write(content, to: filePath) else { print("Failed to save page \(page.id)") return } + + if let originalUrl = page.localized(in: language).originalUrl { + results.redirect(from: originalUrl, to: pageUrl) + } } // MARK: Additional infos @@ -303,4 +313,27 @@ extension Content { storage.write(content, to: externalFileListName) } + + private var redirectsListFileName: String { "redirects.txt" } + + private func generateListOfUrlMappings() { + let redirects = results.redirects.map { "\($0.key) \($0.value);" } + guard !redirects.isEmpty else { + if storage.hasFileInOutputFolder(redirectsListFileName) { + storage.deleteInOutputFolder(redirectsListFileName) + } + return + } + + let list = redirects.sorted().joined(separator: "\n ") + + let content = + """ + map $request_uri $redirect_uri { + \(list) + } + """ + + storage.write(content, to: redirectsListFileName) + } }