| @@ -0,0 +1,152 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <Bucket | |||
| uuid = "83CCDCAB-5627-45C3-BC68-1A59A1D654E0" | |||
| type = "1" | |||
| version = "2.0"> | |||
| <Breakpoints> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "1165C094-7F83-4580-9E1E-36ACC4A42F04" | |||
| shouldBeEnabled = "Yes" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Models/FuelEntry.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "215" | |||
| endingLineNumber = "215" | |||
| landmarkName = "init(id:timestamp:userID:latitude:longitude:product:make:model:serialNumber:tankID:fuelAmount:fuelType:isOverride:tabletserial:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "F812306B-8399-447C-84BE-4AC7A776D420" | |||
| shouldBeEnabled = "Yes" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Models/FuelEntry.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "195" | |||
| endingLineNumber = "195" | |||
| landmarkName = "init(id:timestamp:userID:latitude:longitude:image:product:make:model:serialNumber:tankID:fuelAmount:fuelType:isOverride:tabletserial:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "71BCB6D1-5BA1-44A4-B4BB-3CF6616E1B45" | |||
| shouldBeEnabled = "Yes" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Models/FuelEntry.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "175" | |||
| endingLineNumber = "175" | |||
| landmarkName = "init(id:timestamp:userID:latitude:longitude:image:product:make:model:serialNumber:tankID:fuelAmount:fuelType:isOverride:downloaded:tabletserial:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "D9ECF7FA-C31F-4E3E-A5E0-09B15672960B" | |||
| shouldBeEnabled = "No" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/FuelEntryV2Controller.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "469" | |||
| endingLineNumber = "469" | |||
| landmarkName = "filtered(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "FCC6E6E2-0876-4286-93D8-266C58EAE0FE" | |||
| shouldBeEnabled = "No" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/FuelEntryV2Controller.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "491" | |||
| endingLineNumber = "491" | |||
| landmarkName = "filtered(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "0BD134C2-3EF8-4F87-A31F-13B3E66DE82C" | |||
| shouldBeEnabled = "No" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/FuelEntryV2Controller.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "511" | |||
| endingLineNumber = "511" | |||
| landmarkName = "filtered(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "44A1C379-F3B1-438B-9427-C87E053877C5" | |||
| shouldBeEnabled = "No" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/FuelEntryV2Controller.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "529" | |||
| endingLineNumber = "529" | |||
| landmarkName = "filtered(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "9959EDC1-617C-4BD3-A47D-FA6774BA18A9" | |||
| shouldBeEnabled = "Yes" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/FuelEntryV2Controller.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "547" | |||
| endingLineNumber = "547" | |||
| landmarkName = "filtered(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "C4228ECF-D80C-49F9-BBD8-A33956D74C07" | |||
| shouldBeEnabled = "Yes" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/FuelEntryV2Controller.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "291" | |||
| endingLineNumber = "291" | |||
| landmarkName = "filterLoadDate(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| </Breakpoints> | |||
| </Bucket> | |||
| @@ -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,24 @@ | |||
| <?xml version="1.0" encoding="UTF-8"?> | |||
| <Bucket | |||
| uuid = "D3C706B5-9CBD-4F91-8A68-CF08562866B5" | |||
| type = "1" | |||
| version = "2.0"> | |||
| <Breakpoints> | |||
| <BreakpointProxy | |||
| BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> | |||
| <BreakpointContent | |||
| uuid = "65DB5B80-779D-462A-A47F-A0A75B1C75F8" | |||
| shouldBeEnabled = "Yes" | |||
| ignoreCount = "0" | |||
| continueAfterRunningActions = "No" | |||
| filePath = "Sources/App/Controllers/UserController.swift" | |||
| startingColumnNumber = "9223372036854775807" | |||
| endingColumnNumber = "9223372036854775807" | |||
| startingLineNumber = "35" | |||
| endingLineNumber = "35" | |||
| landmarkName = "create(req:)" | |||
| landmarkType = "7"> | |||
| </BreakpointContent> | |||
| </BreakpointProxy> | |||
| </Breakpoints> | |||
| </Bucket> | |||
| @@ -1,6 +1,6 @@ | |||
| // | |||
| // FuelEntryController.swift | |||
| // | |||
| // | |||
| // | |||
| // Created by Bill Ryckman on 4/24/23. | |||
| // | |||
| @@ -20,13 +20,13 @@ struct FuelEntryController: RouteCollection { | |||
| 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.create(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) | |||
| @@ -39,3 +39,4 @@ struct FuelEntryController: RouteCollection { | |||
| @@ -0,0 +1,797 @@ | |||
| // | |||
| // FuelEntryController.swift | |||
| // | |||
| // | |||
| // Created by Bill Ryckman on 4/24/23. | |||
| // | |||
| import Vapor | |||
| import FluentKit | |||
| import FluentSQL | |||
| struct FuelEntryV2Controller: RouteCollection { | |||
| func boot(routes: RoutesBuilder) throws { | |||
| let fuelEntries = routes.grouped("fuel_entries") | |||
| let tokenAuthMiddleware = Token.authenticator() | |||
| let guardMiddleware = User.guardMiddleware() | |||
| let tokenAuthGroup = fuelEntries.grouped(tokenAuthMiddleware, guardMiddleware) | |||
| tokenAuthGroup.get(use: filterLoadDate) | |||
| tokenAuthGroup.get("main", use: filterLoadDate) | |||
| tokenAuthGroup.get("timestamp", use: filterTimeStamp) | |||
| tokenAuthGroup.get("images", use: filterImages) | |||
| tokenAuthGroup.get("test", use: filtered) | |||
| tokenAuthGroup.get("rpm", use: rpm) | |||
| tokenAuthGroup.get("maxim", use: filtered) | |||
| tokenAuthGroup.post(use: create) | |||
| tokenAuthGroup.put( use: softdelete) | |||
| tokenAuthGroup.group(":fuelEntryID") { fuelEntry in | |||
| fuelEntry.delete(use: delete) | |||
| } | |||
| } | |||
| func index(req: Request) async throws -> [FuelEntry] { | |||
| return try await FuelEntry.query(on: req.db).all() | |||
| } | |||
| struct filteredreturn: Content{ | |||
| var fuelentries: [FuelEntry] | |||
| var pages: Int | |||
| } | |||
| struct dload: Content{ | |||
| var id: UUID | |||
| } | |||
| @Sendable | |||
| func softdelete(req: Request) async throws -> Response { | |||
| let ids = try req.content.decode([dload].self) | |||
| var msg: [String] = [] | |||
| for id in ids { | |||
| guard let fe = try await FuelEntry.find(id.id, on: req.db) else { | |||
| msg.append("create error message for item") | |||
| continue | |||
| } | |||
| fe.downloaded = true | |||
| try await fe.save(on: req.db) | |||
| } | |||
| let response = Response(status: .ok, body: "good") | |||
| return response | |||
| } | |||
| fileprivate func queryParamExists(_ req: Request, _ param: String) async throws -> Bool { | |||
| let x = try req.query.get(Bool.self, at: param) ? true : false | |||
| print ("x: \(x)") | |||
| return x | |||
| } | |||
| fileprivate func parseDate2(_ dateString: String, _ start: Bool = true) throws -> Date? { | |||
| let currentDate = Calendar.current.startOfDay(for: Date()) | |||
| if(dateString.count == 0 && start){ | |||
| if(start) { | |||
| return Calendar.current.date(byAdding: .day, value: -2, to: currentDate) | |||
| } else { | |||
| return currentDate | |||
| } | |||
| } else { | |||
| let parts = dateString.split(separator: "-") | |||
| if(parts.count != 3) { | |||
| return nil | |||
| } | |||
| let year = Int(parts[0]) ?? nil | |||
| if(year == nil) { | |||
| return nil | |||
| } | |||
| let month = Int(parts[1]) ?? nil | |||
| if(month == nil) { | |||
| return nil | |||
| } | |||
| let day = Int(parts[2]) ?? nil | |||
| if( day == nil ) { | |||
| return nil | |||
| } | |||
| var dateComponents = DateComponents() | |||
| dateComponents.year = year | |||
| dateComponents.month = month | |||
| dateComponents.day = day | |||
| if(start) { | |||
| dateComponents.hour = 0 | |||
| dateComponents.minute = 0 | |||
| dateComponents.second = 0 | |||
| } else { | |||
| dateComponents.hour = 23 | |||
| dateComponents.minute = 59 | |||
| dateComponents.second = 59 | |||
| } | |||
| let calendar = Calendar(identifier: .gregorian) | |||
| return calendar.date(from: dateComponents) | |||
| } | |||
| } | |||
| fileprivate func parseDate(_ dateString: String, _ start: Bool = true) throws -> Date? { | |||
| if(dateString.count == 0){ | |||
| return nil | |||
| } else { | |||
| let parts = dateString.split(separator: "-") | |||
| if(parts.count != 3) { | |||
| throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted.")) | |||
| } | |||
| let year = Int(parts[0]) ?? nil | |||
| if(year == nil) { | |||
| throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted. Year component must be in the format yyyy and must be an integer")) | |||
| } | |||
| let month = Int(parts[1]) ?? nil | |||
| if(month == nil) { | |||
| throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted. Month component must be in the format MM and must be an integer")) | |||
| } | |||
| let day = Int(parts[2]) ?? nil | |||
| if( day == nil ) { | |||
| throw Abort(.custom(code: 400,reasonPhrase: "Value at path '\(start ? "startdate" : "enddate")' was not of format 'yyyy-MM-dd'. Data found at '\(start ? "startdate" : "enddate")' was not properly formatted. Day component must be in the format dd and must be an integer")) | |||
| } | |||
| var dateComponents = DateComponents() | |||
| dateComponents.year = year | |||
| dateComponents.month = month | |||
| dateComponents.day = day | |||
| if(start) { | |||
| dateComponents.hour = 0 | |||
| dateComponents.minute = 0 | |||
| dateComponents.second = 0 | |||
| } else { | |||
| dateComponents.hour = 23 | |||
| dateComponents.minute = 59 | |||
| dateComponents.second = 59 | |||
| } | |||
| let calendar = Calendar(identifier: .gregorian) | |||
| return calendar.date(from: dateComponents) | |||
| } | |||
| } | |||
| fileprivate func generateSQLNoImage(_ startdate: Date? = nil, _ enddate: Date? = nil) -> SQLQueryString { | |||
| if(startdate == nil) { | |||
| return SQLQueryString("select count(*) as total from \"fuel_entries\";") | |||
| } | |||
| if(enddate != nil) { | |||
| return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(bind: startdate) and \"loadDate\" <= \(bind: enddate) ;") | |||
| } else { | |||
| return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(bind: startdate);") | |||
| } | |||
| } | |||
| fileprivate func generateSQLImage(_ startdate: Date? = nil, _ enddate: Date? = nil) -> SQLQueryString { | |||
| var sql: String = "" | |||
| if(startdate == nil) { | |||
| return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"image\" is not null;") | |||
| } | |||
| if(enddate != nil) { | |||
| sql = "select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(String(describing: startdate)) and \"loadDate\" <= \(String(describing: enddate)) and \"image\" is not null;" | |||
| return SQLQueryString("select count(*) as total from \"fuel_entries\" where \"loadDate\" >= \(bind: startdate) and \"loadDate\" <= \(bind: enddate) and \"image\" is not null;") | |||
| } else { | |||
| sql = "select count(*) as total from \"fuel_entries\" where \"image\" is not null and \"loadDate\" >= '\(startdate ?? Date())';" | |||
| return SQLQueryString(sql) | |||
| } | |||
| } | |||
| struct CountRecords: Content { | |||
| let total: Int | |||
| } | |||
| fileprivate func getCount(_ req: Request, _ sql: SQLQueryString) async throws -> Int { | |||
| print(sql) | |||
| if let db = req.db as? SQLDatabase { | |||
| let answer = try await db | |||
| .raw(sql) | |||
| .first(decoding: CountRecords.self) | |||
| return answer?.total ?? 0 | |||
| } else { | |||
| return 0 | |||
| } | |||
| } | |||
| fileprivate func getPaging(_ page: Int, _ per: Int, _ records: Int) async throws -> [String: Any] { | |||
| var vals: [String: Any] = [:] | |||
| vals["page"] = page | |||
| vals["per"] = per | |||
| vals["records"] = records | |||
| let lastpage = Int(ceil(Double(records) / Double(per))) | |||
| vals["lastpage"] = (page == lastpage) ? true : false | |||
| vals["offset"] = ( page * per) - per | |||
| return vals | |||
| } | |||
| fileprivate func getParams(_ req: Request) async throws -> [qparam] { | |||
| let urlComponents = URLComponents(string: req.url.description)! | |||
| var params: [qparam] = [] | |||
| for queryItem in urlComponents.queryItems ?? [] { | |||
| params.append(qparam(name: queryItem.name, value: queryItem.value ?? "")) | |||
| } | |||
| return params | |||
| } | |||
| fileprivate func getMaximError(_ req: Request, _ message: String) async throws -> returnObj { | |||
| let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") | |||
| let method = req.method.rawValue | |||
| let baseurl = "https://fueling.prelub.com" | |||
| let data : [FuelEntry.Output] = [] | |||
| let meta = Meta(page: 0, per: 0, total: 0, lastpage: true, error: true, message: message, method: method, baseurl: baseurl, route: rt, querystring: "" ) | |||
| return returnObj(data: data, meta: meta) | |||
| } | |||
| @Sendable | |||
| func filterLoadDate(req: Request) async throws -> Response { | |||
| let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") | |||
| let method = req.method.rawValue | |||
| let baseurl = "https://fueling.prelub.com" | |||
| let qstring = req.query | |||
| let components: Dictionary<String, String?> = try req.query.decode(Dictionary<String, String?>.self) | |||
| var startdate : Date? | |||
| var qs: [String] = [] | |||
| for component in components { | |||
| qs.append( "\(component.key)=\(component.value ?? "nil")") | |||
| } | |||
| if(try qstring.get(String?.self, at: "startdate") != nil) { | |||
| startdate = try parseDate2(qstring.get(String?.self, at: "startdate") ?? "") | |||
| if(startdate == nil) { | |||
| return try await(getMaximError(req, "startdate is invalid format. YYYY-MM-DD")) .encodeResponse(for: req) | |||
| } | |||
| } else { | |||
| //throw error | |||
| return try await getMaximError(req, "startdate is required").encodeResponse(for: req) | |||
| } | |||
| var enddate : Date?//= try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| if(try qstring.get(String?.self, at: "enddate") != nil) { | |||
| enddate = try parseDate2(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| if(enddate == nil) { | |||
| return try await getMaximError(req, "enddate is invalid format. YYYY-MM-DD").encodeResponse(for: req) | |||
| } | |||
| } | |||
| let emptyData: Data? = Data() | |||
| let page = try qstring.get(Int?.self, at: "page") ?? 1 | |||
| let per = try qstring.get(Int?.self, at: "per") ?? 10 | |||
| let qsStr = qs.joined(separator: "&") | |||
| let records = try await getCount(req, generateSQLNoImage(startdate ?? nil, enddate ?? nil) ) | |||
| let paging = try await getPaging(page, per, records) | |||
| let meta = Meta(page: page, per: per, total: records, lastpage: (paging["lastpage"] != nil) ? paging["lastpage"] as! Bool : false, error: false, message: "", method: method, baseurl: baseurl, route: rt, querystring: "?\(qsStr)") | |||
| let query = try await FuelEntry.query(on: req.db) | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| .field(\.$tabletserial) | |||
| .group(.and) { | |||
| grp in | |||
| grp.filter(\.$loaddate >= startdate) | |||
| if( enddate != nil) { | |||
| grp.filter(\.$loaddate <= enddate!) | |||
| } | |||
| } | |||
| .sort(\.$loaddate, .ascending) | |||
| .range(lower: (paging["offset"] as! Int), upper: (paging["offset"] as! Int) + (paging["per"] as! Int)) | |||
| .all().map{ | |||
| FuelEntry.Output(id: $0.id, timestamp: $0.timestamp, ssid: $0.userID, latitude: $0.latitude, longitude: $0.longitude, product: $0.product, make: $0.make, model: $0.model, serialNumber: $0.serialNumber, tankID: $0.tankID, fuelAmount: $0.fuelAmount, fuelType: $0.fuelType, isOverride: $0.isOverride, image: emptyData, loaddate: $0.loaddate, useremail: $0.tabletserial ?? "") | |||
| } | |||
| let response = returnObj(data: query, meta: meta) | |||
| return try await response.encodeResponse(for: req) | |||
| } | |||
| @Sendable | |||
| func filterImages(req: Request) async throws -> Response { | |||
| let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") | |||
| let method = req.method.rawValue | |||
| let baseurl = "https://fueling.prelub.com" | |||
| let qstring = req.query | |||
| let components: Dictionary<String, String?> = try req.query.decode(Dictionary<String, String?>.self) | |||
| var startdate : Date? | |||
| var qs: [String] = [] | |||
| for component in components { | |||
| qs.append( "\(component.key)=\(component.value ?? "nil")") | |||
| } | |||
| if(try qstring.get(String?.self, at: "startdate") != nil) { | |||
| startdate = try parseDate2(qstring.get(String?.self, at: "startdate") ?? "") | |||
| if(startdate == nil) { | |||
| return try await(getMaximError(req, "startdate is invalid format. YYYY-MM-DD")) .encodeResponse(for: req) | |||
| } | |||
| } else { | |||
| //throw error | |||
| return try await getMaximError(req, "startdate is required").encodeResponse(for: req) | |||
| } | |||
| var enddate : Date?//= try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| if(try qstring.get(String?.self, at: "enddate") != nil) { | |||
| enddate = try parseDate2(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| if(enddate == nil) { | |||
| return try await getMaximError(req, "enddate is invalid format. YYYY-MM-DD").encodeResponse(for: req) | |||
| } | |||
| } | |||
| let page = try qstring.get(Int?.self, at: "page") ?? 1 | |||
| let per = try qstring.get(Int?.self, at: "per") ?? 5 | |||
| var records : Int = 0 | |||
| if(enddate == nil) { | |||
| records = try await FuelEntry.query(on: req.db) | |||
| .field(\.$id) | |||
| .group(.and) { | |||
| grp in | |||
| grp.filter(\.$loaddate >= startdate) | |||
| .filter(\.$image != nil) | |||
| } | |||
| .all() | |||
| .count | |||
| } else { | |||
| records = try await FuelEntry.query(on: req.db) | |||
| .field(\.$id) | |||
| .group(.and) { | |||
| grp in | |||
| grp.filter(\.$loaddate >= startdate) | |||
| .filter(\.$image != nil) | |||
| .filter(\.$loaddate <= enddate) | |||
| } | |||
| .all() | |||
| .count | |||
| } | |||
| let qsStr = qs.joined(separator: "&") | |||
| let paging = try await getPaging(page, per, records) | |||
| let meta = Meta(page: page, per: per, total: records, lastpage: (paging["lastpage"] != nil) ? paging["lastpage"] as! Bool : false, error: false, message: "", method: method, baseurl: baseurl, route: rt, querystring: "?\(qsStr)") | |||
| let query = try await FuelEntry.query(on: req.db) | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| .field(\.$image) | |||
| .field(\.$tabletserial) | |||
| .group(.and) { | |||
| grp in if(enddate != nil) { | |||
| grp.filter(\.$loaddate >= startdate) | |||
| .filter(\.$image != nil) | |||
| .filter(\.$loaddate <= enddate!) | |||
| } else { | |||
| grp.filter(\.$loaddate >= startdate) | |||
| .filter(\.$image != nil) | |||
| } | |||
| } | |||
| .sort(\.$loaddate, .ascending) | |||
| .range(lower: (paging["offset"] as! Int), upper: (paging["offset"] as! Int) + (paging["per"] as! Int)) | |||
| .all().map{ | |||
| FuelEntry.Output(id: $0.id, timestamp: $0.timestamp, ssid: $0.userID, latitude: $0.latitude, longitude: $0.longitude, product: $0.product, make: $0.make, model: $0.model, serialNumber: $0.serialNumber, tankID: $0.tankID, fuelAmount: $0.fuelAmount, fuelType: $0.fuelType, isOverride: $0.isOverride, image: $0.image, loaddate: $0.loaddate, useremail: $0.tabletserial ?? "") | |||
| } | |||
| let response = returnObj(data: query, meta: meta) | |||
| return try await response.encodeResponse(for: req) | |||
| } | |||
| @Sendable | |||
| func filterTimeStamp(req: Request) async throws -> Response { | |||
| let rt = req.route!.description.replacingOccurrences(of: "GET ", with: "").replacingOccurrences(of: "PUT ", with: "").replacingOccurrences(of: "POST ", with: "").replacingOccurrences(of: "DELETE ", with: "") | |||
| let method = req.method.rawValue | |||
| let baseurl = "https://fueling.prelub.com" | |||
| let qstring = req.query | |||
| let components: Dictionary<String, String?> = try req.query.decode(Dictionary<String, String?>.self) | |||
| var startdate : Date? | |||
| var qs: [String] = [] | |||
| for component in components { | |||
| qs.append( "\(component.key)=\(component.value ?? "nil")") | |||
| } | |||
| if(try qstring.get(String?.self, at: "startdate") != nil) { | |||
| startdate = try parseDate2(qstring.get(String?.self, at: "startdate") ?? "") | |||
| if(startdate == nil) { | |||
| return try await(getMaximError(req, "startdate is invalid format. YYYY-MM-DD")) .encodeResponse(for: req) | |||
| } | |||
| } else { | |||
| //throw error | |||
| return try await getMaximError(req, "startdate is required").encodeResponse(for: req) | |||
| } | |||
| var enddate : Date?//= try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| if(try qstring.get(String?.self, at: "enddate") != nil) { | |||
| enddate = try parseDate2(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| if(enddate == nil) { | |||
| return try await getMaximError(req, "enddate is invalid format. YYYY-MM-DD").encodeResponse(for: req) | |||
| } | |||
| } | |||
| let emptyData: Data? = Data() | |||
| let page = try qstring.get(Int?.self, at: "page") ?? 1 | |||
| let per = try qstring.get(Int?.self, at: "per") ?? 10 | |||
| let records = try await getCount(req, generateSQLNoImage(startdate ?? nil, enddate ?? nil) ) | |||
| let paging = try await getPaging(page, per, records) | |||
| let meta = Meta(page: page, per: per, total: records, lastpage: (paging["lastpage"] != nil) ? paging["lastpage"] as! Bool : false, error: false, message: "", method: method, baseurl: baseurl, route: rt, querystring: "?\(qs.joined(separator: "&"))") | |||
| let query = try await FuelEntry.query(on: req.db) | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| .field(\.$tabletserial) | |||
| .group(.and) { | |||
| grp in | |||
| grp.filter(\.$timestamp >= startdate ?? Calendar.current.startOfDay(for: Calendar.current.date(byAdding: .day, value: -2, to: Date())!)) | |||
| if( enddate != nil) { | |||
| grp.filter(\.$timestamp <= enddate!) | |||
| } | |||
| } | |||
| .sort(\.$loaddate, .ascending) | |||
| .range(lower: (paging["offset"] as! Int), upper: (paging["offset"] as! Int) + (paging["per"] as! Int)) | |||
| .all().map{ | |||
| FuelEntry.Output(id: $0.id, timestamp: $0.timestamp, ssid: $0.userID, latitude: $0.latitude, longitude: $0.longitude, product: $0.product, make: $0.make, model: $0.model, serialNumber: $0.serialNumber, tankID: $0.tankID, fuelAmount: $0.fuelAmount, fuelType: $0.fuelType, isOverride: $0.isOverride, image: emptyData, loaddate: $0.loaddate, useremail: $0.tabletserial ?? "") | |||
| } | |||
| let response = returnObj(data: query, meta: meta) | |||
| return try await response.encodeResponse(for: req) | |||
| } | |||
| @Sendable | |||
| func filtered(req: Request) async throws -> Response { | |||
| let qstring = req.query | |||
| let startdate = try parseDate(qstring.get(String?.self, at: "startdate") ?? "") | |||
| let enddate = try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| let image = try qstring.get(Bool?.self, at: "image") ?? false | |||
| let serial = try qstring.get(String?.self, at: "serial") ?? nil | |||
| let tank = try qstring.get(String?.self, at: "tank") ?? nil | |||
| let previous = try qstring.get(Bool?.self, at: "previous") ?? false | |||
| var query = FuelEntry.query(on: req.db) | |||
| if(image){ | |||
| query = query | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$image) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| .field(\.$tabletserial) | |||
| //.filter(\.$image != nil) | |||
| } else { | |||
| query = query | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$downloaded) | |||
| .field(\.$tabletserial) | |||
| .field(\.$loaddate) | |||
| } | |||
| query = query.group(.and){ | |||
| grp in | |||
| if( startdate != nil) { | |||
| grp.filter(\.$loaddate >= startdate) | |||
| } | |||
| if( enddate != nil) { | |||
| grp.filter(\.$loaddate <= enddate!) | |||
| } | |||
| if( serial != nil) { | |||
| grp.filter(\.$serialNumber == serial!) | |||
| } | |||
| if( tank != nil) { | |||
| grp.filter(\.$tankID == tank!) | |||
| } | |||
| if(!previous){ | |||
| grp.filter(\.$pulldate == nil) | |||
| } | |||
| } | |||
| query = query.sort(\.$loaddate, .ascending) | |||
| if(image){ | |||
| //query = query.filter(\.$image) | |||
| let wimage = try await query.paginate(for: req).map{ | |||
| img in FuelEntry.wimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, isOverride: img.isOverride, image: img.image == nil ? Data(): img.image, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: previous == true ? img.pulldate : Date()) | |||
| } | |||
| if(!previous){ | |||
| wimage.items.forEach{ | |||
| _ = $0.toFuelEntry().save(on: req.db) | |||
| } | |||
| } | |||
| return try await wimage.encodeResponse(for: req) | |||
| } else { | |||
| let woimage = try await query.paginate(for: req).map{ | |||
| img in FuelEntry.woimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, image: nil, isOverride: img.isOverride, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: previous == true ? img.pulldate : Date(), useremail: img.tabletserial) | |||
| } | |||
| if(!previous) { | |||
| woimage.items.forEach { | |||
| _ = $0.toFuelEntry().save(on: req.db) | |||
| } | |||
| } | |||
| return try await woimage.encodeResponse(for: req) | |||
| } | |||
| } | |||
| @Sendable | |||
| func rpm(req: Request) async throws -> Response { | |||
| let qstring = req.query | |||
| let startdate = try parseDate(qstring.get(String?.self, at: "startdate") ?? "") | |||
| let enddate = try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| let image = try qstring.get(Bool?.self, at: "image") ?? false | |||
| let serial = try qstring.get(String?.self, at: "serial") ?? nil | |||
| let tank = try qstring.get(String?.self, at: "tank") ?? nil | |||
| let previous = try qstring.get(Bool?.self, at: "previous") ?? false | |||
| var query = FuelEntry.query(on: req.db) | |||
| if(image){ | |||
| query = query | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$image) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| } else { | |||
| query = query | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| } | |||
| query = query.group(.and){ | |||
| grp in | |||
| if( startdate != nil) { | |||
| grp.filter(\.$loaddate >= startdate!) | |||
| } | |||
| if( enddate != nil) { | |||
| grp.filter(\.$loaddate <= enddate!) | |||
| } | |||
| if( serial != nil) { | |||
| grp.filter(\.$serialNumber == serial!) | |||
| } | |||
| if( tank != nil) { | |||
| grp.filter(\.$tankID == tank!) | |||
| } | |||
| if(!previous){ | |||
| grp.filter(\.$pulldate == nil) | |||
| } | |||
| } | |||
| query = query.sort(\.$loaddate, .ascending).sort(\.$timestamp).sort(\.$serialNumber) | |||
| if(image){ | |||
| //query = query.filter(\.$image) | |||
| let wimage = try await query.paginate(for: req).map{ | |||
| img in FuelEntry.wimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, isOverride: img.isOverride, image: img.image == nil ? Data(): img.image, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date()) | |||
| } | |||
| return try await wimage.encodeResponse(for: req) | |||
| } else { | |||
| let woimage = try await query.paginate(for: req).map{ | |||
| img in FuelEntry.woimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, image: nil, isOverride: img.isOverride, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date(), useremail: img.tabletserial) | |||
| } | |||
| return try await woimage.encodeResponse(for: req) | |||
| } | |||
| } | |||
| func create(req: Request) async throws -> [FuelEntry] { | |||
| let fuelEntry = try req.content.decode([FuelEntry].self) | |||
| for entry in fuelEntry { | |||
| let data = entry.image ?? nil | |||
| let length = data?.count | |||
| if(data == nil || length == 0){ | |||
| entry.image = nil | |||
| } | |||
| if(entry.id != nil){ | |||
| let dbentry = try await FuelEntry.find(entry.id!, on: req.db) | |||
| if(dbentry != nil){ | |||
| entry._$idExists = true | |||
| } | |||
| } | |||
| entry.save(on: req.db).whenFailure({ error in | |||
| }) | |||
| } | |||
| // try await fuelEntry.create(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 | |||
| } | |||
| @Sendable | |||
| func getrpm(req: Request) async throws -> Response { | |||
| let qstring = req.query | |||
| let startdate = try parseDate(qstring.get(String?.self, at: "startdate") ?? "") | |||
| let enddate = try parseDate(qstring.get(String?.self, at: "enddate") ?? "", false) | |||
| let image = try qstring.get(Bool?.self, at: "image") ?? false | |||
| let serial = try qstring.get(String?.self, at: "serial") ?? nil | |||
| let tank = try qstring.get(String?.self, at: "tank") ?? nil | |||
| let previous = try qstring.get(Bool?.self, at: "previous") ?? false | |||
| var query = FuelEntry.query(on: req.db) | |||
| if(image){ | |||
| query = query | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$image) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| } else { | |||
| query = query | |||
| .field(\.$id) | |||
| .field(\.$timestamp) | |||
| .field(\.$userID) | |||
| .field(\.$product) | |||
| .field(\.$make) | |||
| .field(\.$model) | |||
| .field(\.$serialNumber) | |||
| .field(\.$tankID) | |||
| .field(\.$fuelAmount) | |||
| .field(\.$fuelType) | |||
| .field(\.$isOverride) | |||
| .field(\.$latitude) | |||
| .field(\.$longitude) | |||
| .field(\.$downloaded) | |||
| .field(\.$loaddate) | |||
| } | |||
| query = query.group(.and){ | |||
| grp in | |||
| if( startdate != nil) { | |||
| grp.filter(\.$loaddate >= startdate!) | |||
| } | |||
| if( enddate != nil) { | |||
| grp.filter(\.$loaddate <= enddate!) | |||
| } | |||
| if( serial != nil) { | |||
| grp.filter(\.$serialNumber == serial!) | |||
| } | |||
| if( tank != nil) { | |||
| grp.filter(\.$tankID == tank!) | |||
| } | |||
| if(!previous){ | |||
| grp.filter(\.$pulldate == nil) | |||
| } | |||
| } | |||
| query = query.sort(\.$loaddate, .ascending).sort(\.$timestamp).sort(\.$serialNumber) | |||
| if(image){ | |||
| //query = query.filter(\.$image) | |||
| let wimage = try await query.paginate(for: req).map{ | |||
| img in FuelEntry.wimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, isOverride: img.isOverride, image: img.image == nil ? Data(): img.image, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date()) | |||
| } | |||
| return try await wimage.encodeResponse(for: req) | |||
| } else { | |||
| let woimage = try await query.paginate(for: req).map{ | |||
| img in FuelEntry.woimage(id: img.id, timestamp: img.timestamp, userID: img.userID, latitude: img.latitude, longitude: img.longitude, product: img.product, make: img.make, model: img.model, serialNumber: img.serialNumber, tankID: img.tankID, fuelAmount: img.fuelAmount, fuelType: img.fuelType, image: nil, isOverride: img.isOverride, downloaded: img.downloaded == nil ? false : img.downloaded!, loaddate: img.loaddate == nil ? nil : img.loaddate, pulldate: Date(), useremail: img.tabletserial) | |||
| } | |||
| return try await woimage.encodeResponse(for: req) | |||
| } | |||
| } | |||
| } | |||
| struct custMeta: Content { | |||
| let per: Int | |||
| let page: Int | |||
| let total: Int | |||
| let status: String? | |||
| } | |||
| struct PageRequest: Content { | |||
| var page: Int | |||
| var size: Int | |||
| var status: String? | |||
| // Add any other properties needed for pagination | |||
| init(page: Int, size: Int, status: String? = nil) { | |||
| self.page = page | |||
| self.size = size | |||
| self.status = status | |||
| } | |||
| } | |||
| @@ -1,31 +0,0 @@ | |||
| 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,42 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Michiel Carman on 9/26/24. | |||
| // | |||
| import Vapor | |||
| import Fluent | |||
| struct UserSignup: Content { | |||
| let username: String | |||
| let password: String | |||
| } | |||
| struct NewSession: Content { | |||
| let token: String | |||
| let user: User.Public | |||
| } | |||
| extension UserSignup: Validatable { | |||
| static func validations(_ validations: inout Validations) { | |||
| validations.add("username", as: String.self, is: !.empty) | |||
| validations.add("password", as: String.self, is: .count(6...)) | |||
| } | |||
| } | |||
| struct UserController: RouteCollection { | |||
| func boot(routes: any RoutesBuilder) throws { | |||
| let users = routes.grouped("users") | |||
| users.post(use: create) | |||
| } | |||
| @Sendable | |||
| func create(req: Request) async throws -> Response{ | |||
| let user = try req.content.decode(User.self) | |||
| user.passwordHash = try Bcrypt.hash(user.passwordHash) | |||
| try await user.save(on: req.db) | |||
| let token = try Token.generate(for: user) | |||
| try await token.save(on: req.db) | |||
| return try await token.encodeResponse(for: req) | |||
| } | |||
| } | |||
| @@ -0,0 +1,31 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Michiel Carman on 9/26/24. | |||
| // | |||
| import Foundation | |||
| import Vapor | |||
| enum UserError { | |||
| case usernameTaken | |||
| } | |||
| extension UserError: AbortError { | |||
| var description: String { | |||
| reason | |||
| } | |||
| var status: HTTPResponseStatus { | |||
| switch self { | |||
| case .usernameTaken: return .conflict | |||
| } | |||
| } | |||
| var reason: String { | |||
| switch self { | |||
| case .usernameTaken: return "Username already taken" | |||
| } | |||
| } | |||
| } | |||
| @@ -0,0 +1,48 @@ | |||
| // | |||
| // PageHelper.swift | |||
| // Fueling | |||
| // | |||
| // Created by Michiel Carman on 5/5/25. | |||
| // | |||
| import Foundation | |||
| import Fluent | |||
| import Vapor | |||
| final class PageHelper { | |||
| // static func paginate<T: Paginate>( | |||
| // _ query: Query<T>, | |||
| // page: Int? = nil, | |||
| // perPage: Int? = nil | |||
| // ) -> EventLoopFuture<PagedCollection<T>> { | |||
| // let page = page ?? 1 | |||
| // let perPage = perPage ?? 10 | |||
| // return query | |||
| // .skip((page - 1) * perPage) | |||
| // } | |||
| } | |||
| public struct returnObj: Content{ | |||
| let data: [FuelEntry.Output] | |||
| let meta: Meta | |||
| } | |||
| public struct Meta: Content{ | |||
| let page: Int | |||
| let per: Int | |||
| let total: Int | |||
| let lastpage: Bool | |||
| let error: Bool | |||
| let message: String? | |||
| let method: String? | |||
| let baseurl: String? | |||
| let route: String? | |||
| let querystring: String? | |||
| } | |||
| public struct qparam: Content{ | |||
| let name: String | |||
| let value: String | |||
| } | |||
| @@ -1,6 +1,6 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // | |||
| // Created by Bill Ryckman on 4/26/23. | |||
| // | |||
| @@ -26,29 +26,103 @@ struct CreateFuelEntry: AsyncMigration { | |||
| .field("is_override", .bool) | |||
| .create() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries").delete() | |||
| } | |||
| } | |||
| struct AddLatitudeAndLongitudeAndRemoveGpsLocationAndImage: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .field("latitude", .double) | |||
| .field("longitude", .double) | |||
| .deleteField("gps_location") | |||
| .deleteField("image") | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("latitude") | |||
| .deleteField("longitude") | |||
| .field("gps_location", .string) | |||
| .field("image", .string) | |||
| .update() | |||
| } | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .field("latitude", .double) | |||
| .field("longitude", .double) | |||
| .deleteField("gps_location") | |||
| .deleteField("image") | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("latitude") | |||
| .deleteField("longitude") | |||
| .field("gps_location", .string) | |||
| .field("image", .string) | |||
| .update() | |||
| } | |||
| } | |||
| struct AddImageBackIn: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .field("image", .string) | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("image") | |||
| .update() | |||
| } | |||
| } | |||
| struct StoreImageDataInDatabase: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("image") | |||
| .field("image", .data) | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("image") | |||
| .field("image", .string) | |||
| .update() | |||
| } | |||
| } | |||
| struct AddDownloadedBool: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .field("downloaded", .bool) | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("downloaded") | |||
| .update() | |||
| } | |||
| } | |||
| struct AddLoadDateAndPullDate: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .field("loadDate", .datetime) | |||
| .field("pullDate", .datetime) | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("loadDate") | |||
| .deleteField("pullDate") | |||
| .update() | |||
| } | |||
| } | |||
| struct AddDeviceSerial: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .field("tablet_serial", .string) | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema("fuel_entries") | |||
| .deleteField("tablet_serial") | |||
| .update() | |||
| } | |||
| } | |||
| @@ -1,14 +0,0 @@ | |||
| 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,51 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Michiel Carman on 9/26/24. | |||
| // | |||
| import Foundation | |||
| import Vapor | |||
| import Fluent | |||
| struct CreateTokens: Migration { | |||
| func prepare(on database: Database) -> EventLoopFuture<Void> { | |||
| // 2 | |||
| database.schema(Token.schema) | |||
| // 3 | |||
| .id() | |||
| .field("user_id", .uuid, .references("user", "id")) | |||
| .field("value", .string, .required) | |||
| .unique(on: "value") | |||
| .field("source", .int, .required) | |||
| .field("created_at", .datetime, .required) | |||
| .field("expires_at", .datetime) | |||
| .create() | |||
| } | |||
| // 5 | |||
| func revert(on database: Database) -> EventLoopFuture<Void> { | |||
| database.schema(Token.schema).delete() | |||
| } | |||
| } | |||
| struct UpdateTokens1: Migration { | |||
| func prepare(on database: Database) -> EventLoopFuture<Void> { | |||
| // 2 | |||
| database.schema(Token.schema) | |||
| // 3 | |||
| .deleteField("source") | |||
| .deleteField("created_at") | |||
| .deleteField("expires_at") | |||
| .update() | |||
| } | |||
| // 5 | |||
| func revert(on database: Database) -> EventLoopFuture<Void> { | |||
| database.schema(Token.schema) | |||
| .field("source", .int, .required) | |||
| .field("created_at", .datetime, .required) | |||
| .field("expires_at", .datetime) | |||
| .update() | |||
| } | |||
| } | |||
| @@ -0,0 +1,69 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Michiel Carman on 9/26/24. | |||
| // | |||
| import Foundation | |||
| import Vapor | |||
| import Fluent | |||
| struct CreateUser: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .id() | |||
| .field("username", .string, .required) | |||
| .unique(on: "username") | |||
| .field("password_hash", .string, .required) | |||
| .field("created_at", .datetime, .required) | |||
| .field("updated_at", .datetime, .required) | |||
| .create() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema(User.schema).delete() | |||
| } | |||
| } | |||
| struct UpdateUser1: AsyncMigration{ | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .deleteField("created_at") | |||
| .deleteField("updated_at") | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .field("created_at", .datetime, .required) | |||
| .field("updated_at", .datetime, .required) | |||
| .update() | |||
| } | |||
| } | |||
| struct UpdateUser2_AddTokenfield: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .field("token", .string) | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .deleteField("token") | |||
| .update() | |||
| } | |||
| } | |||
| struct UpdateUser3_RemoveTokenfield: AsyncMigration { | |||
| func prepare(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .deleteField("token") | |||
| .update() | |||
| } | |||
| func revert(on database: Database) async throws { | |||
| try await database.schema(User.schema) | |||
| .field("token", .string) | |||
| .update() | |||
| } | |||
| } | |||
| @@ -10,6 +10,111 @@ import Vapor | |||
| final class FuelEntry: Model, Content { | |||
| static let schema = "fuel_entries" | |||
| struct woimage: Content{ | |||
| let id: UUID? | |||
| let timestamp: Date | |||
| let userID: String | |||
| let latitude: Double | |||
| let longitude: Double | |||
| let product: String | |||
| let make: String | |||
| let model: String | |||
| let serialNumber: String | |||
| let tankID: String | |||
| let fuelAmount: Double | |||
| let fuelType: String | |||
| let image: Data? | |||
| let isOverride: Bool | |||
| let downloaded: Bool? | |||
| let loaddate: Date? | |||
| let pulldate: Date? | |||
| let useremail: String? | |||
| func toFuelEntry() -> FuelEntry { | |||
| let entry = FuelEntry() | |||
| entry.id = self.id | |||
| entry.timestamp = self.timestamp | |||
| entry.userID = self.userID | |||
| entry.latitude = self.latitude | |||
| entry.longitude = self.longitude | |||
| entry.product = self.product | |||
| entry.make = self.make | |||
| entry.model = self.model | |||
| entry.serialNumber = self.serialNumber | |||
| entry.tankID = self.tankID | |||
| entry.fuelAmount = self.fuelAmount | |||
| entry.fuelType = self.fuelType | |||
| entry.isOverride = self.isOverride | |||
| entry.image = nil | |||
| entry.downloaded = self.downloaded | |||
| entry.loaddate = self.loaddate | |||
| entry.pulldate = self.pulldate | |||
| entry._$idExists = self.id == nil ? false : true | |||
| entry.tabletserial = self.useremail | |||
| return entry | |||
| } | |||
| } | |||
| struct Output: Content { | |||
| let id: UUID? | |||
| let timestamp: Date | |||
| let ssid: String | |||
| let latitude: Double | |||
| let longitude: Double | |||
| let product: String | |||
| let make: String | |||
| let model: String | |||
| let serialNumber: String | |||
| let tankID: String | |||
| let fuelAmount: Double | |||
| let fuelType: String | |||
| let isOverride: Bool | |||
| let image: Data? | |||
| let loaddate: Date? | |||
| let useremail: String? | |||
| } | |||
| struct wimage: Content{ | |||
| let id: UUID? | |||
| let timestamp: Date | |||
| let userID: String | |||
| let latitude: Double | |||
| let longitude: Double | |||
| let product: String | |||
| let make: String | |||
| let model: String | |||
| let serialNumber: String | |||
| let tankID: String | |||
| let fuelAmount: Double | |||
| let fuelType: String | |||
| let isOverride: Bool | |||
| let image: Data? | |||
| let downloaded: Bool? | |||
| let loaddate: Date? | |||
| let pulldate: Date? | |||
| func toFuelEntry() -> FuelEntry { | |||
| let entry = FuelEntry() | |||
| entry.id = self.id | |||
| entry.timestamp = self.timestamp | |||
| entry.userID = self.userID | |||
| entry.latitude = self.latitude | |||
| entry.longitude = self.longitude | |||
| entry.product = self.product | |||
| entry.make = self.make | |||
| entry.model = self.model | |||
| entry.serialNumber = self.serialNumber | |||
| entry.tankID = self.tankID | |||
| entry.fuelAmount = self.fuelAmount | |||
| entry.fuelType = self.fuelType | |||
| entry.isOverride = self.isOverride | |||
| entry.image = self.image | |||
| entry.downloaded = self.downloaded | |||
| entry.loaddate = self.loaddate | |||
| entry.pulldate = self.pulldate | |||
| entry._$idExists = self.id == nil ? false : true | |||
| return entry | |||
| } | |||
| } | |||
| @ID(key: .id) | |||
| var id: UUID? | |||
| @@ -26,8 +131,8 @@ final class FuelEntry: Model, Content { | |||
| @Field(key: "longitude") | |||
| var longitude: Double | |||
| // @Field(key: "image") | |||
| // var image: String | |||
| @Field(key: "image") | |||
| var image: Data? | |||
| @Field(key: "product") | |||
| var product: String | |||
| @@ -52,16 +157,67 @@ final class FuelEntry: Model, Content { | |||
| @Field(key: "is_override") | |||
| var isOverride: Bool | |||
| @Field(key: "downloaded") | |||
| var downloaded: Bool? | |||
| @Field(key: "tablet_serial") | |||
| var tabletserial: String? | |||
| @Timestamp(key: "loadDate", on: .create) var loaddate: Date? | |||
| @Timestamp(key: "pullDate", on: .none) var pulldate: Date? | |||
| // var imageData: Data? | |||
| init() {} | |||
| init(id: UUID? = nil, timestamp: Date, userID: String, latitude: Double, longitude: Double, product: String, make: String, model: String, serialNumber: String, tankID: String, fuelAmount: Double, fuelType: String, isOverride: Bool) { | |||
| init(id: UUID? = nil, timestamp: Date, userID: String, latitude: Double, longitude: Double, image: Data?, product: String, make: String, model: String, serialNumber: String, tankID: String, fuelAmount: Double, fuelType: String, isOverride: Bool, downloaded: Bool? = nil, tabletserial: String? = nil) { //imageData: Data? | |||
| self.id = id | |||
| self.timestamp = timestamp | |||
| self.userID = userID | |||
| self.latitude = latitude | |||
| self.longitude = longitude | |||
| self.image = image ?? nil | |||
| self.product = product | |||
| self.make = make | |||
| self.model = model | |||
| self.serialNumber = serialNumber | |||
| self.tankID = tankID | |||
| self.fuelAmount = fuelAmount | |||
| self.fuelType = fuelType | |||
| self.isOverride = isOverride | |||
| self.downloaded = downloaded ?? nil | |||
| self.image = image ?? nil | |||
| self.tabletserial = tabletserial ?? nil | |||
| // self.imageData = imageData | |||
| } | |||
| init(id: UUID? = nil, timestamp: Date, userID: String, latitude: Double, longitude: Double, image: Data?, product: String, make: String, model: String, serialNumber: String, tankID: String, fuelAmount: Double, fuelType: String, isOverride: Bool, tabletserial: String? = nil) { //imageData: Data? | |||
| self.id = id | |||
| self.timestamp = timestamp | |||
| self.userID = userID | |||
| self.latitude = latitude | |||
| self.longitude = longitude | |||
| self.image = image ?? nil | |||
| self.product = product | |||
| self.make = make | |||
| self.model = model | |||
| self.serialNumber = serialNumber | |||
| self.tankID = tankID | |||
| self.fuelAmount = fuelAmount | |||
| self.fuelType = fuelType | |||
| self.isOverride = isOverride | |||
| self.downloaded = downloaded ?? nil | |||
| self.image = image ?? nil | |||
| self.tabletserial = tabletserial ?? nil | |||
| // self.imageData = imageData | |||
| } | |||
| init(id: UUID? = nil, timestamp: Date, userID: String, latitude: Double, longitude: Double, product: String, make: String, model: String, serialNumber: String, tankID: String, fuelAmount: Double, fuelType: String, isOverride: Bool, tabletserial: String? = nil) { //imageData: Data? | |||
| self.id = id | |||
| self.timestamp = timestamp | |||
| self.userID = userID | |||
| self.latitude = latitude | |||
| self.longitude = longitude | |||
| // self.image = image | |||
| self.image = image ?? nil | |||
| self.product = product | |||
| self.make = make | |||
| self.model = model | |||
| @@ -70,5 +226,7 @@ final class FuelEntry: Model, Content { | |||
| self.fuelAmount = fuelAmount | |||
| self.fuelType = fuelType | |||
| self.isOverride = isOverride | |||
| self.tabletserial = tabletserial ?? nil | |||
| // self.imageData = imageData | |||
| } | |||
| } | |||
| @@ -1,19 +0,0 @@ | |||
| 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,50 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Michiel Carman on 9/24/24. | |||
| // | |||
| import Vapor | |||
| import Fluent | |||
| final class Token: Model, Content, @unchecked Sendable { | |||
| static let schema = "token" | |||
| @ID() | |||
| var id: UUID? | |||
| @Parent(key: "user_id") | |||
| var user: User | |||
| @Field(key: "value") | |||
| var value: String | |||
| init() {} | |||
| init(id: UUID? = nil, userId: User.IDValue, token: String) { | |||
| self.id = id | |||
| self.$user.id = userId | |||
| self.value = token | |||
| } | |||
| } | |||
| extension Token { | |||
| static func generate(for user: User) throws -> Token { | |||
| let random = [UInt8].random(count: 32).base64 | |||
| return try Token( userId: user.requireID(), token: random) | |||
| } | |||
| } | |||
| extension Token: ModelTokenAuthenticatable { | |||
| typealias User = App.User | |||
| static let valueKey = \Token.$value | |||
| static let userKey = \Token.$user | |||
| var isValid: Bool { | |||
| true | |||
| } | |||
| } | |||
| @@ -0,0 +1,63 @@ | |||
| // | |||
| // File.swift | |||
| // | |||
| // | |||
| // Created by Michiel Carman on 9/24/24. | |||
| // | |||
| import Fluent | |||
| import Vapor | |||
| final class User: Model, Content { | |||
| static let schema = "user" | |||
| final class Public: Content { | |||
| var id: UUID? | |||
| var username: String | |||
| init(id: UUID?, username: String) { | |||
| self.id = id | |||
| self.username = username | |||
| } | |||
| } | |||
| @ID() | |||
| var id: UUID? | |||
| @Field(key: "username") | |||
| var username: String | |||
| @Field(key: "password_hash") | |||
| var passwordHash: String | |||
| // @Timestamp(key: "created_at", on: .create) | |||
| // var createdAt: Date? | |||
| // | |||
| // @Timestamp(key: "updated_at", on: .update) | |||
| // var updatedAt: Date? | |||
| init() {} | |||
| init(id: UUID? = nil, username: String, passwordHash: String) { | |||
| self.id = id | |||
| self.username = username | |||
| self.passwordHash = passwordHash | |||
| } | |||
| } | |||
| extension User { | |||
| func convertToPublic() -> User.Public { | |||
| return User.Public(id: id, username: username) | |||
| } | |||
| } | |||
| extension User: ModelAuthenticatable { | |||
| static let usernameKey = \User.$username | |||
| static let passwordHashKey = \User.$passwordHash | |||
| func verify(password: String) throws -> Bool { | |||
| try Bcrypt.verify(password, created: self.passwordHash) | |||
| } | |||
| } | |||
| @@ -1,18 +1,56 @@ | |||
| import Fluent | |||
| import FluentPostgresDriver | |||
| import NIOSSL | |||
| import Vapor | |||
| // configures your application | |||
| public func configure(_ app: Application) async throws { | |||
| app.middleware.use(ErrorMiddleware.default(environment: app.environment)) | |||
| // uncomment to serve files from /Public folder | |||
| // app.middleware.use(FileMiddleware(publicDirectory: app.directory.publicDirectory)) | |||
| app.routes.defaultMaxBodySize = "1000kb" | |||
| // let timeout = HTTPClient.Configuration.Timeout(connect: .seconds(300), read: .seconds(300)) | |||
| // app.http.client.configuration.timeout = timeout | |||
| app.databases.use(.postgres(hostname: "localhost", username: "mcarman", password: "@ng31F@rm0823262", database: "fueling"), as: .psql) | |||
| app.http.server.configuration.port = 3001 | |||
| app.routes.defaultMaxBodySize = "128mb" | |||
| let timeout = HTTPClient.Configuration.Timeout(connect: .seconds(300), read: .seconds(300)) | |||
| app.http.client.configuration.timeout = timeout | |||
| // let envHost = Environment.get("DATABASE_HOST") ?? "vapor.prelub.com" | |||
| let envHost = Environment.get("DATABASE_HOST") ?? "127.0.0.1" | |||
| var envPort: Int | |||
| switch app.environment { | |||
| case .development: | |||
| envPort = 5433 | |||
| default: | |||
| envPort = 5432 | |||
| } | |||
| let envUsername = Environment.get("DATABASE_USERNAME") ?? "mcarman" | |||
| let envPassword = Environment.get("DATABASE_PASSWORD") ?? "@ng31F@rm0823262" | |||
| let envDB = Environment.get("DATABASE_NAME") ?? "fueling" | |||
| app.databases.use(DatabaseConfigurationFactory.postgres(configuration: .init( | |||
| hostname: envHost, | |||
| port: envPort, | |||
| username: envUsername, | |||
| password: envPassword, | |||
| database: envDB) | |||
| ), as: .psql) | |||
| // app.databases.use(.postgres(hostname: "127.0.0.1", port: 5432, username: "mcarman", password: "@ng31F@rm0823262", database: "fueling"), as: .psql) | |||
| app.http.server.configuration.port = 3002 | |||
| app.migrations.add(CreateFuelEntry()) | |||
| app.migrations.add(AddLatitudeAndLongitudeAndRemoveGpsLocationAndImage()) | |||
| app.migrations.add(AddImageBackIn()) | |||
| app.migrations.add(StoreImageDataInDatabase()) | |||
| app.migrations.add(AddDownloadedBool()) | |||
| app.migrations.add(CreateUser()) | |||
| app.migrations.add(CreateTokens()) | |||
| app.migrations.add(UpdateUser1()) | |||
| app.migrations.add(UpdateTokens1()) | |||
| app.migrations.add(UpdateUser2_AddTokenfield()) | |||
| app.migrations.add(UpdateUser3_RemoveTokenfield()) | |||
| app.migrations.add(AddLoadDateAndPullDate()) | |||
| app.migrations.add(AddDeviceSerial()) | |||
| try await app.autoMigrate().get() | |||
| // register routes | |||
| @@ -1,23 +1,18 @@ | |||
| //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 { | |||
| app.routes.caseInsensitive = true | |||
| app.routes.defaultMaxBodySize = "64mb"; | |||
| let v2 = app.grouped("api").grouped("v2") | |||
| try v2.register(collection: FuelEntryV2Controller()) | |||
| try v2.register(collection: UserController()) | |||
| let fuelEntryController = FuelEntryController() | |||
| app.get { | |||
| req in return "Fueling API v2" | |||
| } | |||
| app.get("fuel-entries") { req in | |||
| try await fuelEntryController.index(req: req) | |||
| } | |||
| @@ -29,6 +24,36 @@ func routes(_ app: Application) throws { | |||
| app.delete("fuel-entries", ":fuelEntryID") { req in | |||
| try await fuelEntryController.delete(req: req) | |||
| } | |||
| // V2 API routes with image upload | |||
| // let v2Routes: () = app.group("api", "v2") { v2 in | |||
| // let fuelEntryV2Controller = FuelEntryV2Controller() | |||
| // | |||
| // v2.get("fuel-entries") {req in | |||
| // try await fuelEntryV2Controller.index(req: req) | |||
| // } | |||
| // | |||
| //// v2.get("fuel-entries", "with-images") {req in | |||
| //// try await fuelEntryV2Controller.getAllEntriesWithImages(req: req) | |||
| //// } | |||
| // | |||
| // v2.post("fuel-entries") {req in | |||
| // try await fuelEntryV2Controller.create(req: req) | |||
| // } | |||
| // | |||
| //// v2.post("fuel-entries", ":id", "upload-image") { req -> FuelEntry in | |||
| //// return try await fuelEntryV2Controller.uploadImage(req: req) | |||
| //// } | |||
| // | |||
| // v2.delete("fuel-entries", ":fuelEntryID") { req in | |||
| // try await fuelEntryV2Controller.delete(req: req) | |||
| // } | |||
| // } | |||
| } | |||