-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Improve routing API * Rename generic types * Update README for v0.7.0 * Update SPI links
- Loading branch information
1 parent
900653c
commit 64b2f36
Showing
21 changed files
with
518 additions
and
855 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
182 changes: 182 additions & 0 deletions
182
Sources/VaporWalletOrders/OrdersServiceCustom+RouteCollection.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import Fluent | ||
import FluentWalletOrders | ||
import Vapor | ||
import VaporWallet | ||
|
||
extension OrdersServiceCustom: RouteCollection { | ||
public func boot(routes: any RoutesBuilder) throws { | ||
let orderTypeIdentifier = PathComponent(stringLiteral: OrderDataType.typeIdentifier) | ||
|
||
let v1 = routes.grouped("v1") | ||
v1.get("devices", ":deviceIdentifier", "registrations", orderTypeIdentifier, use: self.ordersForDevice) | ||
v1.post("log", use: self.logMessage) | ||
|
||
let v1auth = v1.grouped(AppleOrderMiddleware<OrderType>()) | ||
v1auth.post("devices", ":deviceIdentifier", "registrations", orderTypeIdentifier, ":orderIdentifier", use: self.registerDevice) | ||
v1auth.get("orders", orderTypeIdentifier, ":orderIdentifier", use: self.latestVersionOfOrder) | ||
v1auth.delete("devices", ":deviceIdentifier", "registrations", orderTypeIdentifier, ":orderIdentifier", use: self.unregisterDevice) | ||
} | ||
|
||
private func latestVersionOfOrder(req: Request) async throws -> Response { | ||
req.logger.debug("Called latestVersionOfOrder") | ||
|
||
var ifModifiedSince: TimeInterval = 0 | ||
if let header = req.headers[.ifModifiedSince].first, let ims = TimeInterval(header) { | ||
ifModifiedSince = ims | ||
} | ||
|
||
guard let id = req.parameters.get("orderIdentifier", as: UUID.self) else { | ||
throw Abort(.badRequest) | ||
} | ||
guard | ||
let order = try await OrderType.query(on: req.db) | ||
.filter(\._$id == id) | ||
.filter(\._$typeIdentifier == OrderDataType.typeIdentifier) | ||
.first() | ||
else { | ||
throw Abort(.notFound) | ||
} | ||
|
||
guard ifModifiedSince < order.updatedAt?.timeIntervalSince1970 ?? 0 else { | ||
throw Abort(.notModified) | ||
} | ||
|
||
guard | ||
let orderData = try await OrderDataType.query(on: req.db) | ||
.filter(\._$order.$id == id) | ||
.first() | ||
else { | ||
throw Abort(.notFound) | ||
} | ||
|
||
var headers = HTTPHeaders() | ||
headers.add(name: .contentType, value: "application/vnd.apple.order") | ||
headers.lastModified = HTTPHeaders.LastModified(order.updatedAt ?? Date.distantPast) | ||
headers.add(name: .contentTransferEncoding, value: "binary") | ||
return try await Response( | ||
status: .ok, | ||
headers: headers, | ||
body: Response.Body(data: self.build(order: orderData, on: req.db)) | ||
) | ||
} | ||
|
||
private func registerDevice(req: Request) async throws -> HTTPStatus { | ||
req.logger.debug("Called register device") | ||
|
||
let pushToken: String | ||
do { | ||
pushToken = try req.content.decode(PushTokenDTO.self).pushToken | ||
} catch { | ||
throw Abort(.badRequest) | ||
} | ||
|
||
guard let orderIdentifier = req.parameters.get("orderIdentifier", as: UUID.self) else { | ||
throw Abort(.badRequest) | ||
} | ||
let deviceIdentifier = req.parameters.get("deviceIdentifier")! | ||
guard | ||
let order = try await OrderType.query(on: req.db) | ||
.filter(\._$id == orderIdentifier) | ||
.filter(\._$typeIdentifier == OrderDataType.typeIdentifier) | ||
.first() | ||
else { | ||
throw Abort(.notFound) | ||
} | ||
|
||
let device = try await DeviceType.query(on: req.db) | ||
.filter(\._$libraryIdentifier == deviceIdentifier) | ||
.filter(\._$pushToken == pushToken) | ||
.first() | ||
if let device = device { | ||
return try await Self.createRegistration(device: device, order: order, db: req.db) | ||
} else { | ||
let newDevice = DeviceType(libraryIdentifier: deviceIdentifier, pushToken: pushToken) | ||
try await newDevice.create(on: req.db) | ||
return try await Self.createRegistration(device: newDevice, order: order, db: req.db) | ||
} | ||
} | ||
|
||
private static func createRegistration(device: DeviceType, order: OrderType, db: any Database) async throws -> HTTPStatus { | ||
let r = try await OrdersRegistrationType.for( | ||
deviceLibraryIdentifier: device.libraryIdentifier, | ||
typeIdentifier: order.typeIdentifier, | ||
on: db | ||
) | ||
.filter(OrderType.self, \._$id == order.requireID()) | ||
.first() | ||
// If the registration already exists, docs say to return 200 OK | ||
if r != nil { return .ok } | ||
|
||
let registration = OrdersRegistrationType() | ||
registration._$order.id = try order.requireID() | ||
registration._$device.id = try device.requireID() | ||
try await registration.create(on: db) | ||
return .created | ||
} | ||
|
||
private func ordersForDevice(req: Request) async throws -> OrderIdentifiersDTO { | ||
req.logger.debug("Called ordersForDevice") | ||
|
||
let deviceIdentifier = req.parameters.get("deviceIdentifier")! | ||
|
||
var query = OrdersRegistrationType.for( | ||
deviceLibraryIdentifier: deviceIdentifier, | ||
typeIdentifier: OrderDataType.typeIdentifier, | ||
on: req.db | ||
) | ||
if let since: TimeInterval = req.query["ordersModifiedSince"] { | ||
let when = Date(timeIntervalSince1970: since) | ||
query = query.filter(OrderType.self, \._$updatedAt > when) | ||
} | ||
|
||
let registrations = try await query.all() | ||
guard !registrations.isEmpty else { | ||
throw Abort(.noContent) | ||
} | ||
|
||
var orderIdentifiers: [String] = [] | ||
var maxDate = Date.distantPast | ||
for registration in registrations { | ||
let order = try await registration._$order.get(on: req.db) | ||
try orderIdentifiers.append(order.requireID().uuidString) | ||
if let updatedAt = order.updatedAt, updatedAt > maxDate { | ||
maxDate = updatedAt | ||
} | ||
} | ||
|
||
return OrderIdentifiersDTO(with: orderIdentifiers, maxDate: maxDate) | ||
} | ||
|
||
private func logMessage(req: Request) async throws -> HTTPStatus { | ||
let entries = try req.content.decode(LogEntriesDTO.self) | ||
|
||
for log in entries.logs { | ||
req.logger.notice("VaporWalletOrders: \(log)") | ||
} | ||
|
||
return .ok | ||
} | ||
|
||
private func unregisterDevice(req: Request) async throws -> HTTPStatus { | ||
req.logger.debug("Called unregisterDevice") | ||
|
||
guard let orderIdentifier = req.parameters.get("orderIdentifier", as: UUID.self) else { | ||
throw Abort(.badRequest) | ||
} | ||
let deviceIdentifier = req.parameters.get("deviceIdentifier")! | ||
|
||
guard | ||
let r = try await OrdersRegistrationType.for( | ||
deviceLibraryIdentifier: deviceIdentifier, | ||
typeIdentifier: OrderDataType.typeIdentifier, | ||
on: req.db | ||
) | ||
.filter(OrderType.self, \._$id == orderIdentifier) | ||
.first() | ||
else { | ||
throw Abort(.notFound) | ||
} | ||
try await r.delete(on: req.db) | ||
return .ok | ||
} | ||
} |
Oops, something went wrong.