minor adjustments to backend

This commit is contained in:
QkoSad
2024-11-25 07:49:45 +02:00
parent 4496672d19
commit 06ea52ead6
26 changed files with 459 additions and 229 deletions
+13 -11
View File
@@ -7,11 +7,6 @@ DELIMITER $$;
CREATE PROCEDURE CleanTables() CREATE PROCEDURE CleanTables()
BEGIN BEGIN
TRUNCATE TABLE Timelog;
TRUNCATE TABLE Project;
SET foreign_key_checks = 0;
TRUNCATE TABLE User;
SET foreign_key_checks = 1;
END $$ END $$
DELIMITER ; DELIMITER ;
@@ -20,7 +15,13 @@ DELIMITER ;
DELIMITER $$ DELIMITER $$
CREATE PROCEDURE InitDB() CREATE PROCEDURE InitDB()
BEGIN BEGIN
CALL CleanTables(); DECLARE i INT DEFAULT 1;
TRUNCATE TABLE Timelog;
TRUNCATE TABLE Project;
SET foreign_key_checks = 0;
TRUNCATE TABLE User;
SET foreign_key_checks = 1;
INSERT INTO Project(name) VALUES("My own"),("Outcons"),("Free Time"); INSERT INTO Project(name) VALUES("My own"),("Outcons"),("Free Time");
CREATE TEMPORARY TABLE temp_fname (fname VARCHAR(255)); CREATE TEMPORARY TABLE temp_fname (fname VARCHAR(255));
@@ -56,13 +57,14 @@ INSERT INTO temp_mail (mail) VALUES
( "gmail.com" ), ( "gmail.com" ),
( "live.com" ); ( "live.com" );
WHILE i <= 100 DO
INSERT INTO User (f_name, l_name, mail) INSERT INTO User (f_name, l_name, mail)
SELECT SELECT
(SELECT fname FROM temp_fname ORDER BY RAND() LIMIT 1), (SELECT fname FROM temp_fname ORDER BY RAND() LIMIT 1),
(SELECT lname FROM temp_lname ORDER BY RAND() LIMIT 1), (SELECT lname FROM temp_lname ORDER BY RAND() LIMIT 1),
(SELECT mail FROM temp_mail ORDER BY RAND() LIMIT 1) (SELECT mail FROM temp_mail ORDER BY RAND() LIMIT 1);
FROM SET i = i + 1;
(SELECT 1 FROM information_schema.tables LIMIT 100) AS temp; END WHILE;
UPDATE User UPDATE User
SET User.mail = CONCAT(User.f_name,".", User.l_name,"@", User.mail); SET User.mail = CONCAT(User.f_name,".", User.l_name,"@", User.mail);
@@ -83,7 +85,7 @@ BEGIN
DECLARE logs INT; DECLARE logs INT;
DECLARE hours FLOAT; DECLARE hours FLOAT;
DECLARE project INT; DECLARE project INT;
DECLARE curDate DATE DEFAULT "2024-11-18"; DECLARE curDate DATE DEFAULT '2024-11-18';
DECLARE h2 INT; DECLARE h2 INT;
WHILE users <= 100 DO WHILE users <= 100 DO
@@ -118,7 +120,7 @@ DELIMITER ;
## ##
-- get data -- get data
SELECT t.time,t.date,p.name,u.f_name,u.l_name,u.mail FROM Timelog t INNER JOIN Project p ON p.id=t.project INNER JOIN User u ON u.id=t.user; SELECT t.time,t.date,p.name,u.f_name,u.l_name,u.mail FROM Timelog t INNER JOIN Project p ON p.id=t.project INNER JOIN User u ON u.id=t.user;
-- old timelog with adding each on a new day
CREATE PROCEDURE fill_timelog () CREATE PROCEDURE fill_timelog ()
BEGIN BEGIN
DECLARE j INT DEFAULT 1; DECLARE j INT DEFAULT 1;
+133
View File
@@ -0,0 +1,133 @@
using System.Net;
using System.Text;
using MySql.Data.MySqlClient;
namespace Server
{
public class CreateProcedure
{
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
{
try
{
// Open the connection
conn.Open();
// Prepare the SQL query
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conn;
cmd.CommandText = @"
CREATE PROCEDURE fill_timelog ()
BEGIN
DECLARE j INT DEFAULT 1;
DECLARE users INT DEFAULT 1;
DECLARE logs INT;
DECLARE hours FLOAT;
DECLARE project INT;
DECLARE curDate DATE DEFAULT '2024-11-18';
DECLARE h2 INT;
WHILE users <= 100 DO
SET logs = FLOOR(1 + (RAND() * 20));
SET j = 1;
WHILE j <= logs DO
SET project = FLOOR(1 + (RAND() * 3));
SET curDate = DATE_ADD('2020-01-01', INTERVAL FLOOR(RAND() * DATEDIFF('2020-02-01', '2020-01-01')) DAY);
SET hours = (RAND() * (8 - 0.25)) + 0.25;
SELECT SUM(time) INTO h2
FROM Timelog
WHERE date = curdate && user = users;
WHILE(h2 + hours) > 8 DO
SET curDate = DATE_ADD('2020-01-01', INTERVAL FLOOR(RAND() * DATEDIFF('2020-02-01', '2020-01-01')) DAY);
SELECT SUM(time)INTO h2
FROM Timelog
WHERE date = curdate && user = users;
END WHILE;
INSERT INTO Timelog(user, project, date, time) VALUES(users, project, curDate, hours);
SET j = j + 1;
END WHILE;
SET users = users + 1;
END WHILE;
END;";
cmd.ExecuteNonQuery();
cmd.CommandText = @"CREATE PROCEDURE InitDB()
BEGIN
DECLARE i INT DEFAULT 1;
TRUNCATE TABLE Timelog;
TRUNCATE TABLE Project;
SET foreign_key_checks = 0;
TRUNCATE TABLE User;
SET foreign_key_checks = 1;
INSERT INTO Project(name) VALUES('My own'),('Outcons'),('Free Time');
CREATE TEMPORARY TABLE temp_fname (fname VARCHAR(255));
INSERT INTO temp_fname (fname) VALUES
( 'John' ),
( 'Gringo' ),
( 'Mark' ),
( 'Lisa' ),
( 'Maria' ),
( 'Sonya' ),
( 'Philip' ),
( 'Jose' ),
( 'Lorenzo' ),
( 'George' ),
( 'Justin' );
CREATE TEMPORARY TABLE temp_lname (lname VARCHAR(255));
INSERT INTO temp_lname (lname) VALUES
( 'Johnson' ),
( 'Lamas' ),
( 'Jackson' ),
( 'Brown' ),
( 'Mason' ),
( 'Rodriguez' ),
( 'Roberts' ),
( 'Thomas' ),
( 'Rose' ),
( 'McDonalds' );
CREATE TEMPORARY TABLE temp_mail (mail VARCHAR(255));
INSERT INTO temp_mail (mail) VALUES
( 'hotmail.com' ),
( 'gmail.com' ),
( 'live.com' );
WHILE i <= 100 DO
INSERT INTO User (f_name, l_name, mail)
SELECT
(SELECT fname FROM temp_fname ORDER BY RAND() LIMIT 1),
(SELECT lname FROM temp_lname ORDER BY RAND() LIMIT 1),
(SELECT mail FROM temp_mail ORDER BY RAND() LIMIT 1);
SET i = i + 1;
END WHILE;
UPDATE User
SET User.mail = CONCAT(User.f_name,'.', User.l_name,'@', User.mail);
CALL fill_timelog();
DROP TABLE temp_mail;
DROP TABLE temp_fname;
DROP TABLE temp_lname;
END;";
cmd.ExecuteNonQuery();
// prepare response
response.StatusCode = (int)HttpStatusCode.OK;
response.StatusDescription = "Status OK";
}
catch (Exception ex)
{
// Handle any connection errors
string errorMessage = $"Error: {ex.Message}";
byte[] buffer = Encoding.UTF8.GetBytes(errorMessage);
response.ContentType = "text/plain";
response.ContentLength64 = buffer.Length;
response.OutputStream.Write(buffer, 0, buffer.Length);
}
conn.Close();
}
}
}
+27 -21
View File
@@ -1,4 +1,3 @@
using System;
using System.Net; using System.Net;
using System.Text; using System.Text;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
@@ -6,15 +5,16 @@ using Newtonsoft.Json;
namespace Server namespace Server
{ {
// there should be a better way to deal with data comming from sql
public class All public class All
{ {
public object f_name { get; set; } public object? f_name { get; set; }
public object l_name { get; set; } public object? l_name { get; set; }
public object mail { get; set; } public object? mail { get; set; }
public object name { get; set; } public object? name { get; set; }
public object time { get; set; } public object? time { get; set; }
public object date { get; set; } public object? date { get; set; }
public object user { get; set; } public object? user { get; set; }
} }
public class Getall public class Getall
@@ -26,14 +26,16 @@ namespace Server
// Open the connection // Open the connection
conn.Open(); conn.Open();
// Prepare the SQL query // Prepare the SQL query
MySqlCommand myCommand = new MySqlCommand(); MySqlCommand cmd = new MySqlCommand();
myCommand.Connection = conn; cmd.Connection = conn;
// get url params
var queryString = request.QueryString; var queryString = request.QueryString;
string from = queryString["from"]; string? from = queryString["from"];
string to = queryString["to"]; string? to = queryString["to"];
string sortby = queryString["sortby"]; string? sortby = queryString["sortby"];
string offset = queryString["offset"]; string? offset = queryString["offset"];
string? order = queryString["order"];
order = order == "true" ? "ASC" : "DESC";
// this shenanigan is needed to remove the "" around // this shenanigan is needed to remove the "" around
// group by // group by
string sqlQ = @"SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user string sqlQ = @"SELECT u.f_name,u.l_name,u.mail,p.name,t.time,t.date,t.user
@@ -41,6 +43,7 @@ namespace Server
INNER JOIN Project p ON p.id=t.project INNER JOIN Project p ON p.id=t.project
INNER JOIN User u ON u.id=t.user "; INNER JOIN User u ON u.id=t.user ";
string offsetQ = " LIMIT 10 OFFSET " + offset + ";"; string offsetQ = " LIMIT 10 OFFSET " + offset + ";";
// depending on the incoming parameters construct a Query
if (!string.IsNullOrEmpty(to) && !string.IsNullOrEmpty(from)) if (!string.IsNullOrEmpty(to) && !string.IsNullOrEmpty(from))
{ {
string whereQ = " WHERE t.date BETWEEN @from AND @to "; string whereQ = " WHERE t.date BETWEEN @from AND @to ";
@@ -48,15 +51,18 @@ namespace Server
} }
if (!string.IsNullOrEmpty(sortby)) if (!string.IsNullOrEmpty(sortby))
{ {
string orderQ = " ORDER BY " + sortby; string orderQ = " ORDER BY " + sortby + " " + order;
sqlQ = sqlQ + orderQ; sqlQ = sqlQ + orderQ;
} }
myCommand.CommandText = sqlQ + offsetQ; // add the final line to the query
myCommand.Parameters.AddWithValue("@from", from); cmd.CommandText = sqlQ + offsetQ;
myCommand.Parameters.AddWithValue("@to", to); // those don't produce error if they don't find their variables
cmd.Parameters.AddWithValue("@from", from);
cmd.Parameters.AddWithValue("@to", to);
// Execute the query and read the results // Execute the query and read the results
MySqlDataReader reader = myCommand.ExecuteReader(); MySqlDataReader reader = cmd.ExecuteReader();
List<All> entries = new List<All>(); List<All> entries = new List<All>();
while (reader.Read()) while (reader.Read())
{ {
@@ -71,7 +77,7 @@ namespace Server
mail = reader["mail"], mail = reader["mail"],
}); });
} }
// Serialize the data to JSON // serialize the data to JSON
string jsonResponse = JsonConvert.SerializeObject(entries); string jsonResponse = JsonConvert.SerializeObject(entries);
// prepare response // prepare response
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse); byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
+16 -17
View File
@@ -1,4 +1,3 @@
using System;
using System.Net; using System.Net;
using System.Text; using System.Text;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
@@ -8,13 +7,13 @@ namespace Server
{ {
public class TopTen public class TopTen
{ {
public object user { get; set; } public object? user { get; set; }
public object date { get; set; } public object? date { get; set; }
public object project { get; set; } public object? project { get; set; }
public object f_name { get; set; } public object? f_name { get; set; }
public object l_name { get; set; } public object? l_name { get; set; }
public object name { get; set; } public object? name { get; set; }
public object total_time { get; set; } public object? total_time { get; set; }
} }
public class Gettopten public class Gettopten
{ {
@@ -25,12 +24,12 @@ namespace Server
// Open the connection // Open the connection
conn.Open(); conn.Open();
// Prepare the SQL query // Prepare the SQL query
MySqlCommand myCommand = new MySqlCommand(); MySqlCommand cmd = new MySqlCommand();
myCommand.Connection = conn; cmd.Connection = conn;
var queryString = request.QueryString; var queryString = request.QueryString;
string from = queryString["from"]; string? from = queryString["from"];
string to = queryString["to"]; string? to = queryString["to"];
string filterBy = queryString["filterBy"]; string? filterBy = queryString["filterBy"];
// this shenanigan is needed to remove the "" around // this shenanigan is needed to remove the "" around
// group by // group by
string req = @"SELECT t.user,t.date,t.project,u.f_name,u.l_name,p.name,SUM(t.time) as total_time string req = @"SELECT t.user,t.date,t.project,u.f_name,u.l_name,p.name,SUM(t.time) as total_time
@@ -40,12 +39,12 @@ namespace Server
WHERE t.date BETWEEN @from AND @to WHERE t.date BETWEEN @from AND @to
GROUP BY " + filterBy + @" ORDER BY total_time DESC GROUP BY " + filterBy + @" ORDER BY total_time DESC
LIMIT 10;"; LIMIT 10;";
myCommand.CommandText = req; cmd.CommandText = req;
myCommand.Parameters.AddWithValue("@from", from); cmd.Parameters.AddWithValue("@from", from);
myCommand.Parameters.AddWithValue("@to", to); cmd.Parameters.AddWithValue("@to", to);
// Execute the query and read the results // Execute the query and read the results
MySqlDataReader reader = myCommand.ExecuteReader(); MySqlDataReader reader = cmd.ExecuteReader();
List<TopTen> entries = new List<TopTen>(); List<TopTen> entries = new List<TopTen>();
while (reader.Read()) while (reader.Read())
{ {
+10 -36
View File
@@ -1,37 +1,11 @@
using System;
using System.Net; using System.Net;
using System.Text; using System.Text;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using System.Dynamic;
using Newtonsoft.Json; using Newtonsoft.Json;
namespace Server namespace Server
{ {
class DynamicObject
{
// A dictionary to store dynamic properties/fields
public Dictionary<object, object> Fields { get; set; }
public DynamicObject()
{
Fields = new Dictionary<object, object>();
}
// Adding a dynamic field
public void AddField(object key, object value)
{
Fields[key] = value;
}
// Retrieving a dynamic field
public object GetField(object key)
{
if (Fields.ContainsKey(key))
{
return Fields[key];
}
return null;
}
}
public class Getuser public class Getuser
{ {
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response) public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
@@ -41,27 +15,27 @@ namespace Server
// Open the connection // Open the connection
conn.Open(); conn.Open();
// Prepare the SQL query // Prepare the SQL query
MySqlCommand myCommand = new MySqlCommand(); MySqlCommand cmd = new MySqlCommand();
myCommand.Connection = conn; cmd.Connection = conn;
myCommand.CommandText = @"SELECT p.name, SUM(t.time) cmd.CommandText = @"SELECT p.name, SUM(t.time)
FROM Timelog t FROM Timelog t
INNER JOIN Project p ON p.id=t.project INNER JOIN Project p ON p.id=t.project
INNER JOIN User u ON u.id=t.user INNER JOIN User u ON u.id=t.user
WHERE User = @userid WHERE User = @userid
GROUP BY name;"; GROUP BY name;";
var queryString = request.QueryString; var queryString = request.QueryString;
string userid = queryString["userid"]; string? userid = queryString["userid"];
myCommand.Parameters.AddWithValue("@userid", userid); cmd.Parameters.AddWithValue("@userid", userid);
// Execute the query and read the results // Execute the query and read the results
MySqlDataReader reader = myCommand.ExecuteReader(); MySqlDataReader reader = cmd.ExecuteReader();
DynamicObject dO = new DynamicObject(); dynamic expando = new ExpandoObject();
while (reader.Read()) while (reader.Read())
{ {
dO.AddField(reader["name"], reader["SUM(t.time)"]); ((IDictionary<string?, object>)expando)[reader["name"].ToString()] = reader["SUM(t.time)"];
} }
// Serialize the data to JSON // Serialize the data to JSON
string jsonResponse = JsonConvert.SerializeObject(dO); string jsonResponse = JsonConvert.SerializeObject(expando);
// prepare response // prepare response
byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse); byte[] buffer = Encoding.UTF8.GetBytes(jsonResponse);
response.ContentType = "application/json"; response.ContentType = "application/json";
+22 -12
View File
@@ -1,10 +1,7 @@
using System; using System.Net;
using System.Net;
using System.Text; using System.Text;
using System.Threading;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
using Newtonsoft.Json; /* using System.Threading; */
using System.Collections.Generic;
namespace Server namespace Server
@@ -20,13 +17,14 @@ namespace Server
listener.Prefixes.Add("http://localhost:5000/api/gettopten/"); listener.Prefixes.Add("http://localhost:5000/api/gettopten/");
listener.Prefixes.Add("http://localhost:5000/api/getuser/"); listener.Prefixes.Add("http://localhost:5000/api/getuser/");
listener.Prefixes.Add("http://localhost:5000/api/reset/"); listener.Prefixes.Add("http://localhost:5000/api/reset/");
listener.Prefixes.Add("http://localhost:5000/api/createp/");
// Start listening for incoming requests // Start listening for incoming requests
listener.Start(); listener.Start();
Console.WriteLine("Server is listening on http://localhost:5000/"); Console.WriteLine("Server is listening on http://localhost:5000/");
// god knows what that is // god knows what that is
Thread listenerThread = new Thread(() => /* Thread listenerThread = new Thread(() => */
{ /* { */
while (true) while (true)
{ {
// wait for request // wait for request
@@ -39,8 +37,17 @@ namespace Server
MySqlConnection conn = new MySqlConnection(connectionString); MySqlConnection conn = new MySqlConnection(connectionString);
// url after localhost:5000/ // url after localhost:5000/
var uri = request.Url.AbsolutePath; // i think the validation is unnecessry but the compiler has
// more experience
string uri;
if (request != null && request.Url != null)
{
uri = request.Url.AbsolutePath;
}
else
{
return;
}
switch (uri) switch (uri)
{ {
case "/api/reset": case "/api/reset":
@@ -55,6 +62,9 @@ namespace Server
case "/api/getuser": case "/api/getuser":
Getuser.run(conn, request, response); Getuser.run(conn, request, response);
break; break;
case "/api/createp":
CreateProcedure.run(conn, request, response);
break;
default: default:
response.StatusCode = 404; response.StatusCode = 404;
string errorMessage = "Not Found"; string errorMessage = "Not Found";
@@ -67,9 +77,9 @@ namespace Server
// Close the response // Close the response
response.OutputStream.Close(); response.OutputStream.Close();
} }
}); /* }); */
// Start the listener thread /* // Start the listener thread */
listenerThread.Start(); /* listenerThread.Start(); */
} }
} }
} }
+6 -7
View File
@@ -1,11 +1,9 @@
using System;
using System.Net; using System.Net;
using System.Text; using System.Text;
using MySql.Data.MySqlClient; using MySql.Data.MySqlClient;
namespace Server namespace Server
{ {
public class Reset public class Reset
{ {
public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response) public static void run(MySqlConnection conn, HttpListenerRequest request, HttpListenerResponse response)
@@ -15,11 +13,12 @@ namespace Server
// Open the connection // Open the connection
conn.Open(); conn.Open();
// Prepare the SQL query // Prepare the SQL query
MySqlCommand myCommand = new MySqlCommand(); MySqlCommand cmd = new MySqlCommand();
myCommand.Connection = conn; cmd.Connection = conn;
myCommand.CommandText = "CALL InitDB"; cmd.CommandText = "CALL InitDB";
MySqlDataReader reader = myCommand.ExecuteReader(); // execute query
cmd.ExecuteNonQuery();
// set up and send response
response.StatusCode = (int)HttpStatusCode.OK; response.StatusCode = (int)HttpStatusCode.OK;
response.StatusDescription = "Status OK"; response.StatusDescription = "Status OK";
} }
Binary file not shown.
Binary file not shown.
@@ -13,7 +13,7 @@ using System.Reflection;
[assembly: System.Reflection.AssemblyCompanyAttribute("TimelogBackend")] [assembly: System.Reflection.AssemblyCompanyAttribute("TimelogBackend")]
[assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")] [assembly: System.Reflection.AssemblyConfigurationAttribute("Debug")]
[assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyFileVersionAttribute("1.0.0.0")]
[assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("1.0.0+4496672d19c31da56be4394168028d97a19d3a6b")]
[assembly: System.Reflection.AssemblyProductAttribute("TimelogBackend")] [assembly: System.Reflection.AssemblyProductAttribute("TimelogBackend")]
[assembly: System.Reflection.AssemblyTitleAttribute("TimelogBackend")] [assembly: System.Reflection.AssemblyTitleAttribute("TimelogBackend")]
[assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")] [assembly: System.Reflection.AssemblyVersionAttribute("1.0.0.0")]
@@ -1 +1 @@
4dc0d476a06a0877992a3936924b0e881bcf70b32aef70b9fa285a64b7d9395c 9366787f5f967306279f95e5eb689ad57d8d916a1aff008ae6b71d7ccaf910fe
@@ -8,6 +8,6 @@ build_property.PlatformNeutralAssembly =
build_property.EnforceExtendedAnalyzerRules = build_property.EnforceExtendedAnalyzerRules =
build_property._SupportedPlatformList = Linux,macOS,Windows build_property._SupportedPlatformList = Linux,macOS,Windows
build_property.RootNamespace = TimelogBackend build_property.RootNamespace = TimelogBackend
build_property.ProjectDir = /home/arch/temp/HelloWorldApp/ build_property.ProjectDir = /home/arch/projects/wip/timelog-interview/backendCs/
build_property.EnableComHosting = build_property.EnableComHosting =
build_property.EnableGeneratedComInterfaceComImportInterop = build_property.EnableGeneratedComInterfaceComImportInterop =
@@ -1 +1 @@
a26e25722337c85065d06325a739b066cff412c2c9a8e669c741ff1bfb48e5f6 8cb7b4e3896ea6e4199194b8ade89330b75c191994f715b16fe2d035c7102d40
@@ -36,3 +36,41 @@
/home/arch/temp/HelloWorldApp/obj/Debug/net8.0/TimelogBackend.pdb /home/arch/temp/HelloWorldApp/obj/Debug/net8.0/TimelogBackend.pdb
/home/arch/temp/HelloWorldApp/obj/Debug/net8.0/TimelogBackend.genruntimeconfig.cache /home/arch/temp/HelloWorldApp/obj/Debug/net8.0/TimelogBackend.genruntimeconfig.cache
/home/arch/temp/HelloWorldApp/obj/Debug/net8.0/ref/TimelogBackend.dll /home/arch/temp/HelloWorldApp/obj/Debug/net8.0/ref/TimelogBackend.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/TimelogBackend
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/TimelogBackend.deps.json
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/TimelogBackend.runtimeconfig.json
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/TimelogBackend.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/TimelogBackend.pdb
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/BouncyCastle.Cryptography.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/Google.Protobuf.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/K4os.Compression.LZ4.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/K4os.Compression.LZ4.Streams.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/K4os.Hash.xxHash.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/MySql.Data.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/Newtonsoft.Json.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/System.Configuration.ConfigurationManager.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/System.Diagnostics.EventLog.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/System.IO.Pipelines.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/System.Security.Cryptography.ProtectedData.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/System.Security.Permissions.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/System.Windows.Extensions.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/ZstdSharp.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win-x64/native/comerr64.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win-x64/native/gssapi64.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win-x64/native/k5sprt64.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win-x64/native/krb5_64.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win-x64/native/krbcc64.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.Messages.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win/lib/net8.0/System.Diagnostics.EventLog.dll
/home/arch/projects/wip/timelog-interview/backendCs/bin/Debug/net8.0/runtimes/win/lib/net8.0/System.Windows.Extensions.dll
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.csproj.AssemblyReference.cache
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.GeneratedMSBuildEditorConfig.editorconfig
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.AssemblyInfoInputs.cache
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.AssemblyInfo.cs
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.csproj.CoreCompileInputs.cache
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.csproj.CopyComplete
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.dll
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/refint/TimelogBackend.dll
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.pdb
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/TimelogBackend.genruntimeconfig.cache
/home/arch/projects/wip/timelog-interview/backendCs/obj/Debug/net8.0/ref/TimelogBackend.dll
Binary file not shown.
@@ -1 +1 @@
349d85780636e3e61d35aee10e34ef55954b239c07ad0a356798a097ceae0148 b9db7be95623da1c56ce81f0a2fe43bd17220a8c9689f0c3bac4131258accda2
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,17 +1,17 @@
{ {
"format": 1, "format": 1,
"restore": { "restore": {
"/home/arch/temp/HelloWorldApp/TimelogBackend.csproj": {} "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj": {}
}, },
"projects": { "projects": {
"/home/arch/temp/HelloWorldApp/TimelogBackend.csproj": { "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj": {
"version": "1.0.0", "version": "1.0.0",
"restore": { "restore": {
"projectUniqueName": "/home/arch/temp/HelloWorldApp/TimelogBackend.csproj", "projectUniqueName": "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj",
"projectName": "TimelogBackend", "projectName": "TimelogBackend",
"projectPath": "/home/arch/temp/HelloWorldApp/TimelogBackend.csproj", "projectPath": "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj",
"packagesPath": "/home/arch/.nuget/packages/", "packagesPath": "/home/arch/.nuget/packages/",
"outputPath": "/home/arch/temp/HelloWorldApp/obj/", "outputPath": "/home/arch/projects/wip/timelog-interview/backendCs/obj/",
"projectStyle": "PackageReference", "projectStyle": "PackageReference",
"configFilePaths": [ "configFilePaths": [
"/home/arch/.nuget/NuGet/NuGet.Config" "/home/arch/.nuget/NuGet/NuGet.Config"
+3 -3
View File
@@ -1658,11 +1658,11 @@
"project": { "project": {
"version": "1.0.0", "version": "1.0.0",
"restore": { "restore": {
"projectUniqueName": "/home/arch/temp/HelloWorldApp/TimelogBackend.csproj", "projectUniqueName": "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj",
"projectName": "TimelogBackend", "projectName": "TimelogBackend",
"projectPath": "/home/arch/temp/HelloWorldApp/TimelogBackend.csproj", "projectPath": "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj",
"packagesPath": "/home/arch/.nuget/packages/", "packagesPath": "/home/arch/.nuget/packages/",
"outputPath": "/home/arch/temp/HelloWorldApp/obj/", "outputPath": "/home/arch/projects/wip/timelog-interview/backendCs/obj/",
"projectStyle": "PackageReference", "projectStyle": "PackageReference",
"configFilePaths": [ "configFilePaths": [
"/home/arch/.nuget/NuGet/NuGet.Config" "/home/arch/.nuget/NuGet/NuGet.Config"
+2 -2
View File
@@ -1,8 +1,8 @@
{ {
"version": 2, "version": 2,
"dgSpecHash": "p6MNaUN/SYJSFf9M574e8kcv9EqEwjPgKKmmL1309Lwqd26TTBeTctoKZziGbcJiysFehsYg0kxDJKBlru2uCA==", "dgSpecHash": "05fTwHDwROQn3aS1fZFUfkni+eNLFijwdR49kiMZyADYQWkBGYKVh4QK8CMaBFfif3DNASYK7goRXVy8COyb4A==",
"success": true, "success": true,
"projectFilePath": "/home/arch/temp/HelloWorldApp/TimelogBackend.csproj", "projectFilePath": "/home/arch/projects/wip/timelog-interview/backendCs/TimelogBackend.csproj",
"expectedPackageFiles": [ "expectedPackageFiles": [
"/home/arch/.nuget/packages/bouncycastle.cryptography/2.3.1/bouncycastle.cryptography.2.3.1.nupkg.sha512", "/home/arch/.nuget/packages/bouncycastle.cryptography/2.3.1/bouncycastle.cryptography.2.3.1.nupkg.sha512",
"/home/arch/.nuget/packages/google.protobuf/3.26.1/google.protobuf.3.26.1.nupkg.sha512", "/home/arch/.nuget/packages/google.protobuf/3.26.1/google.protobuf.3.26.1.nupkg.sha512",
+1 -1
View File
@@ -8,7 +8,7 @@ function App() {
const [reset, setReset] = useState(true); const [reset, setReset] = useState(true);
return ( return (
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid size={6}> <Grid size={{ lg: 12, xl: 6 }}>
<LeftSide reset={reset} setReset={setReset} /> <LeftSide reset={reset} setReset={setReset} />
</Grid> </Grid>
<Grid size={6}> <Grid size={6}>
+113 -45
View File
@@ -7,18 +7,37 @@ import {
TableCell, TableCell,
TableHead, TableHead,
Table, Table,
Button,
} from "@mui/material"; } from "@mui/material";
const LeftSide = ({ reset, setReset }) => { interface User {
// next prev and sort date: string;
const [users, setUsers] = useState(); f_name: string;
const [params, setParams] = useState({ offset: 0, sortby: "f_name" }); l_name: string;
// reset button mail: string;
// const [reset, setReset] = useState(true); name: string;
time: number;
user: number;
}
// date const LeftSide = ({
const [date, setDate] = useState({ from: "2021-01-01", to: "2028-01-01" }); reset,
const [dateToSubmit, setDateToSubmit] = useState({ setReset,
}: {
reset: boolean;
setReset: Function;
}) => {
// next prev and sort buttons
const [users, setUsers] = useState<User[]>();
const [params, setParams] = useState({
offset: 0,
sortby: "f_name",
from: "2000-01-01",
to: "2028-01-01",
order: true,
});
// date buttons
const [date, setDate] = useState({
from: "2021-01-01", from: "2021-01-01",
to: "2028-01-01", to: "2028-01-01",
}); });
@@ -28,7 +47,7 @@ const LeftSide = ({ reset, setReset }) => {
const resp = await api.get("/getall", { const resp = await api.get("/getall", {
params, params,
}); });
setUsers(resp.data); if (resp.data.length) setUsers(resp.data);
} }
async function resetData() { async function resetData() {
await api.get("/reset"); await api.get("/reset");
@@ -39,15 +58,14 @@ const LeftSide = ({ reset, setReset }) => {
} }
fetchData(); fetchData();
}, [reset, params, dateToSubmit]); }, [reset, params]);
const viewProjectHours = (user) => { const viewProjectHours = (userid: number) => {
async function fetchHours() { async function fetchHours() {
const resp = await api.get("/getuser", { const resp = await api.get("/getuser", {
params: { userid: user }, params: { userid },
}); });
// const entriesArray = Object.entries(resp.data); const entriesArray = Object.entries(resp.data);
const entriesArray = Object.entries(resp.data.Fields);
alert(entriesArray); alert(entriesArray);
} }
fetchHours(); fetchHours();
@@ -56,7 +74,7 @@ const LeftSide = ({ reset, setReset }) => {
if (!users) return <></>; if (!users) return <></>;
return ( return (
<Grid container spacing={2}> <Grid container spacing={2}>
<Grid size={5}> <Grid size={12}>
<label htmlFor="date">From: </label> <label htmlFor="date">From: </label>
<input <input
type="date" type="date"
@@ -70,31 +88,15 @@ const LeftSide = ({ reset, setReset }) => {
type="date" type="date"
id="to" id="to"
name="to" name="to"
value={date.to} value={params.to}
onChange={(event) => setDate({ ...date, to: event.target.value })} onChange={(event) => setDate({ ...date, to: event.target.value })}
/> />
<button onClick={() => setDateToSubmit(date)}>Submit Date</button> <button
</Grid> onClick={() => setParams({ ...params, from: date.from, to: date.to })}
<Grid size={3}>
<span>Select a sort:</span>
<select
value={params.sortby}
onChange={(event) =>
setParams((prevParams) => {
return { ...prevParams, sortby: event.target.value };
})
}
> >
<option value="">--Select--</option> Submit Date
<option value="f_name">First name</option> </button>
<option value="l_name">Last Name</option>
<option value="mail">Email</option>
<option value="date">Date</option>
<option value="time">Time</option>
</select>
</Grid> </Grid>
<Grid size={4}></Grid>
<Grid size={4}></Grid>
<Grid size={4}> <Grid size={4}>
<button <button
onClick={() => { onClick={() => {
@@ -106,6 +108,9 @@ const LeftSide = ({ reset, setReset }) => {
> >
Prev users Prev users
</button> </button>
</Grid>
<Grid size={4}></Grid>
<Grid size={4}>
<button <button
onClick={() => onClick={() =>
setParams((prevParams) => { setParams((prevParams) => {
@@ -119,12 +124,73 @@ const LeftSide = ({ reset, setReset }) => {
<Table> <Table>
<TableHead> <TableHead>
<TableRow> <TableRow>
<TableCell>First Name</TableCell> <TableCell>
<TableCell>Last Name</TableCell> <Button
<TableCell>Email</TableCell> onClick={() =>
<TableCell>Project name</TableCell> setParams({
<TableCell>Date</TableCell> ...params,
<TableCell>Hours</TableCell> sortby: "f_name",
order: !params.order,
})
}
>
First Name
</Button>
</TableCell>
<TableCell>
<Button
onClick={() =>
setParams({
...params,
sortby: "l_name",
order: !params.order,
})
}
>
Last Name
</Button>
</TableCell>
<TableCell>
<Button
onClick={() =>
setParams({ ...params, sortby: "mail", order: !params.order })
}
>
Email
</Button>
</TableCell>
<TableCell>
<Button
onClick={() =>
setParams({
...params,
sortby: "project",
order: !params.order,
})
}
>
Project
</Button>
</TableCell>
<TableCell>
<Button
onClick={() =>
setParams({ ...params, sortby: "date", order: !params.order })
}
>
Date
</Button>
</TableCell>
<TableCell>
<Button
onClick={() =>
setParams({ ...params, sortby: "time", order: !params.order })
}
>
Hours
</Button>
</TableCell>
<TableCell />
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
@@ -139,13 +205,15 @@ const LeftSide = ({ reset, setReset }) => {
<TableCell>{post.time} </TableCell> <TableCell>{post.time} </TableCell>
<TableCell> <TableCell>
<button onClick={() => viewProjectHours(post.user)}> <button onClick={() => viewProjectHours(post.user)}>
View Project Hours Hours
</button> </button>
</TableCell> </TableCell>
</TableRow> </TableRow>
)) ))
) : ( ) : (
<div>No posts found...</div> <TableRow>
<TableCell>No data found...</TableCell>
</TableRow>
)} )}
</TableBody> </TableBody>
</Table> </Table>
+19 -18
View File
@@ -2,12 +2,9 @@ import { useEffect, useState } from "react";
import api from "../utils/api"; import api from "../utils/api";
import { Chart } from "react-google-charts"; import { Chart } from "react-google-charts";
const RightSide = (reset) => { const RightSide = ({ reset }: { reset: boolean }) => {
// graph date // graph date
const [topten, setTopten] = useState({ const [chartData, setChartData] = useState<String[][]>();
from: "2000-01-01",
to: "2100-01-01",
});
// date input field // date input field
const [date, setDate] = useState({ from: "2000-01-01", to: "2100-01-01" }); const [date, setDate] = useState({ from: "2000-01-01", to: "2100-01-01" });
const [dateToSubmit, setDateToSubmit] = useState({ const [dateToSubmit, setDateToSubmit] = useState({
@@ -15,7 +12,7 @@ const RightSide = (reset) => {
to: "2100-01-01", to: "2100-01-01",
}); });
// radio button // radio button
const [selectedOption, setSelectedOption] = useState("project"); const [filter, setFilter] = useState("project");
useEffect(() => { useEffect(() => {
async function fetchData() { async function fetchData() {
@@ -23,26 +20,26 @@ const RightSide = (reset) => {
params: { params: {
from: dateToSubmit.from, from: dateToSubmit.from,
to: dateToSubmit.to, to: dateToSubmit.to,
filterBy: selectedOption, filterBy: filter,
}, },
}); });
resp.data.unshift(["User", "Hours"]); resp.data.unshift(["User", "Hours"]);
// turn the data into form suitable to charts // turn the data into form suitable to charts
if (selectedOption === "project") if (filter === "project")
for (let idx = 1; idx < resp.data.length; idx++) { for (let idx = 1; idx < resp.data.length; idx++) {
resp.data[idx] = [resp.data[idx].name, resp.data[idx].total_time]; resp.data[idx] = [resp.data[idx].name, resp.data[idx].total_time];
} }
else if (selectedOption === "user") else if (filter === "user")
for (let idx = 1; idx < resp.data.length; idx++) { for (let idx = 1; idx < resp.data.length; idx++) {
resp.data[idx] = [ resp.data[idx] = [
resp.data[idx].f_name + " " + resp.data[idx].l_name, resp.data[idx].f_name + " " + resp.data[idx].l_name,
resp.data[idx].total_time, resp.data[idx].total_time,
]; ];
} }
setTopten(resp.data); setChartData(resp.data);
} }
fetchData(); fetchData();
}, [dateToSubmit, selectedOption, reset]); }, [dateToSubmit, filter, reset]);
// Chart options // Chart options
const options = { const options = {
@@ -53,11 +50,11 @@ const RightSide = (reset) => {
minValue: 0, minValue: 0,
}, },
vAxis: { vAxis: {
title: selectedOption, title: filter,
}, },
}; };
if (!topten) <></>; if (!chartData) <></>;
return ( return (
<div style={{ flex: 1 }}> <div style={{ flex: 1 }}>
@@ -85,8 +82,8 @@ const RightSide = (reset) => {
<input <input
type="radio" type="radio"
value="user" value="user"
checked={selectedOption === "user"} checked={filter === "user"}
onChange={(event) => setSelectedOption(event.target.value)} onChange={(event) => setFilter(event.target.value)}
/> />
User User
</label> </label>
@@ -94,19 +91,23 @@ const RightSide = (reset) => {
<input <input
type="radio" type="radio"
value="project" value="project"
checked={selectedOption === "project"} checked={filter === "project"}
onChange={(event) => setSelectedOption(event.target.value)} onChange={(event) => setFilter(event.target.value)}
/> />
Project Project
</label> </label>
</> </>
{chartData !== undefined && chartData.length < 2 ? (
<div>No data</div>
) : (
<Chart <Chart
chartType="BarChart" chartType="BarChart"
width="100%" width="100%"
height="400px" height="400px"
data={topten} data={chartData}
options={options} options={options}
></Chart> ></Chart>
)}
</div> </div>
); );
}; };