From eb2ba91a2106687786000e8edf8b55e3e3c965d5 Mon Sep 17 00:00:00 2001 From: Mike Carman Date: Mon, 26 Oct 2026 13:42:22 -0400 Subject: [PATCH] V2.2 --- .../UserInterfaceState.xcuserstate | Bin 73489 -> 102405 bytes .../xcdebugger/Breakpoints_v2.xcbkptlist | 146 +--- .../V2.1/FuelEntryControllerV2_1.swift | 32 +- .../V2.2/FuelEntryControllerV2_2.swift | 819 ++++++++++++++++++ Sources/App/DTO/V2.2/v2.2.swift | 71 ++ Sources/App/Migrations/CreateFuelEntry.swift | 14 + Sources/App/Models/FuelEntry.swift | 109 ++- Sources/App/configure.swift | 1 + 8 files changed, 1010 insertions(+), 182 deletions(-) diff --git a/.swiftpm/xcode/package.xcworkspace/xcuserdata/mcarman.xcuserdatad/UserInterfaceState.xcuserstate b/.swiftpm/xcode/package.xcworkspace/xcuserdata/mcarman.xcuserdatad/UserInterfaceState.xcuserstate index 45ce814aa44fb804bac9fd0de653d70dfb621150..49348394e5ad74d89dc492113ddd99050add9fc9 100644 GIT binary patch literal 102405 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 by)*c~|8(y3|NeXY-2eCA|NrlhV|x4_M(Q8; literal 73489 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 a$OtlntYBkMv~b6ShcCGDl?DHAaOgj^xZo}T diff --git a/.swiftpm/xcode/xcuserdata/mcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/.swiftpm/xcode/xcuserdata/mcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist index 1d67c13..bcd2102 100644 --- a/.swiftpm/xcode/xcuserdata/mcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +++ b/.swiftpm/xcode/xcuserdata/mcarman.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist @@ -8,15 +8,15 @@ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> @@ -24,15 +24,15 @@ BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint"> @@ -46,9 +46,9 @@ filePath = "Sources/App/Models/FuelEntry.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "200" - endingLineNumber = "200" - landmarkName = "init(id:timestamp:userID:latitude:longitude:image:product:make:model:serialNumber:tankID:fuelAmount:fuelType:isOverride:downloaded:tabletserial:)" + startingLineNumber = "203" + endingLineNumber = "203" + landmarkName = "init(id:timestamp:userID:latitude:longitude:image:product:make:model:serialNumber:tankID:fuelAmount:fuelType:isOverride:downloaded:tabletserial:uniqueID:)" landmarkType = "7"> @@ -174,8 +174,8 @@ filePath = "Sources/App/Models/FuelEntry.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "285" - endingLineNumber = "285" + startingLineNumber = "291" + endingLineNumber = "291" landmarkName = "init(from:)" landmarkType = "7"> @@ -222,76 +222,12 @@ filePath = "Sources/App/Models/FuelEntry.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "291" - endingLineNumber = "291" + startingLineNumber = "297" + endingLineNumber = "297" landmarkName = "init(from:)" landmarkType = "7"> - - - - - - - - - - - - - - - - @@ -318,54 +254,10 @@ filePath = "Sources/App/Controllers/V2.1/FuelEntryControllerV2_1.swift" startingColumnNumber = "9223372036854775807" endingColumnNumber = "9223372036854775807" - startingLineNumber = "670" - endingLineNumber = "670" + startingLineNumber = "674" + endingLineNumber = "674" landmarkName = "create(req:)" landmarkType = "7"> - - - - - - - - diff --git a/Sources/App/Controllers/V2.1/FuelEntryControllerV2_1.swift b/Sources/App/Controllers/V2.1/FuelEntryControllerV2_1.swift index 36ba6ae..67d0ed5 100644 --- a/Sources/App/Controllers/V2.1/FuelEntryControllerV2_1.swift +++ b/Sources/App/Controllers/V2.1/FuelEntryControllerV2_1.swift @@ -649,21 +649,25 @@ struct FuelEntryV2ControllerV2_1: RouteCollection { var results: [FuelEntry] = [] for entry in fuelEntry { let input = try FuelEntry.init(from: entry) - let data = entry.image ?? nil - let length = data?.count - if(data == nil || length == 0){ - input.image = nil - } - if(entry.id != nil){ - if (try await FuelEntry.find(entry.id!, on: req.db)) != nil { - input._$id.exists = true - } else { - input._$idExists = false + + + + let data = entry.image ?? nil + let length = data?.count + if(data == nil || length == 0){ + input.image = nil } - - } - try await input.save(on: req.db) - results.append(input) + if(entry.id != nil){ + if (try await FuelEntry.find(entry.id!, on: req.db)) != nil { + input._$id.exists = true + } else { + input._$idExists = false + } + + } + try await input.save(on: req.db) + results.append(input) + } // try await fuelEntry.create(on: req.db) diff --git a/Sources/App/Controllers/V2.2/FuelEntryControllerV2_2.swift b/Sources/App/Controllers/V2.2/FuelEntryControllerV2_2.swift index e69de29..9c8569c 100644 --- a/Sources/App/Controllers/V2.2/FuelEntryControllerV2_2.swift +++ b/Sources/App/Controllers/V2.2/FuelEntryControllerV2_2.swift @@ -0,0 +1,819 @@ +// +// FuelEntryControllerV2_2.swift +// Fueling +// +// Created by Michiel Carman on 10/26/26. +// + +// +// FuelEntryControllerV2_1.swift +// Fueling +// +// Created by Michiel Carman on 9/15/26. +// + +import Vapor +import FluentKit +import FluentSQL + +struct FuelEntryV2ControllerV2_2: 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) + } + + } + @Sendable + func index(req: Request) async throws -> Response { + return try await FuelEntry.query(on: req.db).all().map{ + try FuelEntry.V2_1_Output.init(from: $0) + }.encodeResponse(for: req) + } + + 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 -> returnObjV2_1 { + 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.V2_1_Output] = [] + let meta = Meta(page: 0, per: 0, total: 0, lastpage: true, error: true, message: message, method: method, baseurl: baseurl, route: rt, querystring: "" ) + return returnObjV2_1(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 = try req.query.decode(Dictionary.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{ + try FuelEntry.V2_1_Output.init(from: $0) + } + let response = returnObjV2_1(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 = try req.query.decode(Dictionary.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{ + try FuelEntry.V2_1_Output.init(from: $0) + } + let response = returnObjV2_1(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 = try req.query.decode(Dictionary.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{ + try FuelEntry.V2_1_Output.init(from: $0) + } + let response = returnObjV2_1(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 -> Response { + let fuelEntry = try req.content.decode([FuelEntry.V2_2_Input].self) + var results: [FuelEntry] = [] + for entry in fuelEntry { + let input = FuelEntry.init(from: entry) + let exists = try await FuelEntry.query(on: req.db).filter(\.$uniqueID, .equal, input.uniqueID).first() + if(exists == nil) { + let data = entry.image ?? nil + let length = data?.count + if(data == nil || length == 0){ + input.image = nil + } + if(entry.id != nil){ + if (try await FuelEntry.find(entry.id!, on: req.db)) != nil { + input._$id.exists = true + } else { + input._$idExists = false + } + + } + try await input.save(on: req.db) + results.append(input) + } else { + results.append(exists!) + } + + + + } + +// try await fuelEntry.create(on: req.db) + let response = try await results.map{ + try FuelEntry.V2_1_Output.init(from: $0) + }.encodeResponse(for: req) + return response + } + + + + 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 +// } +//} + + + + + + + + + + diff --git a/Sources/App/DTO/V2.2/v2.2.swift b/Sources/App/DTO/V2.2/v2.2.swift index e69de29..e86c155 100644 --- a/Sources/App/DTO/V2.2/v2.2.swift +++ b/Sources/App/DTO/V2.2/v2.2.swift @@ -0,0 +1,71 @@ +// +// v2.2.swift +// Fueling +// +// Created by Michiel Carman on 10/26/26. +// + +import Vapor + +extension FuelEntry { + struct V2_2_Input: Content { + var id: UUID? + var tabletSerial: String? + var fuelAmount: Double? + var fuelType: String? + var timeStamp: Date? + var appVersion: String? + var longitude: Double? + var product: String? + var latitude: Double? + var serialNumber: String? + var isOverride: Bool? + var make: String? + var model: String? + var tankId: String? + var image: Data? + var userId: String? + var uniqueID: String? + } + + struct V2_2_Output: Content { + var id: UUID? + var tabletSerial: String? + var fuelAmount: Double? + var fuelType: String? + var timeStamp: Date? + var appVersion: String? + var longitude: Double? + var product: String? + var latitude: Double? + var serialNumber: String? + var isOverride: Bool? + var make: String? + var model: String? + var tankId: String? + var image: Data? + var uniqueID: String? + init(from decoder: FuelEntry, img: Bool = false) throws { + self.id = decoder.id + self.tabletSerial = decoder.tabletserial + self.fuelAmount = decoder.fuelAmount + self.fuelType = decoder.fuelType + self.timeStamp = decoder.timestamp + self.appVersion = decoder.appVersion + self.longitude = decoder.longitude + self.product = decoder.product + self.latitude = decoder.latitude + self.serialNumber = decoder.serialNumber + self.isOverride = decoder.isOverride + self.make = decoder.make + self.model = decoder.model + self.tankId = decoder.tankID + if img { + self.image = decoder.image + } + self.uniqueID = decoder.uniqueID?.uuidString + } + } + +} + diff --git a/Sources/App/Migrations/CreateFuelEntry.swift b/Sources/App/Migrations/CreateFuelEntry.swift index a579dfa..0c9181e 100755 --- a/Sources/App/Migrations/CreateFuelEntry.swift +++ b/Sources/App/Migrations/CreateFuelEntry.swift @@ -96,6 +96,20 @@ struct AddDownloadedBool: AsyncMigration { } } +struct AddUniqueIDFiled: AsyncMigration { + func prepare(on database: Database) async throws { + try await database.schema("fuel_entries") + .field("unique_id", .uuid) + .update() + } + + func revert(on database: Database) async throws { + try await database.schema("fuel_entries") + .deleteField("unique_id") + .update() + } +} + struct AddAppVersion: AsyncMigration { func prepare(on database: Database) async throws { try await database.schema("fuel_entries") diff --git a/Sources/App/Models/FuelEntry.swift b/Sources/App/Models/FuelEntry.swift index 108fba5..7a031ae 100755 --- a/Sources/App/Models/FuelEntry.swift +++ b/Sources/App/Models/FuelEntry.swift @@ -115,46 +115,46 @@ final class FuelEntry: Model, Content { return entry } } - + @ID(key: .id) var id: UUID? - + @Field(key: "timestamp") var timestamp: Date - + @Field(key: "user_id") var userID: String - + @Field(key: "latitude") var latitude: Double @Field(key: "longitude") var longitude: Double - + @Field(key: "image") var image: Data? - + @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 @@ -170,11 +170,13 @@ final class FuelEntry: Model, Content { @Timestamp(key: "loadDate", on: .create) var loaddate: Date? @Timestamp(key: "pullDate", on: .none) var pulldate: Date? -// var imageData: Data? - + @Field(key: "unique_id") var uniqueID: UUID? + + // var imageData: Data? + init() {} - 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, appversion: String? = nil) { //imageData: Data? + 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, appversion: String? = nil, uniqueID: UUID? = nil) { //imageData: Data? self.id = id self.timestamp = timestamp self.userID = userID @@ -193,10 +195,11 @@ final class FuelEntry: Model, Content { self.image = image ?? nil self.tabletserial = tabletserial ?? nil self.appVersion = appversion ?? nil -// self.imageData = imageData + self.uniqueID = uniqueID + // 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, downloaded: Bool? = nil, tabletserial: String? = nil) { //imageData: Data? + + 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, uniqueID: UUID? = nil) { //imageData: Data? self.id = id self.timestamp = timestamp self.userID = userID @@ -214,9 +217,10 @@ final class FuelEntry: Model, Content { self.downloaded = downloaded ?? nil self.image = image ?? nil self.tabletserial = tabletserial ?? nil -// self.imageData = imageData + self.uniqueID = uniqueID + // 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? + 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, uniqueID: UUID? = nil) { //imageData: Data? self.id = id self.timestamp = timestamp self.userID = userID @@ -234,9 +238,10 @@ final class FuelEntry: Model, Content { self.downloaded = downloaded ?? nil self.image = image ?? nil self.tabletserial = tabletserial ?? nil -// self.imageData = imageData + self.uniqueID = uniqueID + // 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? + 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, uniqueID: UUID? = nil) { //imageData: Data? self.id = id self.timestamp = timestamp self.userID = userID @@ -252,26 +257,27 @@ final class FuelEntry: Model, Content { self.fuelType = fuelType self.isOverride = isOverride self.tabletserial = tabletserial ?? nil -// self.imageData = imageData + self.uniqueID = uniqueID + // self.imageData = imageData } -// struct V2_1_Input: Content { -// var id: UUID? -// var tabletSerial: Date? -// var fuelAmount: Double? -// var fuelType: String? -// var timeStamp: Date? -// var appVersion: String? -// var longitude: String? -// var product: String? -// var latitude: String? -// var serialNumber: String? -// var isOverride: Bool? -// var make: String? -// var model: String? -// var tankId: String? -// var image: Data? -// } + // struct V2_1_Input: Content { + // var id: UUID? + // var tabletSerial: Date? + // var fuelAmount: Double? + // var fuelType: String? + // var timeStamp: Date? + // var appVersion: String? + // var longitude: String? + // var product: String? + // var latitude: String? + // var serialNumber: String? + // var isOverride: Bool? + // var make: String? + // var model: String? + // var tankId: String? + // var image: Data? + // } init(from decoder: FuelEntry.V2_1_Input) throws { self.id = decoder.id @@ -292,4 +298,25 @@ final class FuelEntry: Model, Content { self.tabletserial = decoder.tabletSerial ?? "" self.downloaded = false } + + init(from decoder: FuelEntry.V2_2_Input) { + self.id = decoder.id + self.timestamp = decoder.timeStamp ?? Date() + self.fuelAmount = decoder.fuelAmount ?? 0 + self.fuelType = decoder.fuelType ?? "" + self.appVersion = decoder.appVersion ?? "" + self.longitude = decoder.longitude ?? 0 + self.product = decoder.product ?? "" + self.latitude = decoder.latitude ?? 0 + self.serialNumber = decoder.serialNumber ?? "" + self.isOverride = decoder.isOverride ?? false + self.make = decoder.make ?? "" + self.model = decoder.model ?? "" + self.tankID = decoder.tankId ?? "" + self.userID = decoder.userId ?? "" + self.image = decoder.image + self.tabletserial = decoder.tabletSerial ?? "" + self.downloaded = false + self.uniqueID = decoder.uniqueID == nil ? nil : UUID(uuidString: decoder.uniqueID!) + } } diff --git a/Sources/App/configure.swift b/Sources/App/configure.swift index 92901ff..ce8affc 100755 --- a/Sources/App/configure.swift +++ b/Sources/App/configure.swift @@ -52,6 +52,7 @@ public func configure(_ app: Application) async throws { app.migrations.add(AddLoadDateAndPullDate()) app.migrations.add(AddDeviceSerial()) app.migrations.add(AddAppVersion()) + app.migrations.add(AddUniqueIDFiled()) try await app.autoMigrate().get() // register routes