Compare commits

...

6 Commits

Author SHA1 Message Date
762680537b New: Readme
All checks were successful
Build and Push Docker Image / build (push) Successful in 4m7s
2026-03-18 11:09:30 +01:00
dbcd9f4872 Update: Rental Form Styles
All checks were successful
Build and Push Docker Image / build (push) Successful in 2m10s
2026-03-18 10:49:04 +01:00
18289006d1 New: better Exception Handling
All checks were successful
Build and Push Docker Image / build (push) Successful in 7m0s
2026-03-18 09:47:58 +01:00
d90a6f970f New: gitignore 2026-03-18 09:46:56 +01:00
4634c4ae98 Fix migration order
All checks were successful
Build and Push Docker Image / build (push) Successful in 2m9s
2026-03-18 01:24:06 +01:00
7afab94810 Delay of 20 seconds before migration 2026-03-18 01:21:54 +01:00
13 changed files with 197 additions and 103 deletions

View File

@@ -28,26 +28,6 @@ BEGIN
);
END;
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Rental]') AND type = 'U')
BEGIN
CREATE TABLE Rental (
id BIGINT NOT NULL IDENTITY (1, 1),
rentalStart DATETIME NOT NULL,
rentalEnd DATETIME NOT NULL,
actualEnd DATETIME NULL,
customerID BIGINT NOT NULL,
vehicleID BIGINT NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE Rental
ADD CONSTRAINT FK_Customer_TO_Rental FOREIGN KEY (customerID) REFERENCES Customer (id);
ALTER TABLE Rental
ADD CONSTRAINT FK_Vehicle_TO_Rental FOREIGN KEY (vehicleID) REFERENCES Vehicle (id);
END;
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[VehicleCategory]') AND type = 'U')
BEGIN
CREATE TABLE VehicleCategory (
@@ -78,4 +58,25 @@ BEGIN
ADD CONSTRAINT FK_VehicleCategory_TO_Vehicle FOREIGN KEY (vehicleCategoryID) REFERENCES VehicleCategory (id);
END;
IF NOT EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[dbo].[Rental]') AND type = 'U')
BEGIN
CREATE TABLE Rental (
id BIGINT NOT NULL IDENTITY (1, 1),
rentalStart DATETIME NOT NULL,
rentalEnd DATETIME NOT NULL,
actualEnd DATETIME NULL,
customerID BIGINT NOT NULL,
vehicleID BIGINT NOT NULL,
PRIMARY KEY (id)
);
ALTER TABLE Rental
ADD CONSTRAINT FK_Customer_TO_Rental FOREIGN KEY (customerID) REFERENCES Customer (id);
ALTER TABLE Rental
ADD CONSTRAINT FK_Vehicle_TO_Rental FOREIGN KEY (vehicleID) REFERENCES Vehicle (id);
END;

View File

@@ -0,0 +1,2 @@
bin/
obj/

View File

@@ -1,4 +1,9 @@
@inherits LayoutComponentBase
@using Services
@inherits LayoutComponentBase
@implements IDisposable
@rendermode RenderMode.InteractiveServer
@inject IErrorService ErrorService
<div class="page">
<div class="sidebar">
@@ -7,6 +12,13 @@
<main>
<article class="content px-4">
@if(ErrorService.ex != null) {
<div class="alert alert-danger m-3" role="alert">
@ErrorService.ex.Message
<button type="button" class="btn-close float-end" aria-label="Close" @onclick="DismissError"></button>
</div>
}
@Body
</article>
</main>
@@ -17,3 +29,20 @@
<a href="." class="reload">Reload</a>
<span class="dismiss">🗙</span>
</div>
@code {
protected override void OnInitialized()
{
ErrorService.OnChange += StateHasChanged;
}
private void DismissError()
{
ErrorService.ex = null;
}
public void Dispose()
{
ErrorService.OnChange -= StateHasChanged;
}
}

View File

@@ -0,0 +1,18 @@
@page "/ErrorTest"
@using Microsoft.Data.SqlClient
@using Services
@inject IErrorService ErrorService
<PageTitle>Error Test</PageTitle>
<h1>Error Page</h1>
<button @onclick="SetError" class="btn btn-primary">Set Error</button>
@code {
private void SetError() {
ErrorService.ex = new Exception("Hello World");
}
}

View File

@@ -1,7 +1,9 @@
@page "/"
@using Models
@using Services
@using System.Runtime.InteropServices
@inject IRentService RentService
@inject IErrorService ErrorService
<PageTitle>Home</PageTitle>
@@ -45,9 +47,11 @@
protected override void OnInitialized()
{
_vehicles = RentService.GetAvailableCars();
Console.WriteLine("VC" + _vehicles.Count);
@* return Task.CompletedTask; *@
try {
_vehicles = RentService.GetAvailableCars();
} catch (Exception e) {
ErrorService.ex = e;
}
}
}

View File

@@ -1,33 +1,48 @@
@page "/rent"
@using Models
@using Services
@using System.Runtime.InteropServices
@inject IRentService RentService
@inject NavigationManager NavigationManager
@inject IErrorService ErrorService
<PageTitle>Rent</PageTitle>
<h1>Rent</h1>
<form @onsubmit="RentCar">
<InputSelect @bind-Value="_vehicleId">
@foreach (Vehicle v in _vehicles)
{
<option value=@v.Id>@v.Id - @v.Brand - @v.Model</option>
}
</InputSelect>
<InputSelect @bind-Value="_customerId">
@foreach (Customer c in _customers)
{
<option value=@c.Id>@c.Name</option>
}
</InputSelect>
<div class="form-group mb-3">
<label for="vehicle">Vehicle: </label>
<InputSelect @bind-Value="_vehicleId" id="vehicle" class="form-control" placeholder="Fahrzeug">
@foreach (Vehicle v in _vehicles)
{
<option value=@v.Id>@v.Id - @v.Brand - @v.Model</option>
}
</InputSelect>
</div>
<InputDate @bind-Value="_from"/>
<div class="form-group mb-3">
<label for="customer">Kunde: </label>
<InputSelect @bind-Value="_customerId" id="customer" class="form-control" placeholder="Kunde">
@foreach (Customer c in _customers)
{
<option value=@c.Id>@c.Name</option>
}
</InputSelect>
</div>
<InputDate @bind-Value="_thru"/>
<div class="form-group mb-3">
<label for="from">Von: </label>
<InputDate @bind-Value="_from" class="form-control" id="from" />
</div>
<button type="submit">Submit</button>
<div class="form-group mb-3">
<label for="thru">Bis: </label>
<InputDate @bind-Value="_thru" class="form-control" id="thru" />
</div>
<button type="submit" class="btn btn-primary">Mieten!</button>
</form>
@code {
@@ -41,15 +56,22 @@
protected override void OnInitialized()
{
_vehicles = RentService.GetAvailableCars();
_customers = RentService.GetCustomers();
try {
_vehicles = RentService.GetAvailableCars();
_customers = RentService.GetCustomers();
} catch (Exception e) {
ErrorService.ex = e;
}
}
private Task RentCar()
{
RentService.RentCar(_customerId, _vehicleId, _from, _thru);
Console.WriteLine("Rented Car");
NavigationManager.NavigateTo("/");
try {
RentService.RentCar(_customerId, _vehicleId, _from, _thru);
NavigationManager.NavigateTo("/");
} catch (Exception e) {
ErrorService.ex = e;
}
return Task.CompletedTask;
}
}

View File

@@ -2,6 +2,7 @@
@using Models
@using Services
@inject IRollbackService RollbackService
@inject IErrorService ErrorService
<PageTitle>Rollback</PageTitle>
@@ -12,7 +13,11 @@
@code {
private Task PerformRollback() {
RollbackService.ResetToDefaults();
try {
RollbackService.ResetToDefaults();
} catch (Exception e) {
ErrorService.ex = e;
}
return Task.CompletedTask;
}
}

View File

@@ -17,6 +17,7 @@ public static class ServiceCollectionExtension
services.Services.AddScoped<IRentService, RentService>();
services.Services.AddScoped<IRollbackService, RollbackService>();
services.Services.AddScoped<IErrorService, ErrorService>();
return services;
}
}

View File

@@ -0,0 +1,30 @@
using System.Data;
using Configuration;
using Microsoft.Data.SqlClient;
using Models;
namespace Services
{
public interface IErrorService
{
Exception? ex { get; set; }
event Action? OnChange;
}
public class ErrorService : IErrorService
{
private Exception? _ex;
public Exception? ex
{
get => _ex;
set
{
_ex = value;
NotifyStateChanged();
}
}
public event Action? OnChange;
private void NotifyStateChanged() => OnChange?.Invoke();
}
}

View File

@@ -17,22 +17,16 @@ namespace Services
public List<Vehicle> GetAvailableCars()
{
List<Vehicle> vehicles = new List<Vehicle>();
try
{
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
string sql = "SELECT * FROM v_VerfuegbareFahrzeuge;";
SqlCommand cmd = new SqlCommand(sql, conn);
using SqlDataReader reader = cmd.ExecuteReader();
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
string sql = "SELECT * FROM v_VerfuegbareFahrzeuge;";
SqlCommand cmd = new SqlCommand(sql, conn);
while (reader.Read())
{
vehicles.Add(Vehicle.FromReader(reader));
}
}
catch (Exception e)
using SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(e);
vehicles.Add(Vehicle.FromReader(reader));
}
return vehicles;
@@ -41,22 +35,16 @@ namespace Services
public List<Customer> GetCustomers()
{
List<Customer> customers = new List<Customer>();
try
{
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
string sql = "SELECT * FROM Customer;";
SqlCommand cmd = new SqlCommand(sql, conn);
using SqlDataReader reader = cmd.ExecuteReader();
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
string sql = "SELECT * FROM Customer;";
SqlCommand cmd = new SqlCommand(sql, conn);
while (reader.Read())
{
customers.Add(Customer.FromReader(reader));
}
}
catch (Exception e)
using SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
Console.WriteLine(e);
customers.Add(Customer.FromReader(reader));
}
return customers;
@@ -64,22 +52,17 @@ namespace Services
public void RentCar(long customerId, long vehicleId, DateTime start, DateTime end)
{
try
{
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
using SqlCommand cmd = new SqlCommand("sp_MieteFahrzeug", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@KundeID", customerId);
cmd.Parameters.AddWithValue("@FahrzeugID", vehicleId);
cmd.Parameters.AddWithValue("@Start", start);
cmd.Parameters.AddWithValue("@Ende", end);
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
using SqlCommand cmd = new SqlCommand("sp_MieteFahrzeug", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.ExecuteNonQuery();
}catch (Exception ex)
{
Console.WriteLine(ex);
}
cmd.Parameters.AddWithValue("@KundeID", customerId);
cmd.Parameters.AddWithValue("@FahrzeugID", vehicleId);
cmd.Parameters.AddWithValue("@Start", start);
cmd.Parameters.AddWithValue("@Ende", end);
cmd.ExecuteNonQuery();
}
}
}

View File

@@ -14,24 +14,17 @@ namespace Services
{
public void ResetToDefaults()
{
try
{
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
using SqlConnection conn = sqlConnectionFactory.CreateSqlConnection();
string sql = @"
USE [master];
ALTER DATABASE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB] FROM DATABASE_SNAPSHOT = '2025_5bhitn_konstantin_hintermayer_smarter_rentDB_snapshot';
ALTER DATABASE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB] SET MULTI_USER;";
string sql = @"
USE [master];
ALTER DATABASE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
RESTORE DATABASE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB] FROM DATABASE_SNAPSHOT = '2025_5bhitn_konstantin_hintermayer_smarter_rentDB_snapshot';
ALTER DATABASE [2025_5bhitn_konstantin_hintermayer_smarter_rentDB] SET MULTI_USER;";
using SqlCommand cmd = new SqlCommand(sql, conn);
using SqlCommand cmd = new SqlCommand(sql, conn);
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
cmd.ExecuteNonQuery();
}
}
}

View File

@@ -1,6 +1,9 @@
#!/bin/bash
# Run the three SQL files using sqlcmd
# -S: Server, -U: User, -P: Password (passed via ENV)
sleep 20
echo "Applying SQL files..."
for migration in $(ls . | grep -E '\.sql$')

3
README.md Normal file
View File

@@ -0,0 +1,3 @@
# Smartrent
Deployed unter: https://sr.kocoder.xyz