public async Task <ActionResult> CollectFine(SpeedingViolation speedingViolation, [FromServices] DaprClient daprClient) { decimal fine = _fineCalculator.CalculateFine(_fineCalculatorLicenseKey, speedingViolation.ViolationInKmh); // get owner info var vehicleInfo = await _vehicleRegistrationService.GetVehicleInfo(speedingViolation.VehicleId); // log fine string fineString = fine == 0 ? "tbd by the prosecutor" : $"{fine} Euro"; _logger.LogInformation($"Sent speeding ticket to {vehicleInfo.OwnerName}. " + $"Road: {speedingViolation.RoadId}, Licensenumber: {speedingViolation.VehicleId}, " + $"Vehicle: {vehicleInfo.Brand} {vehicleInfo.Model}, " + $"Violation: {speedingViolation.ViolationInKmh} Km/h, Fine: {fineString}, " + $"On: {speedingViolation.Timestamp.ToString("dd-MM-yyyy")} " + $"at {speedingViolation.Timestamp.ToString("hh:mm:ss")}."); // send fine by email var body = EmailUtils.CreateEmailBody(speedingViolation, vehicleInfo, fineString); var metadata = new Dictionary <string, string> { ["emailFrom"] = "*****@*****.**", ["emailTo"] = vehicleInfo.OwnerEmail, ["subject"] = $"Speeding violation on the {speedingViolation.RoadId}" }; await daprClient.InvokeBindingAsync("sendmail", "create", body, metadata); return(Ok()); }
public async Task <ActionResult> VehicleExit(VehicleRegistered msg, [FromServices] DaprClient daprClient) { try { // get vehicle state var vehicleState = await _vehicleStateRepository.GetVehicleStateAsync(msg.LicenseNumber); if (vehicleState == null) { return(NotFound()); } // log exit _logger.LogInformation($"EXIT detected in lane {msg.Lane} at {msg.Timestamp.ToString("hh:mm:ss")} " + $"of vehicle with license-number {msg.LicenseNumber}."); // update state vehicleState.ExitTimestamp = msg.Timestamp; await _vehicleStateRepository.SaveVehicleStateAsync(vehicleState); // handle possible speeding violation int violation = _speedingViolationCalculator.DetermineSpeedingViolationInKmh( vehicleState.EntryTimestamp, vehicleState.ExitTimestamp); if (violation > 0) { _logger.LogInformation($"Speeding violation detected ({violation} KMh) of vehicle" + $"with license-number {vehicleState.LicenseNumber}."); var speedingViolation = new SpeedingViolation { VehicleId = msg.LicenseNumber, RoadId = _roadId, ViolationInKmh = violation, Timestamp = msg.Timestamp }; // In last half of Assignment 3, update pub/sub to use Dapr ASP.NET Core client // argument #1: Name of pub/sub component // argument #2: Name of topic to which to publish // argument #3: The message payload // publish speedingviolation await daprClient.PublishEventAsync("pubsub", "collectfine", speedingViolation); // pub/sub code from first-half of Assignment 3 // var message = JsonContent.Create<SpeedingViolation>(speedingViolation); // // Replace the hardcoded API code with a call to the Dapr pub/sub side car // await _httpClient.PostAsync("http://localhost:3600/v1.0/publish/pubsub/collectfine", message); // //await _httpClient.PostAsync("http://localhost:6001/collectfine", message); } return(Ok()); } catch { return(StatusCode(500)); } }
public ActionResult SendFine(SpeedingViolation speedingViolation) { decimal fine = _fineCalculator.CalculateFine(speedingViolation.ViolationInKmh); string fineString = fine == 0 ? "tbd by the prosecutor" : $"{fine} Euro"; _logger.LogInformation($"Sent speeding ticket. Road: {speedingViolation.RoadId}, Licensenumber: {speedingViolation.VehicleId}, " + $"Violation: {speedingViolation.ViolationInKmh} Km/h, Fine: {fineString}, On: {speedingViolation.Timestamp.ToString("dd-MM-yyyy")} " + $"at {speedingViolation.Timestamp.ToString("hh:mm:ss")}."); return(Ok()); }
public async Task <ActionResult> VehicleExitAsync(VehicleRegistered msg, [FromServices] DaprClient daprClient) { try { // get vehicle state var state = await _vehicleStateRepository.GetVehicleStateAsync(msg.LicenseNumber); if (state == default(VehicleState)) { return(NotFound()); } // log exit _logger.LogInformation($"EXIT detected in lane {msg.Lane} at {msg.Timestamp.ToString("hh:mm:ss")} " + $"of vehicle with license-number {msg.LicenseNumber}."); // update state var exitState = state.Value with { ExitTimestamp = msg.Timestamp }; await _vehicleStateRepository.SaveVehicleStateAsync(exitState); // handle possible speeding violation int violation = _speedingViolationCalculator.DetermineSpeedingViolationInKmh(exitState.EntryTimestamp, exitState.ExitTimestamp.Value); if (violation > 0) { _logger.LogInformation($"Speeding violation detected ({violation} KMh) of vehicle" + $"with license-number {state.Value.LicenseNumber}."); var speedingViolation = new SpeedingViolation { VehicleId = msg.LicenseNumber, RoadId = _roadId, ViolationInKmh = violation, Timestamp = msg.Timestamp }; // publish speedingviolation (Dapr publish / subscribe) await daprClient.PublishEventAsync("pubsub", "speedingviolations", speedingViolation); } return(Ok()); } catch (Exception ex) { _logger.LogError(ex, "Error occurred while processing EXIT"); return(StatusCode(500)); } }
public async Task <ActionResult> CollectFine(SpeedingViolation speedingViolation, [FromServices] DaprClient daprClient) // Replace the SpeedingViolation with a JsonDocument parameter. Doing so will enable Dapr pub/sub messaging. //public async Task<ActionResult> CollectFine([FromBody] System.Text.Json.JsonDocument cloudevent) { // Remove CloudEvent parsing code when using ASP.NET Core Dapr client // // Extract SpeedingViolation data from the cloudevent parameter and assign to SpeedingViolation type. // var data = cloudevent.RootElement.GetProperty("data"); // // Transform raw data into a SpeedingViolation object // var speedingViolation = new SpeedingViolation // { // VehicleId = data.GetProperty("vehicleId").GetString(), // RoadId = data.GetProperty("roadId").GetString(), // Timestamp = data.GetProperty("timestamp").GetDateTime(), // ViolationInKmh = data.GetProperty("violationInKmh").GetInt32() // }; decimal fine = _fineCalculator.CalculateFine(_fineCalculatorLicenseKey, speedingViolation.ViolationInKmh); // get owner info var vehicleInfo = await _vehicleRegistrationService.GetVehicleInfo(speedingViolation.VehicleId); // log fine string fineString = fine == 0 ? "tbd by the prosecutor" : $"{fine} Euro"; _logger.LogInformation($"Sent speeding ticket to {vehicleInfo.OwnerName}. " + $"Road: {speedingViolation.RoadId}, Licensenumber: {speedingViolation.VehicleId}, " + $"Vehicle: {vehicleInfo.Brand} {vehicleInfo.Model}, " + $"Violation: {speedingViolation.ViolationInKmh} Km/h, Fine: {fineString}, " + $"On: {speedingViolation.Timestamp.ToString("dd-MM-yyyy")} " + $"at {speedingViolation.Timestamp.ToString("hh:mm:ss")}."); // send fine by email // Create email body with custom EmailUtility class var body = EmailUtils.CreateEmailBody(speedingViolation, vehicleInfo, fineString); // Specify email metadata var metadata = new Dictionary <string, string> { ["emailFrom"] = "*****@*****.**", ["emailTo"] = vehicleInfo.OwnerEmail, ["subject"] = $"Speeding violation on the {speedingViolation.RoadId}" }; // Call email server with Dapr output binding await daprClient.InvokeBindingAsync("sendmail", "create", body, metadata); return(Ok()); }
public async Task <ActionResult> VehicleExit(VehicleRegistered msg) { try { // get vehicle state var vehicleState = await _vehicleStateRepository.GetVehicleStateAsync(msg.LicenseNumber); if (vehicleState == null) { return(NotFound()); } // log exit _logger.LogInformation($"EXIT detected in lane {msg.Lane} at {msg.Timestamp.ToString("hh:mm:ss")} " + $"of vehicle with license-number {msg.LicenseNumber}."); // update state vehicleState.ExitTimestamp = msg.Timestamp; await _vehicleStateRepository.SaveVehicleStateAsync(vehicleState); // handle possible speeding violation int violation = _speedingViolationCalculator.DetermineSpeedingViolationInKmh( vehicleState.EntryTimestamp, vehicleState.ExitTimestamp); if (violation > 0) { _logger.LogInformation($"Speeding violation detected ({violation} KMh) of vehicle" + $"with license-number {vehicleState.LicenseNumber}."); var speedingViolation = new SpeedingViolation { VehicleId = msg.LicenseNumber, RoadId = _roadId, ViolationInKmh = violation, Timestamp = msg.Timestamp }; // publish speedingviolation var message = JsonContent.Create <SpeedingViolation>(speedingViolation); await _httpClient.PostAsync("http://localhost:5001/collectfine", message); } return(Ok()); } catch { return(StatusCode(500)); } }
public async Task <ActionResult> VehicleExit( VehicleRegistered msg, //[FromState(DAPR_STORE_NAME)]StateEntry<VehicleInfo> state, [FromServices] DaprClient daprClient) { try { // get vehicle state var state = await daprClient.GetStateEntryAsync <VehicleState>(DAPR_STORE_NAME, msg.LicenseNumber); if (state.Value == null) { return(NotFound()); } // log exit _logger.LogInformation($"EXIT detected in lane {msg.Lane} at {msg.Timestamp.ToString("hh:mm:ss")}: " + $"{state.Value.Brand} {state.Value.Model} with license-number {msg.LicenseNumber}."); // update state state.Value.ExitTimestamp = msg.Timestamp; await state.SaveAsync(); // handle possible speeding violation int violation = _speedingViolationCalculator.DetermineSpeedingViolationInKmh(state.Value.EntryTimestamp, state.Value.ExitTimestamp); if (violation > 0) { _logger.LogInformation($"Speeding violation detected ({violation} KMh) of {state.Value.Brand} {state.Value.Model} " + $"with license-number {state.Value.LicenseNumber}."); var speedingViolation = new SpeedingViolation { VehicleId = msg.LicenseNumber, RoadId = _roadId, ViolationInKmh = violation, Timestamp = msg.Timestamp }; await _governmentService.SendFine(speedingViolation); } return(Ok()); } catch { return(Ok(new { status = "RETRY" })); } }
public async Task RegisterExitAsync(VehicleRegistered msg) { try { Logger.LogInformation($"EXIT detected in lane {msg.Lane} at " + $"{msg.Timestamp.ToString("hh:mm:ss")} " + $"of vehicle with license-number {msg.LicenseNumber}."); // remove lost vehicle timer await UnregisterReminderAsync("VehicleLost"); // get vehicle state var vehicleState = await this.StateManager.GetStateAsync <VehicleState>("VehicleState"); vehicleState = vehicleState with { ExitTimestamp = msg.Timestamp }; await this.StateManager.SetStateAsync("VehicleState", vehicleState); // handle possible speeding violation int violation = _speedingViolationCalculator.DetermineSpeedingViolationInKmh( vehicleState.EntryTimestamp, vehicleState.ExitTimestamp.Value); if (violation > 0) { Logger.LogInformation($"Speeding violation detected ({violation} KMh) of vehicle " + $"with license-number {vehicleState.LicenseNumber}."); var speedingViolation = new SpeedingViolation { VehicleId = msg.LicenseNumber, RoadId = _roadId, ViolationInKmh = violation, Timestamp = msg.Timestamp }; // publish speedingviolation (Dapr publish / subscribe) await _daprClient.PublishEventAsync("pubsub", "speedingviolations", speedingViolation); } } catch (Exception ex) { Logger.LogError(ex, "Error in RegisterExit"); } }
public async Task <ActionResult> CollectFine(SpeedingViolation speedingViolation) { decimal fine = _fineCalculator.CalculateFine(_fineCalculatorLicenseKey, speedingViolation.ViolationInKmh); // get owner info var vehicleInfo = await _vehicleRegistrationService.GetVehicleInfo(speedingViolation.VehicleId); // log fine string fineString = fine == 0 ? "tbd by the prosecutor" : $"{fine} Euro"; _logger.LogInformation($"Sent speeding ticket to {vehicleInfo.OwnerName}. " + $"Road: {speedingViolation.RoadId}, Licensenumber: {speedingViolation.VehicleId}, " + $"Vehicle: {vehicleInfo.Brand} {vehicleInfo.Model}, " + $"Violation: {speedingViolation.ViolationInKmh} Km/h, Fine: {fineString}, " + $"On: {speedingViolation.Timestamp.ToString("dd-MM-yyyy")} " + $"at {speedingViolation.Timestamp.ToString("hh:mm:ss")}."); // send fine by email // TODO return(Ok()); }
public static string CreateEmailBody( SpeedingViolation speedingViolation, VehicleInfo vehicleInfo, string fine) { return($@" <html> <head> <style> body {{ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; }} table {{ text-align: left; padding-top: 10px; }} th {{ width: 200px; padding-left: 10px; background-clip: content-box; background-color: #EEEEEE; font-weight: normal; }} td {{ padding: 5px; width: 300px; border: 1px solid black; }} .fine {{ font-weight: bold; color: #FF0000; }} .logo {{ float: left; display: block; margin-top: -15px; }} .title {{ display: block; }} .logo-name {{ color: #FFFFFF; background-color: #2AA3D9; vertical-align: middle; padding: 10px; margin-top: 20px; height: 20px; width: 400px; }} .logo-bar {{ background-color: #005D91; width: 420px; height: 20px; margin-top: -22px; margin-bottom: 30px; }} </style> </head> <body> <div class='logo'> <svg version='1.1' width='105px' height='85px' viewBox='-0.5 -0.5 105 85'><defs/><g><path d='M 25.51 71.39 L 45.51 31.2 L 97.04 31.2 L 77.04 71.39 Z' fill='#000000' stroke='none' transform='translate(2,3)rotate(-15,61.27,51.29)' opacity='0.25'/><path d='M 25.51 71.39 L 45.51 31.2 L 97.04 31.2 L 77.04 71.39 Z' fill='#e6e6e6' stroke='none' transform='rotate(-15,61.27,51.29)' pointer-events='all'/><path d='M 15.51 60.24 L 35.51 20.05 L 87.04 20.05 L 67.04 60.24 Z' fill='#000000' stroke='none' transform='translate(2,3)rotate(-15,51.27,40.14)' opacity='0.25'/><path d='M 15.51 60.24 L 35.51 20.05 L 87.04 20.05 L 67.04 60.24 Z' fill='#2aa3d9' stroke='none' transform='rotate(-15,51.27,40.14)' pointer-events='all'/><path d='M 4.39 49.08 L 24.39 8.89 L 75.92 8.89 L 55.92 49.08 Z' fill='#000000' stroke='none' transform='translate(2,3)rotate(-15,40.16,28.99)' opacity='0.25'/><path d='M 4.39 49.08 L 24.39 8.89 L 75.92 8.89 L 55.92 49.08 Z' fill='#005d91' stroke='none' transform='rotate(-15,40.16,28.99)' pointer-events='all'/></g></svg> </div> <div class='title'> <h4 class='logo-name'>Central Fine Collection Agency</h4> <div class='logo-bar'> </div> </div> <p>The Hague, {DateTime.Now.ToLongDateString()}</p> <p>Dear Mr. / Miss / Mrs. {vehicleInfo.OwnerName},</p> <p>We hereby inform you of the fact that a speeding violation was detected with a vehicle that is registered to you.</p> <p>The violation was detected by a speeding camera. We have a digital image of your vehicle committing the violation on record in our system. If requested by your solicitor, we will provide this image to you.</p> <hr/> <p>Below you can find all the details of the violation.</p> <p> <b>Vehicle information:</b> <table> <tr><th>License number</th><td>{vehicleInfo.VehicleId}</td></tr> <tr><th>Brand</th><td>{vehicleInfo.Brand}</td></tr> <tr><th>Model</th><td>{vehicleInfo.Model}</td></tr> </table> </p> <p> <b>Conditions during the violation:</b> <table> <tr><th>Road</th><td>{speedingViolation.RoadId}</td></tr> <tr><th>Date</th><td>{speedingViolation.Timestamp.ToString("dd-MM-yyyy")}</td></tr> <tr><th>Time of day</th><td>{speedingViolation.Timestamp.ToString("hh:mm:ss")}</td></tr> </table> </p> <p> <b>Sanction:</b> <table> <tr><th>Maximum speed violation</th><td>{speedingViolation.ViolationInKmh} KMh</td></tr> <tr><th>Sanction amount</th><td><div class='fine'>{fine}</div></td></tr> </table> </p> <hr/> <p><b>Sanction handling:</b></p> <p>If the amount of the fine is to be determined by the prosecutor, you will receive a notice to appear in court shortly.</p> <p>Otherwise, you must pay the sanctioned fine <b>within 8 weeks</b> after the date of this email. If you fail to pay within 8 weeks, you will receive a first reminder email and <b>the fine will be increased to 1.5x the original fine amount</b>. If you fail to pay within 8 weeks after the first reminder, you will receive a second and last reminder email and <b>the fine will be increased to 3x the original fine amount</b>. If you fail to pay within 8 weeks after the second reminder, the case is turned over to the prosecutor and you will receive a notice to appear in court.</p> <hr/> <p> Yours sincerely,<br/> The Central Fine Collection Agency </p> </body> </html> "); }
public async Task SendFine(SpeedingViolation speedingViolation) { await _httpClient.PostAsJsonAsync <SpeedingViolation>( $"collection/sendfine", speedingViolation, _serializerOptions); }