PI2024-30 #6

Merged
s464958 merged 4 commits from PI2024-30 into master 2024-11-28 20:20:27 +01:00
5 changed files with 271 additions and 1 deletions
Showing only changes of commit e50274b736 - Show all commits

View File

@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using FirmTracker_Server.nHibernate;
using FirmTracker_Server.nHibernate.Expenses;
using Microsoft.AspNetCore.Mvc;
using QuestPDF.Fluent;
using QuestPDF.Helpers;
using QuestPDF.Infrastructure;
namespace FirmTracker_Server.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class PdfController : ControllerBase
{
private readonly IExpenseRepository _expenseRepository;
public PdfController(IExpenseRepository expenseRepository)
{
_expenseRepository = expenseRepository;
}
[HttpGet("download")]
public IActionResult DownloadExpenseReport()
{
// Fetch expense data from the repository
List<Expense> expenses = _expenseRepository.GetAllExpenses();
// Generate the PDF file
byte[] pdfBytes = GeneratePdf(expenses);
string date = DateTime.Now.ToString("yyyy-MM-dd");
string fileName = $"ExpenseReport_{date}.pdf";
// Return the PDF as a downloadable file
return File(pdfBytes, "application/pdf", fileName);
}
private byte[] GeneratePdf(List<Expense> expenses)
{
using (var ms = new MemoryStream())
{
// Calculate total and average expenses
decimal totalExpenses = expenses.Sum(e => e.Value);
decimal averageExpense = expenses.Count > 0 ? totalExpenses / expenses.Count : 0;
// Define the document using QuestPDF
Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(2, Unit.Centimetre);
page.PageColor(Colors.White);
page.DefaultTextStyle(x => x.FontSize(12));
// Main header
page.Header()
.Text("Expense Report")
.FontSize(20)
.SemiBold()
.AlignCenter();
// Summary section
page.Content().PaddingVertical(1, Unit.Centimetre).Column(column =>
{
column.Spacing(10);
column.Item().Row(row =>
{
row.RelativeItem().Text($"Total Expenses: {totalExpenses:C}").FontSize(14).Bold();
row.RelativeItem().Text($"Average Expense: {averageExpense:C}").FontSize(14).Bold();
});
column.Item().Text("Expense Details").FontSize(16).Underline();
// Add a table header
column.Item().Row(row =>
{
row.RelativeItem().Text("Date").SemiBold();
row.RelativeItem().Text("Value").SemiBold();
row.RelativeItem().Text("Description").SemiBold();
});
// Populate table rows with expense data
foreach (var expense in expenses)
{
column.Item().Row(row =>
{
row.RelativeItem().Text(expense.Date.ToString("yyyy-MM-dd"));
row.RelativeItem().Text(expense.Value.ToString("C"));
row.RelativeItem().Text(expense.Description);
});
}
});
// Footer with generation date
page.Footer()
.AlignCenter()
.Text(text =>
{
text.Span("Generated on ");
text.Span(DateTime.Now.ToString("yyyy-MM-dd")).SemiBold();
});
});
}).GeneratePdf(ms);
return ms.ToArray();
}
}
}
}

View File

@ -0,0 +1,55 @@
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Concurrent;
using System.Linq;
namespace YourNamespace.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class WorkdayController : ControllerBase
{
// In-memory storage for simplicity, where the key is the userId.
private static readonly ConcurrentDictionary<string, DateTime?> WorkStartTimes = new ConcurrentDictionary<string, DateTime?>();
// Get the current status of the user's workday (started or not)
[HttpGet("status/{userId}")]
public IActionResult GetWorkdayStatus(string userId)
{
if (WorkStartTimes.TryGetValue(userId, out DateTime? startTime))
{
if (startTime.HasValue)
{
return Ok(new { status = "started", startTime = startTime });
}
else
{
return Ok(new { status = "stopped" });
}
}
else
{
return NotFound(new { message = "User not found" });
}
}
// Start or stop the user's workday by toggling the start/stop state
[HttpPost("toggle/{userId}")]
public IActionResult ToggleWorkday(string userId)
{
// If the workday has already started, stop it, otherwise start it
if (WorkStartTimes.ContainsKey(userId) && WorkStartTimes[userId].HasValue)
{
// Stop the workday
WorkStartTimes[userId] = null;
return Ok(new { status = "stopped" });
}
else
{
// Start the workday
WorkStartTimes[userId] = DateTime.Now;
return Ok(new { status = "started", startTime = WorkStartTimes[userId] });
}
}
}
}

View File

@ -29,6 +29,7 @@
<PackageReference Include="NLog" Version="5.3.4" /> <PackageReference Include="NLog" Version="5.3.4" />
<PackageReference Include="NLog.Database" Version="5.3.4" /> <PackageReference Include="NLog.Database" Version="5.3.4" />
<PackageReference Include="NSwag.Annotations" Version="14.0.7" /> <PackageReference Include="NSwag.Annotations" Version="14.0.7" />
<PackageReference Include="QuestPDF" Version="2024.10.3" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="System.Data.SqlClient" Version="4.8.6" /> <PackageReference Include="System.Data.SqlClient" Version="4.8.6" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.1.2" /> <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.1.2" />

View File

@ -37,6 +37,7 @@ using FirmTracker_Server.Middleware;
using FirmTracker_Server.Services; using FirmTracker_Server.Services;
using System.Reflection; using System.Reflection;
using FirmTracker_Server.Mappings; using FirmTracker_Server.Mappings;
using NuGet.Packaging;
namespace FirmTracker_Server namespace FirmTracker_Server
@ -69,6 +70,7 @@ namespace FirmTracker_Server
TestClass test = new TestClass(); TestClass test = new TestClass();
test.AddTestProduct(); test.AddTestProduct();
QuestPDF.Settings.License = QuestPDF.Infrastructure.LicenseType.Community;
builder.Services.AddCors(options => builder.Services.AddCors(options =>
{ {
@ -173,6 +175,7 @@ namespace FirmTracker_Server
services.AddScoped<IUserService, UserService>(); services.AddScoped<IUserService, UserService>();
services.AddScoped<ErrorHandling>(); services.AddScoped<ErrorHandling>();
services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>(); services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>();
services.AddScoped<IExpenseRepository, ExpenseRepository>();
services.AddMvc(); services.AddMvc();
} }

98
nHIbernate/PdfData.cs Normal file
View File

@ -0,0 +1,98 @@
using System.Collections.Generic;
using System.Linq;
using FirmTracker_Server.nHibernate.Expenses;
using NHibernate;
namespace FirmTracker_Server.nHibernate
{
public interface IExpenseRepository
{
List<Expense> GetAllExpenses();
Expense GetExpense(int expenseId);
void AddExpense(Expense expense);
void UpdateExpense(Expense expense);
void DeleteExpense(int expenseId);
}
public class ExpenseRepository : IExpenseRepository
{
// Retrieve all expenses
public List<Expense> GetAllExpenses()
{
using (var session = SessionFactory.OpenSession())
{
return session.Query<Expense>().ToList();
}
}
// Retrieve a specific expense by ID
public Expense GetExpense(int expenseId)
{
using (var session = SessionFactory.OpenSession())
{
return session.Get<Expense>(expenseId);
}
}
// Add a new expense
public void AddExpense(Expense expense)
{
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
try
{
session.Save(expense);
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
// Update an existing expense
public void UpdateExpense(Expense expense)
{
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
try
{
session.Update(expense);
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
// Delete an expense by ID
public void DeleteExpense(int expenseId)
{
using (var session = SessionFactory.OpenSession())
using (var transaction = session.BeginTransaction())
{
try
{
var expense = session.Get<Expense>(expenseId);
if (expense != null)
{
session.Delete(expense);
}
transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}
}
}
}