| @@ -0,0 +1,7 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <Workspace | |||||
| version = "1.0"> | |||||
| <FileRef | |||||
| location = "self:"> | |||||
| </FileRef> | |||||
| </Workspace> | |||||
| @@ -0,0 +1,14 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |||||
| <plist version="1.0"> | |||||
| <dict> | |||||
| <key>SchemeUserState</key> | |||||
| <dict> | |||||
| <key>Fueling.xcscheme_^#shared#^_</key> | |||||
| <dict> | |||||
| <key>orderHint</key> | |||||
| <integer>0</integer> | |||||
| </dict> | |||||
| </dict> | |||||
| </dict> | |||||
| </plist> | |||||
| @@ -0,0 +1,77 @@ | |||||
| # ================================ | |||||
| # Build image | |||||
| # ================================ | |||||
| FROM swift:5.8-jammy as build | |||||
| # Install OS updates and, if needed, sqlite3 | |||||
| RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ | |||||
| && apt-get -q update \ | |||||
| && apt-get -q dist-upgrade -y\ | |||||
| && rm -rf /var/lib/apt/lists/* | |||||
| # Set up a build area | |||||
| WORKDIR /build | |||||
| # First just resolve dependencies. | |||||
| # This creates a cached layer that can be reused | |||||
| # as long as your Package.swift/Package.resolved | |||||
| # files do not change. | |||||
| COPY ./Package.* ./ | |||||
| RUN swift package resolve | |||||
| # Copy entire repo into container | |||||
| COPY . . | |||||
| # Build everything, with optimizations | |||||
| RUN swift build -c release --static-swift-stdlib | |||||
| # Switch to the staging area | |||||
| WORKDIR /staging | |||||
| # Copy main executable to staging area | |||||
| RUN cp "$(swift build --package-path /build -c release --show-bin-path)/App" ./ | |||||
| # Copy resources bundled by SPM to staging area | |||||
| RUN find -L "$(swift build --package-path /build -c release --show-bin-path)/" -regex '.*\.resources$' -exec cp -Ra {} ./ \; | |||||
| # Copy any resources from the public directory and views directory if the directories exist | |||||
| # Ensure that by default, neither the directory nor any of its contents are writable. | |||||
| RUN [ -d /build/Public ] && { mv /build/Public ./Public && chmod -R a-w ./Public; } || true | |||||
| RUN [ -d /build/Resources ] && { mv /build/Resources ./Resources && chmod -R a-w ./Resources; } || true | |||||
| # ================================ | |||||
| # Run image | |||||
| # ================================ | |||||
| FROM ubuntu:jammy | |||||
| # Make sure all system packages are up to date, and install only essential packages. | |||||
| RUN export DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true \ | |||||
| && apt-get -q update \ | |||||
| && apt-get -q dist-upgrade -y \ | |||||
| && apt-get -q install -y \ | |||||
| ca-certificates \ | |||||
| tzdata \ | |||||
| # If your app or its dependencies import FoundationNetworking, also install `libcurl4`. | |||||
| # libcurl4 \ | |||||
| # If your app or its dependencies import FoundationXML, also install `libxml2`. | |||||
| # libxml2 \ | |||||
| && rm -r /var/lib/apt/lists/* | |||||
| # Create a vapor user and group with /app as its home directory | |||||
| RUN useradd --user-group --create-home --system --skel /dev/null --home-dir /app vapor | |||||
| # Switch to the new home directory | |||||
| WORKDIR /app | |||||
| # Copy built executable and any staged resources from builder | |||||
| COPY --from=build --chown=vapor:vapor /staging /app | |||||
| # Ensure all further commands run as the vapor user | |||||
| USER vapor:vapor | |||||
| # Let Docker bind to port 8080 | |||||
| EXPOSE 8080 | |||||
| # Start the Vapor service when the image is run, default to listening on 8080 in production environment | |||||
| ENTRYPOINT ["./App"] | |||||
| CMD ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] | |||||
| @@ -0,0 +1,239 @@ | |||||
| { | |||||
| "pins" : [ | |||||
| { | |||||
| "identity" : "async-http-client", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/swift-server/async-http-client.git", | |||||
| "state" : { | |||||
| "revision" : "333e60cc90f52973f7ee29cd8e3a7f6adfe79f4e", | |||||
| "version" : "1.17.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "async-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/async-kit.git", | |||||
| "state" : { | |||||
| "revision" : "a61da00d404ec91d12766f1b9aac7d90777b484d", | |||||
| "version" : "1.17.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "console-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/console-kit.git", | |||||
| "state" : { | |||||
| "revision" : "447f1046fb4e9df40973fe426ecb24a6f0e8d3b4", | |||||
| "version" : "4.6.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "fluent", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/fluent.git", | |||||
| "state" : { | |||||
| "revision" : "4b4d8bf15a06fd60137e9c543e5503c4b842654e", | |||||
| "version" : "4.8.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "fluent-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/fluent-kit.git", | |||||
| "state" : { | |||||
| "revision" : "559dc9c730cde77cc9dac76fba73d6e0855f0220", | |||||
| "version" : "1.42.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "fluent-postgres-driver", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/fluent-postgres-driver.git", | |||||
| "state" : { | |||||
| "revision" : "afc07463fc5589f5bf95f98ae2719d13ad9fbbcf", | |||||
| "version" : "2.6.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "multipart-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/multipart-kit.git", | |||||
| "state" : { | |||||
| "revision" : "1adfd69df2da08f7931d4281b257475e32c96734", | |||||
| "version" : "4.5.4" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "postgres-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/postgres-kit.git", | |||||
| "state" : { | |||||
| "revision" : "3ad08265aade48fff5f2ec772e96ecf51b7900a2", | |||||
| "version" : "2.10.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "postgres-nio", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/postgres-nio.git", | |||||
| "state" : { | |||||
| "revision" : "98b8e1b1488c706f8bff9eb07560745630a64679", | |||||
| "version" : "1.14.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "routing-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/routing-kit.git", | |||||
| "state" : { | |||||
| "revision" : "611bc45c5dfb1f54b84d99b89d1f72191fb6b71b", | |||||
| "version" : "4.7.2" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "sql-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/sql-kit.git", | |||||
| "state" : { | |||||
| "revision" : "d547122756534d8224d4599739da0e82e4695623", | |||||
| "version" : "3.25.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-algorithms", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-algorithms.git", | |||||
| "state" : { | |||||
| "revision" : "b14b7f4c528c942f121c8b860b9410b2bf57825e", | |||||
| "version" : "1.0.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-atomics", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-atomics.git", | |||||
| "state" : { | |||||
| "revision" : "6c89474e62719ddcc1e9614989fff2f68208fe10", | |||||
| "version" : "1.1.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-backtrace", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/swift-server/swift-backtrace.git", | |||||
| "state" : { | |||||
| "revision" : "f25620d5d05e2f1ba27154b40cafea2b67566956", | |||||
| "version" : "1.3.3" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-collections", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-collections.git", | |||||
| "state" : { | |||||
| "revision" : "937e904258d22af6e447a0b72c0bc67583ef64a2", | |||||
| "version" : "1.0.4" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-crypto", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-crypto.git", | |||||
| "state" : { | |||||
| "revision" : "33a20e650c33f6d72d822d558333f2085effa3dc", | |||||
| "version" : "2.5.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-log", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-log.git", | |||||
| "state" : { | |||||
| "revision" : "32e8d724467f8fe623624570367e3d50c5638e46", | |||||
| "version" : "1.5.2" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-metrics", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-metrics.git", | |||||
| "state" : { | |||||
| "revision" : "e8bced74bc6d747745935e469f45d03f048d6cbd", | |||||
| "version" : "2.3.4" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-nio", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-nio.git", | |||||
| "state" : { | |||||
| "revision" : "f7c46552983b06b0958a1a4c8bc5199406ae4c8a", | |||||
| "version" : "2.51.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-nio-extras", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-nio-extras.git", | |||||
| "state" : { | |||||
| "revision" : "0e0d0aab665ff1a0659ce75ac003081f2b1c8997", | |||||
| "version" : "1.19.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-nio-http2", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-nio-http2.git", | |||||
| "state" : { | |||||
| "revision" : "6d021a48483dbb273a9be43f65234bdc9185b364", | |||||
| "version" : "1.26.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-nio-ssl", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-nio-ssl.git", | |||||
| "state" : { | |||||
| "revision" : "9d0d5d8798a576fbf674a823734e65e15ca5f2ec", | |||||
| "version" : "2.23.1" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-nio-transport-services", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-nio-transport-services.git", | |||||
| "state" : { | |||||
| "revision" : "59b966415dd336db6f388bbfe3fb43cfa549b981", | |||||
| "version" : "1.16.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "swift-numerics", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/apple/swift-numerics", | |||||
| "state" : { | |||||
| "revision" : "0a5bc04095a675662cf24757cc0640aa2204253b", | |||||
| "version" : "1.0.2" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "vapor", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/vapor.git", | |||||
| "state" : { | |||||
| "revision" : "f4b00a5350238fe896d865d96d64f12fcbbeda95", | |||||
| "version" : "4.76.0" | |||||
| } | |||||
| }, | |||||
| { | |||||
| "identity" : "websocket-kit", | |||||
| "kind" : "remoteSourceControl", | |||||
| "location" : "https://github.com/vapor/websocket-kit.git", | |||||
| "state" : { | |||||
| "revision" : "2166cbe932b29b6419f9cd751e8b27c647e1238e", | |||||
| "version" : "2.8.0" | |||||
| } | |||||
| } | |||||
| ], | |||||
| "version" : 2 | |||||
| } | |||||
| @@ -0,0 +1,35 @@ | |||||
| // swift-tools-version:5.8 | |||||
| import PackageDescription | |||||
| let package = Package( | |||||
| name: "Fueling", | |||||
| platforms: [ | |||||
| .macOS(.v12) | |||||
| ], | |||||
| dependencies: [ | |||||
| // 💧 A server-side Swift web framework. | |||||
| .package(url: "https://github.com/vapor/vapor.git", from: "4.76.0"), | |||||
| .package(url: "https://github.com/vapor/fluent.git", from: "4.8.0"), | |||||
| .package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0"), | |||||
| ], | |||||
| targets: [ | |||||
| .executableTarget( | |||||
| name: "App", | |||||
| dependencies: [ | |||||
| .product(name: "Fluent", package: "fluent"), | |||||
| .product(name: "FluentPostgresDriver", package: "fluent-postgres-driver"), | |||||
| .product(name: "Vapor", package: "vapor") | |||||
| ], | |||||
| swiftSettings: [ | |||||
| // Enable better optimizations when building in Release configuration. Despite the use of | |||||
| // the `.unsafeFlags` construct required by SwiftPM, this flag is recommended for Release | |||||
| // builds. See <https://www.swift.org/server/guides/building.html#building-for-production> for details. | |||||
| .unsafeFlags(["-cross-module-optimization"], .when(configuration: .release)) | |||||
| ] | |||||
| ), | |||||
| .testTarget(name: "AppTests", dependencies: [ | |||||
| .target(name: "App"), | |||||
| .product(name: "XCTVapor", package: "vapor"), | |||||
| ]) | |||||
| ] | |||||
| ) | |||||
| @@ -0,0 +1,41 @@ | |||||
| // | |||||
| // FuelEntryController.swift | |||||
| // | |||||
| // | |||||
| // Created by Bill Ryckman on 4/24/23. | |||||
| // | |||||
| import Vapor | |||||
| struct FuelEntryController: RouteCollection { | |||||
| func boot(routes: RoutesBuilder) throws { | |||||
| let fuelEntries = routes.grouped("fuel_entries") | |||||
| fuelEntries.get(use: index) | |||||
| fuelEntries.post(use: create) | |||||
| fuelEntries.group(":fuelEntryID") { fuelEntry in | |||||
| fuelEntry.delete(use: delete) | |||||
| } | |||||
| } | |||||
| func index(req: Request) async throws -> [FuelEntry] { | |||||
| try await FuelEntry.query(on: req.db).all() | |||||
| } | |||||
| func create(req: Request) async throws -> FuelEntry { | |||||
| let fuelEntry = try req.content.decode(FuelEntry.self) | |||||
| try await fuelEntry.save(on: req.db) | |||||
| return fuelEntry | |||||
| } | |||||
| func delete(req: Request) async throws -> HTTPStatus { | |||||
| guard let fuelEntry = try await FuelEntry.find(req.parameters.get("fuelEntryID"), on: req.db) else { | |||||
| throw Abort(.notFound) | |||||
| } | |||||
| try await fuelEntry.delete(on: req.db) | |||||
| return .noContent | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,31 @@ | |||||
| import Fluent | |||||
| import Vapor | |||||
| struct TodoController: RouteCollection { | |||||
| func boot(routes: RoutesBuilder) throws { | |||||
| let todos = routes.grouped("todos") | |||||
| todos.get(use: index) | |||||
| todos.post(use: create) | |||||
| todos.group(":todoID") { todo in | |||||
| todo.delete(use: delete) | |||||
| } | |||||
| } | |||||
| func index(req: Request) async throws -> [Todo] { | |||||
| try await Todo.query(on: req.db).all() | |||||
| } | |||||
| func create(req: Request) async throws -> Todo { | |||||
| let todo = try req.content.decode(Todo.self) | |||||
| try await todo.save(on: req.db) | |||||
| return todo | |||||
| } | |||||
| func delete(req: Request) async throws -> HTTPStatus { | |||||
| guard let todo = try await Todo.find(req.parameters.get("todoID"), on: req.db) else { | |||||
| throw Abort(.notFound) | |||||
| } | |||||
| try await todo.delete(on: req.db) | |||||
| return .noContent | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,34 @@ | |||||
| // | |||||
| // File.swift | |||||
| // | |||||
| // | |||||
| // Created by Bill Ryckman on 4/26/23. | |||||
| // | |||||
| import Vapor | |||||
| import Fluent | |||||
| struct CreateFuelEntry: AsyncMigration { | |||||
| func prepare(on database: Database) async throws { | |||||
| try await database.schema("fuel_entries") | |||||
| .id() | |||||
| .field("timestamp", .datetime) | |||||
| .field("user_id", .string) | |||||
| .field("gps_location", .string) | |||||
| .field("image", .string) | |||||
| .field("product", .string) | |||||
| .field("make", .string) | |||||
| .field("model", .string) | |||||
| .field("serial_number", .string) | |||||
| .field("tank_id", .string) | |||||
| .field("fuel_amount", .double) | |||||
| .field("fuel_type", .string) | |||||
| .field("is_override", .bool) | |||||
| .create() | |||||
| } | |||||
| func revert(on database: Database) async throws { | |||||
| try await database.schema("fuel_entries").delete() | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| import Fluent | |||||
| struct CreateTodo: AsyncMigration { | |||||
| func prepare(on database: Database) async throws { | |||||
| try await database.schema("todos") | |||||
| .id() | |||||
| .field("title", .string, .required) | |||||
| .create() | |||||
| } | |||||
| func revert(on database: Database) async throws { | |||||
| try await database.schema("todos").delete() | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,105 @@ | |||||
| // | |||||
| // FuelEntry.swift | |||||
| // | |||||
| // | |||||
| // Created by Bill Ryckman on 4/24/23. | |||||
| // | |||||
| import Fluent | |||||
| import Vapor | |||||
| final class FuelEntry: Model, Content { | |||||
| static let schema = "fuel_entries" | |||||
| @ID(key: .id) | |||||
| var id: UUID? | |||||
| @Field(key: "timestamp") | |||||
| var timestamp: Date | |||||
| @Field(key: "user_id") | |||||
| var userID: String | |||||
| @Field(key: "gps_location") | |||||
| var gpsLocation: String | |||||
| @Field(key: "image") | |||||
| var image: String | |||||
| @Field(key: "product") | |||||
| var product: String | |||||
| @Field(key: "make") | |||||
| var make: String | |||||
| @Field(key: "model") | |||||
| var model: String | |||||
| @Field(key: "serial_number") | |||||
| var serialNumber: String | |||||
| @Field(key: "tank_id") | |||||
| var tankID: String | |||||
| @Field(key: "fuel_amount") | |||||
| var fuelAmount: Double | |||||
| @Field(key: "fuel_type") | |||||
| var fuelType: String | |||||
| @Field(key: "is_override") | |||||
| var isOverride: Bool | |||||
| init() {} | |||||
| init(id: UUID? = nil, timestamp: Date, userID: String, gpsLocation: String, image: String, product: String, make: String, model: String, serialNumber: String, tankID: String, fuelAmount: Double, fuelType: String, isOverride: Bool) { | |||||
| self.id = id | |||||
| self.timestamp = timestamp | |||||
| self.userID = userID | |||||
| self.gpsLocation = gpsLocation | |||||
| self.image = image | |||||
| self.product = product | |||||
| self.make = make | |||||
| self.model = model | |||||
| self.serialNumber = serialNumber | |||||
| self.tankID = tankID | |||||
| self.fuelAmount = fuelAmount | |||||
| self.fuelType = fuelType | |||||
| self.isOverride = isOverride | |||||
| } | |||||
| } | |||||
| //extension FuelEntry: Content {} | |||||
| //extension FuelEntry: Migration { | |||||
| // func prepare(on database: FluentKit.Database) -> NIOCore.EventLoopFuture<Void> { | |||||
| // <#code#> | |||||
| // } | |||||
| // | |||||
| // func revert(on database: FluentKit.Database) -> NIOCore.EventLoopFuture<Void> { | |||||
| // <#code#> | |||||
| // } | |||||
| // func prepare(on database: Database) -> EventLoopFuture<Void> { | |||||
| // return database.schema("fuel_entries") | |||||
| // .id() | |||||
| // .field("timestamp", .datetime) | |||||
| // .field("user_id", .string) | |||||
| // .field("gps_location", .string) | |||||
| // .field("image", .string) | |||||
| // .field("product", .string) | |||||
| // .field("make", .string) | |||||
| // .field("model", .string) | |||||
| // .field("serial_number", .string) | |||||
| // .field("tank_id", .string) | |||||
| // .field("fuel_amount", .double) | |||||
| // .field("fuel_type", .string) | |||||
| // .field("is_override", .bool) | |||||
| // .create() | |||||
| // } | |||||
| // | |||||
| // func revert(on database: Database) -> EventLoopFuture<Void> { | |||||
| // return database.schema("fuel_entries").delete() | |||||
| // } | |||||
| //} | |||||
| //extension FuelEntry: Parameter {} | |||||
| @@ -0,0 +1,19 @@ | |||||
| import Fluent | |||||
| import Vapor | |||||
| final class Todo: Model, Content { | |||||
| static let schema = "todos" | |||||
| @ID(key: .id) | |||||
| var id: UUID? | |||||
| @Field(key: "title") | |||||
| var title: String | |||||
| init() { } | |||||
| init(id: UUID? = nil, title: String) { | |||||
| self.id = id | |||||
| self.title = title | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,29 @@ | |||||
| import Fluent | |||||
| import FluentPostgresDriver | |||||
| import Vapor | |||||
| // configures your application | |||||
| public func configure(_ app: Application) async throws { | |||||
| // uncomment to serve files from /Public folder | |||||
| // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) | |||||
| app.databases.use(.postgres(hostname: "localhost", username: "mcarman", password: "@ng31F@rm0823262", database: "fueling"), as: .psql) | |||||
| // app.databases.use(.postgres( | |||||
| // hostname: Environment.get("localhost") ?? "localhost", | |||||
| // port: Environment.get("5432").flatMap(Int.init(_:)) ?? PostgresConfiguration.ianaPortNumber, | |||||
| // username: Environment.get("mcarman") ?? "vapor_username", | |||||
| // //username: Environment.get("bryckman") ?? "vapor_username", | |||||
| // password: Environment.get("@ng31F@rm0823262" ?? "vapor_password"), | |||||
| // //password: Environment.get("55H1ck0ry1669") ?? "vapor_password", | |||||
| // database: Environment.get("fueling") ?? "vapor_database" | |||||
| // ), as: .psql) | |||||
| app.http.server.configuration.port = 3001 | |||||
| // app.migrations.add(CreateTodo()) | |||||
| app.migrations.add(CreateFuelEntry()) | |||||
| try await app.autoMigrate().get() | |||||
| // register routes | |||||
| try routes(app) | |||||
| } | |||||
| @@ -0,0 +1,35 @@ | |||||
| import Vapor | |||||
| import Dispatch | |||||
| import Logging | |||||
| /// This extension is temporary and can be removed once Vapor gets this support. | |||||
| private extension Vapor.Application { | |||||
| static let baseExecutionQueue = DispatchQueue(label: "vapor.codes.entrypoint") | |||||
| func runFromAsyncMainEntrypoint() async throws { | |||||
| try await withCheckedThrowingContinuation { continuation in | |||||
| Vapor.Application.baseExecutionQueue.async { [self] in | |||||
| do { | |||||
| try self.run() | |||||
| continuation.resume() | |||||
| } catch { | |||||
| continuation.resume(throwing: error) | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @main | |||||
| enum Entrypoint { | |||||
| static func main() async throws { | |||||
| var env = try Environment.detect() | |||||
| try LoggingSystem.bootstrap(from: &env) | |||||
| let app = Application(env) | |||||
| defer { app.shutdown() } | |||||
| try await configure(app) | |||||
| try await app.runFromAsyncMainEntrypoint() | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,34 @@ | |||||
| //import Fluent | |||||
| //import Vapor | |||||
| // | |||||
| //func routes(_ app: Application) throws { | |||||
| // app.get { req async in | |||||
| // "It works!" | |||||
| // } | |||||
| // | |||||
| // app.get("hello") { req async -> String in | |||||
| // "Hello, world!" | |||||
| // } | |||||
| // | |||||
| // try app.register(collection: TodoController()) | |||||
| //} | |||||
| import Vapor | |||||
| func routes(_ app: Application) throws { | |||||
| let fuelEntryController = FuelEntryController() | |||||
| app.get("fuel-entries") { req in | |||||
| try await fuelEntryController.index(req: req) | |||||
| } | |||||
| app.post("fuel-entries") { req in | |||||
| try await fuelEntryController.create(req: req) | |||||
| } | |||||
| app.delete("fuel-entries", ":fuelEntryID") { req in | |||||
| try await fuelEntryController.delete(req: req) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,15 @@ | |||||
| @testable import App | |||||
| import XCTVapor | |||||
| final class AppTests: XCTestCase { | |||||
| func testHelloWorld() async throws { | |||||
| let app = Application(.testing) | |||||
| defer { app.shutdown() } | |||||
| try await configure(app) | |||||
| try app.test(.GET, "hello", afterResponse: { res in | |||||
| XCTAssertEqual(res.status, .ok) | |||||
| XCTAssertEqual(res.body.string, "Hello, world!") | |||||
| }) | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,74 @@ | |||||
| # Docker Compose file for Vapor | |||||
| # | |||||
| # Install Docker on your system to run and test | |||||
| # your Vapor app in a production-like environment. | |||||
| # | |||||
| # Note: This file is intended for testing and does not | |||||
| # implement best practices for a production deployment. | |||||
| # | |||||
| # Learn more: https://docs.docker.com/compose/reference/ | |||||
| # | |||||
| # Build images: docker-compose build | |||||
| # Start app: docker-compose up app | |||||
| # Start database: docker-compose up db | |||||
| # Run migrations: docker-compose run migrate | |||||
| # Stop all: docker-compose down (add -v to wipe db) | |||||
| # | |||||
| version: '3.7' | |||||
| volumes: | |||||
| db_data: | |||||
| x-shared_environment: &shared_environment | |||||
| LOG_LEVEL: ${LOG_LEVEL:-debug} | |||||
| DATABASE_HOST: db | |||||
| DATABASE_NAME: vapor_database | |||||
| DATABASE_USERNAME: vapor_username | |||||
| DATABASE_PASSWORD: vapor_password | |||||
| services: | |||||
| app: | |||||
| image: fueling:latest | |||||
| build: | |||||
| context: . | |||||
| environment: | |||||
| <<: *shared_environment | |||||
| depends_on: | |||||
| - db | |||||
| ports: | |||||
| - '8080:8080' | |||||
| # user: '0' # uncomment to run as root for testing purposes even though Dockerfile defines 'vapor' user. | |||||
| command: ["serve", "--env", "production", "--hostname", "0.0.0.0", "--port", "8080"] | |||||
| migrate: | |||||
| image: fueling:latest | |||||
| build: | |||||
| context: . | |||||
| environment: | |||||
| <<: *shared_environment | |||||
| depends_on: | |||||
| - db | |||||
| command: ["migrate", "--yes"] | |||||
| deploy: | |||||
| replicas: 0 | |||||
| revert: | |||||
| image: fueling:latest | |||||
| build: | |||||
| context: . | |||||
| environment: | |||||
| <<: *shared_environment | |||||
| depends_on: | |||||
| - db | |||||
| command: ["migrate", "--revert", "--yes"] | |||||
| deploy: | |||||
| replicas: 0 | |||||
| db: | |||||
| image: postgres:15-alpine | |||||
| volumes: | |||||
| - db_data:/var/lib/postgresql/data/pgdata | |||||
| environment: | |||||
| PGDATA: /var/lib/postgresql/data/pgdata | |||||
| POSTGRES_USER: vapor_username | |||||
| POSTGRES_PASSWORD: vapor_password | |||||
| POSTGRES_DB: vapor_database | |||||
| ports: | |||||
| - '5432:5432' | |||||