Merge pull request #782 from hargata/Hargata/697

added API method that generates a calendar of reminders for the user.
This commit is contained in:
Hargata Softworks
2025-01-08 12:39:26 -07:00
committed by GitHub
4 changed files with 92 additions and 9 deletions

View File

@@ -1166,6 +1166,19 @@ namespace CarCareTracker.Controllers
return Json(results); return Json(results);
} }
} }
[HttpGet]
[Route("/api/calendar")]
public IActionResult Calendar()
{
var vehiclesStored = _dataAccess.GetVehicles();
if (!User.IsInRole(nameof(UserData.IsRootUser)))
{
vehiclesStored = _userLogic.FilterUserVehicles(vehiclesStored, GetUserID());
}
var reminders = _vehicleLogic.GetReminders(vehiclesStored, true);
var calendarContent = StaticHelper.RemindersToCalendar(reminders);
return File(calendarContent, "text/calendar");
}
[Authorize(Roles = nameof(UserData.IsRootUser))] [Authorize(Roles = nameof(UserData.IsRootUser))]
[HttpGet] [HttpGet]
[Route("/api/vehicle/reminders/send")] [Route("/api/vehicle/reminders/send")]

View File

@@ -1,6 +1,8 @@
using CarCareTracker.Models; using CarCareTracker.Models;
using CsvHelper; using CsvHelper;
using System.Globalization; using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json; using System.Text.Json;
namespace CarCareTracker.Helper namespace CarCareTracker.Helper
@@ -754,5 +756,52 @@ namespace CarCareTracker.Helper
_csv.NextRecord(); _csv.NextRecord();
} }
} }
public static byte[] RemindersToCalendar(List<ReminderRecordViewModel> reminders)
{
//converts reminders to iCal file
StringBuilder sb = new StringBuilder();
//start the calendar item
sb.AppendLine("BEGIN:VCALENDAR");
sb.AppendLine("VERSION:2.0");
sb.AppendLine("PRODID:lubelogger.com");
sb.AppendLine("CALSCALE:GREGORIAN");
sb.AppendLine("METHOD:PUBLISH");
//create events.
foreach(ReminderRecordViewModel reminder in reminders)
{
var dtStart = reminder.Date.Date.ToString("yyyyMMddTHHmm00");
var dtEnd = reminder.Date.Date.AddDays(1).AddMilliseconds(-1).ToString("yyyyMMddTHHmm00");
var calendarUID = new Guid(MD5.HashData(Encoding.UTF8.GetBytes($"{dtStart}_{reminder.Description}")));
sb.AppendLine("BEGIN:VEVENT");
sb.AppendLine("DTSTAMP:" + DateTime.Now.ToString("yyyyMMddTHHmm00"));
sb.AppendLine("UID:" + calendarUID);
sb.AppendLine("DTSTART:" + dtStart);
sb.AppendLine("DTEND:" + dtEnd);
sb.AppendLine($"SUMMARY:{reminder.Description}");
sb.AppendLine($"DESCRIPTION:{reminder.Description}");
switch (reminder.Urgency)
{
case ReminderUrgency.NotUrgent:
sb.AppendLine("PRIORITY:3");
break;
case ReminderUrgency.Urgent:
sb.AppendLine("PRIORITY:2");
break;
case ReminderUrgency.VeryUrgent:
sb.AppendLine("PRIORITY:1");
break;
case ReminderUrgency.PastDue:
sb.AppendLine("PRIORITY:1");
break;
}
sb.AppendLine("END:VEVENT");
}
//end calendar item
sb.AppendLine("END:VCALENDAR");
string calendarContent = sb.ToString();
return Encoding.UTF8.GetBytes(calendarContent);
}
} }
} }

View File

@@ -106,11 +106,15 @@ var app = builder.Build();
// Configure the HTTP request pipeline. // Configure the HTTP request pipeline.
app.UseExceptionHandler("/Home/Error"); app.UseExceptionHandler("/Home/Error");
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions app.UseStaticFiles(new StaticFileOptions
{ {
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "data", "images")),
RequestPath = "/images",
OnPrepareResponse = ctx => OnPrepareResponse = ctx =>
{ {
if (ctx.Context.Request.Path.StartsWithSegments("/images") || ctx.Context.Request.Path.StartsWithSegments("/documents")) if (ctx.Context.Request.Path.StartsWithSegments("/images"))
{ {
ctx.Context.Response.Headers.Add("Cache-Control", "no-store"); ctx.Context.Response.Headers.Add("Cache-Control", "no-store");
if (!ctx.Context.User.Identity.IsAuthenticated) if (!ctx.Context.User.Identity.IsAuthenticated)
@@ -121,16 +125,21 @@ app.UseStaticFiles(new StaticFileOptions
} }
}); });
app.UseStaticFiles(new StaticFileOptions app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "data", "images")),
RequestPath = "/images"
});
app.UseStaticFiles(new StaticFileOptions
{ {
FileProvider = new PhysicalFileProvider( FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "data", "documents")), Path.Combine(builder.Environment.ContentRootPath, "data", "documents")),
RequestPath = "/documents" RequestPath = "/documents",
OnPrepareResponse = ctx =>
{
if (ctx.Context.Request.Path.StartsWithSegments("/documents"))
{
ctx.Context.Response.Headers.Add("Cache-Control", "no-store");
if (!ctx.Context.User.Identity.IsAuthenticated)
{
ctx.Context.Response.Redirect("/Login");
}
}
}
}); });
app.UseStaticFiles(new StaticFileOptions app.UseStaticFiles(new StaticFileOptions
{ {
@@ -142,7 +151,18 @@ app.UseStaticFiles(new StaticFileOptions
{ {
FileProvider = new PhysicalFileProvider( FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "data", "temp")), Path.Combine(builder.Environment.ContentRootPath, "data", "temp")),
RequestPath = "/temp" RequestPath = "/temp",
OnPrepareResponse = ctx =>
{
if (ctx.Context.Request.Path.StartsWithSegments("/temp"))
{
ctx.Context.Response.Headers.Add("Cache-Control", "no-store");
if (!ctx.Context.User.Identity.IsAuthenticated)
{
ctx.Context.Response.Redirect("/Login");
}
}
}
}); });
app.UseRouting(); app.UseRouting();

View File

@@ -34,6 +34,7 @@
<meta name="apple-mobile-web-app-capable" content="yes" /> <meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent"> <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<title>@ViewData["Title"] - LubeLogger</title> <title>@ViewData["Title"] - LubeLogger</title>
<link rel="icon" type="image/x-icon" href="~/favicon.ico">
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap-icons.css" /> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap-icons.css" />
<link rel="stylesheet" href="~/lib/bootstrap-datepicker/css/bootstrap-datepicker.min.css" /> <link rel="stylesheet" href="~/lib/bootstrap-datepicker/css/bootstrap-datepicker.min.css" />