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
3 changes: 3 additions & 0 deletions CodingTracker.DzemalKurtic/CodingTracker.DzemalKurtic.slnx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Solution>
<Project Path="CodingTracker.DzemalKurtic/CodingTracker.DzemalKurtic.csproj" />
</Solution>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<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.79" />
<PackageReference Include="Microsoft.Data.Sqlite" Version="10.0.11" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.11" />
<PackageReference Include="Spectre.Console" Version="0.57.2" />
</ItemGroup>

<ItemGroup>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using CodingTracker.DzemalKurtic.Models;
using Dapper;
using Microsoft.Data.Sqlite;

namespace CodingTracker.DzemalKurtic.Controllers;

internal class CodingSessionController
{
public string ConnectionString { get; set; }
public CodingSessionController(string connectionString)
{
ConnectionString = connectionString;
}

public void AddItem(DateTime start, DateTime end)
{
using var connection = new SqliteConnection(ConnectionString);
connection.Open();

var sql =
"""
INSERT INTO coding_sessions
(StartTime, EndTime)
VALUES (@StartTime, @EndTime)
""";

var session = new CodingSession { StartTime = start, EndTime = end };

connection.Execute(sql, session);
}

public int DeleteItem(int id)
{
using var connection = new SqliteConnection(ConnectionString);
connection.Open();

var sql =
"""
DELETE FROM coding_sessions
WHERE Id = @Id;
""";

var rowCount = connection.Execute(sql, new { Id = id });
return rowCount;
}

public int UpdateItem(int id, DateTime start, DateTime end)
{
using var connection = new SqliteConnection(ConnectionString);
connection.Open();

var sql =
"""
UPDATE coding_sessions SET StartTime = @StartTime, EndTime = @EndTime
WHERE Id = @Id
""";
var session = new CodingSession { Id = id, StartTime = start, EndTime = end };

var rowCount = connection.Execute(sql, session);
return rowCount;
}

public List<CodingSession> ViewItems()
{
using var connection = new SqliteConnection(ConnectionString);
connection.Open();

var sql = "SELECT * FROM coding_sessions";
var sessions = connection.Query<CodingSession>(sql).ToList();

return sessions;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Dapper;
using Microsoft.Data.Sqlite;

namespace CodingTracker.DzemalKurtic.Data;

internal static class Database
{
public static void Initialize(string connectionString)
{
using var connection = new SqliteConnection(connectionString);
connection.Open();

var sql =
"""
CREATE TABLE IF NOT EXISTS coding_sessions (
Id INTEGER PRIMARY KEY AUTOINCREMENT,
StartTime TEXT NOT NULL,
EndTime TEXT NOT NULL
);
""";

connection.Execute(sql);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace CodingTracker.DzemalKurtic;

internal enum MenuAction
{
ViewSessions,
AddSession,
UpdateSession,
DeleteSession
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
namespace CodingTracker.DzemalKurtic.Models;

public class CodingSession
{
public int Id { get; set; }
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }

public TimeSpan Duration => EndTime - StartTime;

public CodingSession(int id, DateTime startTime, DateTime endTime)
{
Id = id;
StartTime = startTime;
EndTime = endTime;
}

public CodingSession(DateTime startTime, DateTime endTime)
{
StartTime = startTime;
EndTime = endTime;
}

public CodingSession()
{

}
}
15 changes: 15 additions & 0 deletions CodingTracker.DzemalKurtic/CodingTracker.DzemalKurtic/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using CodingTracker.DzemalKurtic.Controllers;
using CodingTracker.DzemalKurtic.Data;
using CodingTracker.DzemalKurtic.Views;
using Microsoft.Extensions.Configuration;

IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json")
.Build();

var connectionString = config.GetConnectionString("DefaultConnection");

Database.Initialize(connectionString);
var controller = new CodingSessionController(connectionString);
var ui = new UserInterface(controller);
ui.MainMenu();
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"profiles": {
"CodingTracker.DzemalKurtic": {
"commandName": "Project"
}
}
}
69 changes: 69 additions & 0 deletions CodingTracker.DzemalKurtic/CodingTracker.DzemalKurtic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
**Project requirements:**



* Logging occurrence of a coding session
* Users need to be bale to input the start date of the coding session
* Users need to be bale to input the end date of the coding session
* Duration of the sessions should be calculated from these values
* App should use a real database
* Users should be able to insert, delete, update and view their coding sessions
* All input errors should be handled
* Only Dapper should be used



**How the App works?**



When a user starts the app, he sees a menu with options:



\- View all Sessions

\- Add a Session

\- Update a Session

\- Delete a Session



&#x20;

Choosing "View all Sessions" will show him a table with all the sessions that are recorded in the database.



Choosing "Add a Session" will open another screen where he will be able to enter a start time in dd-mm-yy hh:mm format.

After entering it he will be able to enter a end time in dd-mm-yy hh:mm format for the session.



Choosing "Update a Session" will bring up a new screen where a user will be able to update an existing record.

You must use Id of the record that exists in the database.

After choosing an Id user will be able to enter new start time and time for the session.



Choosing "Delete a Session" bring up a new screen where a use will be able to delete the sessions that are already recorded.

You must use Id of the record that exists in the database.





**Thoughts on the project:**



This project made me use appsettings.json where I put the connection string to the Sqlite database. Dapper is easier to use than ADO.NET. For user interface I used spectre console, which has quite a few neat features. I really like the table feature. Also it's easier to get a list of options and a correct answer.

Hardest part was figuring out how to convert between a model and a database because Sqlite doesn't have a date data type. I was using strings in the model because I couldn't get it to work with DateTime type. But then I was wondering how to calculate the duration of the session.

Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using Spectre.Console;
using System.Globalization;

namespace CodingTracker.DzemalKurtic;

internal static class Validation
{
internal static DateTime ValidateDate(string dateInput, string dateName)
{
string date = dateInput;

while (!DateTime.TryParseExact(date, "dd-MM-yy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out _))
{
AnsiConsole.WriteLine("Invalid date. (Format: dd-mm-yy hh:mm). Try again:");
date = AnsiConsole.Ask<string>($"Enter the {dateName} date of the Coding Session: (Format: dd-mm-yy hh:mm)");
}

return DateTime.ParseExact(date, "dd-MM-yy HH:mm", CultureInfo.InvariantCulture);
}


internal static int ValidateId(int idInput)
{
int id = idInput;
while (Convert.ToInt32(id) < 0)
{
AnsiConsole.WriteLine("Number can't be negative. Try again.");
id = AnsiConsole.Ask<int>("Please typt the Id od the item you want to update");
}

return Convert.ToInt32(id);
}

internal static bool ValidateTimespan(DateTime start, DateTime end)
{
bool isBigger = end <= start;
if (isBigger) AnsiConsole.WriteLine("End date can not be before start date");
return isBigger;
}
}
Loading
Loading