Implemented phase 6 for the POC prototype in the Website service.
This commit is contained in:
1 parent
256d22df40
commit
f2f445827b
40 files changed
+1906
-37
No files matched your search
@@ -64,7 +64,11 @@ extension CollectingController: RouterController {
|
||||
routes.post(.init("\(String.Route.wants)/:id/remove"), use: removeWant)
|
||||
routes.get(.init(.Route.series), use: seriesIndex)
|
||||
routes.get(.init("\(String.Route.series)/:slug"), use: series)
|
||||
routes.post(.init("\(String.Route.series)/:slug/own"), use: toggleOwned)
|
||||
routes.get(.init(.Route.compare), use: compare)
|
||||
routes.get(.init(.Route.collection), use: collection)
|
||||
routes.post(.init(.Route.collection), use: addBooks)
|
||||
routes.get(.init(.Route.events), use: events)
|
||||
|
||||
return routes
|
||||
}
|
||||
@@ -240,12 +244,18 @@ private extension CollectingController {
|
||||
let listings = try await catalogue.listings().filter { $0.seriesSlug == slug }
|
||||
let issue = request.uri.queryParameters.get("issue", as: Int.self)
|
||||
let viewer = await sessions.viewer(for: request)
|
||||
var owned: Set<Int>?
|
||||
|
||||
if let user = await sessions.user(for: request) {
|
||||
owned = try await collecting.ownedIssues(of: user)[slug] ?? []
|
||||
}
|
||||
|
||||
return .init(additionalHeaders: .perViewer) { [analytics, assetVersion] in
|
||||
SeriesPage(
|
||||
series: series,
|
||||
listings: listings,
|
||||
issue: issue,
|
||||
owned: owned,
|
||||
viewer: viewer,
|
||||
assetVersion: assetVersion,
|
||||
analytics: analytics
|
||||
@@ -277,8 +287,114 @@ private extension CollectingController {
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Collection and events
|
||||
|
||||
private extension CollectingController {
|
||||
|
||||
/// Handles books added to the collection from its form.
|
||||
@Sendable
|
||||
func addBooks(
|
||||
request: Request,
|
||||
context: Context
|
||||
) async throws -> Response {
|
||||
guard let user = await sessions.user(for: request) else {
|
||||
return .redirect(to: .Route.signIn(returningTo: .Route.collection), type: .normal)
|
||||
}
|
||||
|
||||
let form = try await URLEncodedFormDecoder().decode(BooksForm.self, from: request, context: context)
|
||||
|
||||
try await collecting.own(issues: CollectionPage.issues(in: form.issues), ofSeries: form.series, by: user)
|
||||
|
||||
return .redirect(to: .Route.collection, type: .normal)
|
||||
}
|
||||
|
||||
/// Handles a request for the collection tracker.
|
||||
@Sendable
|
||||
func collection(
|
||||
request: Request,
|
||||
context: Context
|
||||
) async throws -> Response {
|
||||
guard let user = await sessions.user(for: request) else {
|
||||
return .redirect(to: .Route.signIn(returningTo: .Route.collection), type: .found)
|
||||
}
|
||||
|
||||
let catalogue = try await collecting.allSeries()
|
||||
let owned = try await collecting.ownedIssues(of: user)
|
||||
let listings = try await self.catalogue.listings()
|
||||
let viewer = await sessions.viewer(for: request)
|
||||
|
||||
return HTMLResponse(additionalHeaders: .perViewer) { [analytics, assetVersion] in
|
||||
CollectionPage(
|
||||
catalogue: catalogue,
|
||||
owned: owned,
|
||||
listings: listings,
|
||||
viewer: viewer,
|
||||
assetVersion: assetVersion,
|
||||
analytics: analytics
|
||||
)
|
||||
}
|
||||
.response(from: request, context: context)
|
||||
}
|
||||
|
||||
/// Handles a request for the events.
|
||||
@Sendable
|
||||
func events(
|
||||
request: Request,
|
||||
context: Context
|
||||
) async throws -> HTMLResponse {
|
||||
let events = try await collecting.upcomingEvents()
|
||||
let listings = try await catalogue.listings()
|
||||
let viewer = await sessions.viewer(for: request)
|
||||
|
||||
return .init(additionalHeaders: .perViewer) { [analytics, assetVersion] in
|
||||
EventsPage(
|
||||
events: events,
|
||||
listings: listings,
|
||||
viewer: viewer,
|
||||
assetVersion: assetVersion,
|
||||
analytics: analytics
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Handles the switch on an issue of a series: into the collection, or out of it.
|
||||
@Sendable
|
||||
func toggleOwned(
|
||||
request: Request,
|
||||
context: Context
|
||||
) async throws -> Response {
|
||||
let slug = try context.parameters.require("slug")
|
||||
|
||||
guard let user = await sessions.user(for: request) else {
|
||||
return .redirect(to: .Route.signIn(returningTo: .Route.series(slug)), type: .normal)
|
||||
}
|
||||
|
||||
let form = try await URLEncodedFormDecoder().decode(IssueForm.self, from: request, context: context)
|
||||
|
||||
if try await collecting.ownedIssues(of: user)[slug]?.contains(form.issue) == true {
|
||||
try await collecting.disown(issue: form.issue, ofSeries: slug, by: user)
|
||||
} else {
|
||||
try await collecting.own(issues: [form.issue], ofSeries: slug, by: user)
|
||||
}
|
||||
|
||||
return .redirect(to: .Route.series(slug), type: .normal)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// MARK: - Structs
|
||||
|
||||
/// The fields the add-books form posts.
|
||||
private struct BooksForm: Decodable {
|
||||
let series: String
|
||||
let issues: String
|
||||
}
|
||||
|
||||
/// The field an issue's switch posts.
|
||||
private struct IssueForm: Decodable {
|
||||
let issue: Int
|
||||
}
|
||||
|
||||
/// The fields the add-a-want form posts.
|
||||
private struct WantForm: Decodable {
|
||||
let title: String
|
||||
|
||||
Reference in new issue
Block a user