Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -478,3 +478,4 @@ $RECYCLE.BIN/
*.lnk
/MathGame2
/CodingTracker.TomDonegan/TextFile1.txt
KelvinTawiah.CodingTracker/appsettings.json
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"dotnet.defaultSolution": "KelvinTawiah.slnx"
}
209 changes: 209 additions & 0 deletions KelvinTawiah.CodingTracker/CodingController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
using Spectre.Console;
using KelvinTawiah.CodingTracker.model;
using KelvinTawiah.CodingTracker.service;

namespace KelvinTawiah.CodingTracker;

public class CodingController
{
private readonly SessionService _sessionService;
private readonly SessionLogService _logService;

public CodingController(SessionService sessionService, SessionLogService logService)
{
_sessionService = sessionService;
_logService = logService;
}

public void Run()
{
while (true)
{
var choice = AnsiConsole.Prompt(
new SelectionPrompt<string>()
.Title("[bold blue]Coding Tracker[/]")
.PageSize(10)
.AddChoices(
"Add session",
"View all sessions",
"View session details",
"Update session",
"Delete session",
"View logs",
"Exit")
);

switch (choice)
{
case "Add session":
AddSession();
break;
case "View all sessions":
ShowAllSessions();
break;
case "View session details":
ShowSessionDetails();
break;
case "Update session":
UpdateSession();
break;
case "Delete session":
DeleteSession();
break;
case "View logs":
ShowLogs();
break;
case "Exit":
return;
}
}
}

private void AddSession()
{
var session = UserInput.PromptForSession();
_sessionService.AddSession(session);
_logService.AddLog(new SessionLog
{
SessionId = session.Id,
Action = "Create",
Message = "Session added",
LoggedAt = DateTime.Now
});

AnsiConsole.MarkupLine("[green]Session added successfully.[/]");
WaitForKey();
}

private void ShowAllSessions()
{
var sessions = _sessionService.GetAllSessions();
var table = new Table().RoundedBorder();
table.AddColumn("Id");
table.AddColumn("Start");
table.AddColumn("End");
table.AddColumn("Duration (min)");
table.AddColumn("Notes");

foreach (var s in sessions)
{
table.AddRow(
s.Id.ToString(),
s.StartTime.ToString(Validation.DateFormat),
s.EndTime.ToString(Validation.DateFormat),
s.DurationMinutes.ToString(),
string.IsNullOrWhiteSpace(s.Notes) ? "-" : s.Notes
);
}

if (sessions.Count == 0)
{
AnsiConsole.MarkupLine("[yellow]No sessions found.[/]");
}
else
{
AnsiConsole.Write(table);
}

WaitForKey();
}

private void ShowSessionDetails()
{
var id = UserInput.PromptForSessionId("Enter session Id:");
var session = _sessionService.GetSessionById(id);
if (session == null)
{
AnsiConsole.MarkupLine("[red]Session not found.[/]");
WaitForKey();
return;
}

var panel = new Panel($"Id: {session.Id}\nStart: {session.StartTime:yyyy-MM-dd HH:mm}\nEnd: {session.EndTime:yyyy-MM-dd HH:mm}\nDuration (min): {session.DurationMinutes}\nNotes: {session.Notes}")
.Border(BoxBorder.Rounded)
.Header("Session Details", Justify.Center);

AnsiConsole.Write(panel);
WaitForKey();
}

private void UpdateSession()
{
var id = UserInput.PromptForSessionId("Enter session Id:");
var session = _sessionService.GetSessionById(id);
if (session == null)
{
AnsiConsole.MarkupLine("[red]Session not found.[/]");
WaitForKey();
return;
}

var updated = UserInput.PromptForSessionUpdate(session);
_sessionService.UpdateSession(updated);
_logService.AddLog(new SessionLog
{
SessionId = updated.Id,
Action = "Update",
Message = "Session updated",
LoggedAt = DateTime.Now
});

AnsiConsole.MarkupLine("[green]Session updated.[/]");
WaitForKey();
}

private void DeleteSession()
{
var id = UserInput.PromptForSessionId("Enter session Id:");
_sessionService.DeleteSession(id);
_logService.AddLog(new SessionLog
{
SessionId = id,
Action = "Delete",
Message = "Session deleted",
LoggedAt = DateTime.Now
});

AnsiConsole.MarkupLine("[green]Session deleted.[/]");
WaitForKey();
}

private void ShowLogs()
{
var logs = _logService.ViewLogs();
var table = new Table().RoundedBorder();
table.AddColumn("Id");
table.AddColumn("SessionId");
table.AddColumn("Action");
table.AddColumn("Message");
table.AddColumn("LoggedAt");

foreach (var log in logs)
{
table.AddRow(
log.Id.ToString(),
log.SessionId?.ToString() ?? "-",
log.Action,
string.IsNullOrWhiteSpace(log.Message) ? "-" : log.Message,
log.LoggedAt.ToString(Validation.DateFormat)
);
}

if (logs.Count == 0)
{
AnsiConsole.MarkupLine("[yellow]No logs found.[/]");
}
else
{
AnsiConsole.Write(table);
}

WaitForKey();
}

private static void WaitForKey()
{
AnsiConsole.MarkupLine("\n[grey]Press any key to continue...[/]");
Console.ReadKey();
}
}
16 changes: 16 additions & 0 deletions KelvinTawiah.CodingTracker/KelvinTawiah.CodingTracker.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Dapper" Version="2.1.66" />
<PackageReference Include="Microsoft.Data.SqlClient" Version="6.1.4" />
<PackageReference Include="Spectre.Console" Version="0.54.0" />
</ItemGroup>

</Project>
117 changes: 117 additions & 0 deletions KelvinTawiah.CodingTracker/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using System.Text.Json;
using Microsoft.Data.SqlClient;
using KelvinTawiah.CodingTracker;
using KelvinTawiah.CodingTracker.service;

public class Program
{
static readonly string APP_SETTING_PATH = FindPathUpward("appsettings.json");
static readonly string MASTER_DB_USER = "master";
static string? DATABASE_NAME;
static string? DATABASE_PASSWORD;
static string? DATABASE_USER;
static string? DATABASE_SERVER;
static string? CONNECTION_STRING;


private static string FindPathUpward(string fileName)
{
string path = fileName;

DirectoryInfo? currDir = new(Directory.GetCurrentDirectory());

while (currDir != null)
{
string potentialPath = Path.Combine(currDir.FullName, fileName);

if (File.Exists(potentialPath)) return potentialPath;
currDir = currDir.Parent;
}

return path;
}

public static void Main(string[] args)
{
var appSettings = LoadAppSettings();
DATABASE_NAME = appSettings.GetProperty("Database").GetProperty("Name").GetString();
DATABASE_USER = appSettings.GetProperty("Database").GetProperty("User").GetString();
DATABASE_PASSWORD = appSettings.GetProperty("Database").GetProperty("Password").GetString();
DATABASE_SERVER = appSettings.GetProperty("Database").GetProperty("Server").GetString();

InitializeDatabase();
CONNECTION_STRING = $"Server={DATABASE_SERVER};Database={DATABASE_NAME};User Id={DATABASE_USER};Password={DATABASE_PASSWORD};TrustServerCertificate=True";

var sessionService = new SessionService(CONNECTION_STRING!);
var sessionLogService = new SessionLogService(CONNECTION_STRING!);
var controller = new CodingController(sessionService, sessionLogService);

controller.Run();
}

private static void InitializeDatabase()
{
var masterConnString = $"Server={DATABASE_SERVER};Database={MASTER_DB_USER};User Id={DATABASE_USER};Password={DATABASE_PASSWORD};TrustServerCertificate=True";
var appConnString = $"Server={DATABASE_SERVER};Database={DATABASE_NAME};User Id={DATABASE_USER};Password={DATABASE_PASSWORD};TrustServerCertificate=True";

using (var conn = new SqlConnection(masterConnString))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = $"IF DB_ID('{DATABASE_NAME}') IS NULL CREATE DATABASE {DATABASE_NAME}";
cmd.ExecuteNonQuery();
}

// Create tables
using (var conn = new SqlConnection(appConnString))
{
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = @"
IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'CodingSessions')
BEGIN
CREATE TABLE CodingSessions (
Id INT PRIMARY KEY IDENTITY(1,1),
StartTime DATETIME NOT NULL,
EndTime DATETIME NOT NULL,
DurationMinutes INT NOT NULL,
Notes NVARCHAR(MAX) NULL
)
END
ELSE IF COL_LENGTH('CodingSessions', 'DurationMinutes') IS NULL
BEGIN
ALTER TABLE CodingSessions ADD DurationMinutes INT NOT NULL DEFAULT(0);
END

IF NOT EXISTS (SELECT * FROM sys.tables WHERE name = 'SessionLogs')
BEGIN
CREATE TABLE SessionLogs (
Id INT PRIMARY KEY IDENTITY(1,1),
SessionId INT NULL,
Action NVARCHAR(100) NOT NULL,
Message NVARCHAR(MAX) NULL,
LoggedAt DATETIME NOT NULL DEFAULT(GETDATE()),
FOREIGN KEY (SessionId) REFERENCES CodingSessions(Id)
)
END
ELSE
BEGIN
IF COL_LENGTH('SessionLogs', 'SessionId') IS NULL
ALTER TABLE SessionLogs ADD SessionId INT NULL;
IF COL_LENGTH('SessionLogs', 'Action') IS NULL
ALTER TABLE SessionLogs ADD Action NVARCHAR(100) NOT NULL DEFAULT('');
IF COL_LENGTH('SessionLogs', 'Message') IS NULL
ALTER TABLE SessionLogs ADD Message NVARCHAR(MAX) NULL;
IF COL_LENGTH('SessionLogs', 'LoggedAt') IS NULL
ALTER TABLE SessionLogs ADD LoggedAt DATETIME NOT NULL DEFAULT(GETDATE());
END";
cmd.ExecuteNonQuery();
}
}

private static JsonElement LoadAppSettings()
{
var json = File.ReadAllText(APP_SETTING_PATH);
return JsonElement.Parse(json);
}
}
Loading