diff --git a/CardReaderService/CardReaderService.conf b/CardReaderService/CardReaderService.conf
new file mode 100644
index 0000000..802a6f4
--- /dev/null
+++ b/CardReaderService/CardReaderService.conf
@@ -0,0 +1,5 @@
+[program:CardReaderService]
+command=mono-service CardReaderService.exe --no-daemon
+directory=/DIRECTORYTOSET/CardReaderService
+stdout_logfile=/DIRECTORYTOSET/CardReaderService/out.log
+redirect_stderr=true
diff --git a/CardReaderService/CardReaderService/CardReaderService.sln b/CardReaderService/CardReaderService.sln
similarity index 57%
rename from CardReaderService/CardReaderService/CardReaderService.sln
rename to CardReaderService/CardReaderService.sln
index 61dbd08..79a69b4 100644
--- a/CardReaderService/CardReaderService/CardReaderService.sln
+++ b/CardReaderService/CardReaderService.sln
@@ -3,9 +3,18 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 14
VisualStudioVersion = 14.0.25420.1
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CardReaderService", "CardReaderService.csproj", "{5F30E8E4-5107-4C99-ADFF-38D735DC113D}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CardReaderService", "CardReaderService\CardReaderService.csproj", "{5F30E8E4-5107-4C99-ADFF-38D735DC113D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CardReaderServiceHost", "..\CardReaderServiceHost\CardReaderServiceHost.csproj", "{6E48913F-9D8C-4132-93A7-C7B1C6DD5264}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CardReaderServiceHost", "CardReaderServiceHost\CardReaderServiceHost.csproj", "{6E48913F-9D8C-4132-93A7-C7B1C6DD5264}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Logger", "Logger\Logger.csproj", "{42EFE386-DC2E-455A-BA81-5FC9CEE45D02}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux Conf", "Linux Conf", "{F9053F37-761D-45EE-9153-46776B083DBA}"
+ ProjectSection(SolutionItems) = preProject
+ CardReaderService.conf = CardReaderService.conf
+ install.sh = install.sh
+ uninstall.sh = uninstall.sh
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -21,6 +30,10 @@ Global
{6E48913F-9D8C-4132-93A7-C7B1C6DD5264}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6E48913F-9D8C-4132-93A7-C7B1C6DD5264}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6E48913F-9D8C-4132-93A7-C7B1C6DD5264}.Release|Any CPU.Build.0 = Release|Any CPU
+ {42EFE386-DC2E-455A-BA81-5FC9CEE45D02}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {42EFE386-DC2E-455A-BA81-5FC9CEE45D02}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {42EFE386-DC2E-455A-BA81-5FC9CEE45D02}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {42EFE386-DC2E-455A-BA81-5FC9CEE45D02}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/CardReaderService/CardReaderService/App.config b/CardReaderService/CardReaderService/App.config
index da9bca9..89c3fd7 100644
--- a/CardReaderService/CardReaderService/App.config
+++ b/CardReaderService/CardReaderService/App.config
@@ -1,9 +1,9 @@
-
+
-
+
-
\ No newline at end of file
+
diff --git a/CardReaderService/CardReaderService/CardDataPost.cs b/CardReaderService/CardReaderService/CardDataPost.cs
new file mode 100644
index 0000000..6dfce4c
--- /dev/null
+++ b/CardReaderService/CardReaderService/CardDataPost.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace CardReaderService
+{
+ public class CardDataPost
+ {
+ public DateTime UtcTimeStamp { get; set; }
+ public string CardUId { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/CardReaderService/CardReaderService/CardReaderService.csproj b/CardReaderService/CardReaderService/CardReaderService.csproj
index 2b37206..8621c3d 100644
--- a/CardReaderService/CardReaderService/CardReaderService.csproj
+++ b/CardReaderService/CardReaderService/CardReaderService.csproj
@@ -9,9 +9,10 @@
Properties
CardReaderService
CardReaderService
- v4.5.2
+ v4.5
512
true
+
AnyCPU
@@ -33,12 +34,12 @@
4
-
- packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll
+
+ ..\packages\Newtonsoft.Json.12.0.2\lib\net45\Newtonsoft.Json.dll
True
-
- packages\PCSC.3.6.0\lib\net40\pcsc-sharp.dll
+
+ ..\packages\PCSC.4.2.0\lib\net40\PCSC.dll
True
@@ -53,6 +54,11 @@
+
+
+
+
+
@@ -68,6 +74,12 @@
+
+
+ {42EFE386-DC2E-455A-BA81-5FC9CEE45D02}
+ Logger
+
+
+
\ No newline at end of file
diff --git a/CardReaderService/Logger/MessageLogger.cs b/CardReaderService/Logger/MessageLogger.cs
new file mode 100644
index 0000000..a693525
--- /dev/null
+++ b/CardReaderService/Logger/MessageLogger.cs
@@ -0,0 +1,20 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Logger
+{
+ public class MessageLogger
+ {
+ private static string _logPath = "log.txt";
+
+ public static void Log(string message)
+ {
+ Console.WriteLine(message);
+ File.AppendAllText(_logPath, string.Format("{0} | {1}{2}", DateTime.Now, message, Environment.NewLine));
+ }
+ }
+}
diff --git a/CardReaderService/Logger/Properties/AssemblyInfo.cs b/CardReaderService/Logger/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..3ae09c3
--- /dev/null
+++ b/CardReaderService/Logger/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Logger")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Logger")]
+[assembly: AssemblyCopyright("Copyright © 2017")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("42efe386-dc2e-455a-ba81-5fc9cee45d02")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/CardReaderService/dependencies.txt b/CardReaderService/dependencies.txt
new file mode 100644
index 0000000..ceae7b8
--- /dev/null
+++ b/CardReaderService/dependencies.txt
@@ -0,0 +1,7 @@
+install:
+ - pcscd
+ - supervisor
+ - mono-complete
+
+copy CardReaderService.conf to /home/osboxes/CardReaderService
+
diff --git a/CardReaderService/install.sh b/CardReaderService/install.sh
new file mode 100644
index 0000000..a90cdb9
--- /dev/null
+++ b/CardReaderService/install.sh
@@ -0,0 +1,24 @@
+#!/bin/sh
+if [ -z "$1" ]
+ then
+ echo "No arguments supplied, supply the base path"
+fi
+echo "Installing dependencies"
+apt-get install mono-complete pcscd supervisor -y
+
+echo "Modifying supervisor conf file"
+sed -i "s|/DIRECTORYTOSET|$1|g" CardReaderService.conf
+
+echo "Installing service configuration file"
+cp CardReaderService.conf /etc/supervisor/conf.d/
+
+echo "Installing applicaton"
+mkdir $1/CardReaderService
+cp ./*.* $1/CardReaderService
+cd $1/CardReaderService
+rm *.pdb
+rm *.vshost.exe
+rm *.vshost.exe.config
+rm *.vshost.exe.manifest
+echo "Starting application........."
+service supervisor restart
\ No newline at end of file
diff --git a/CardReaderService/uninstall.sh b/CardReaderService/uninstall.sh
new file mode 100644
index 0000000..5cb65ce
--- /dev/null
+++ b/CardReaderService/uninstall.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+if [ -z "$1" ]
+ then
+ echo "No arguments supplied, supply the base path"
+fi
+echo "Stopping service...."
+service supervisor stop
+rm -f /etc/supervisor/conf.d/CardReaderService.conf
+echo "Removing Application.."
+rm -r -f $1/CardReaderService
+echo "Removing application dependencies.."
+apt-get remove pcscd supervisor mono-complete -y
diff --git a/DataCenter_Windows/WindowsDataCenter/CardReaderService/App.config b/DataCenter_Windows/WindowsDataCenter/CardReaderService/App.config
index a1f8f1f..ed0e97f 100644
--- a/DataCenter_Windows/WindowsDataCenter/CardReaderService/App.config
+++ b/DataCenter_Windows/WindowsDataCenter/CardReaderService/App.config
@@ -1,10 +1,18 @@
-
+
-
+
-
-
+
+
-
\ No newline at end of file
+
+
+
+
+
+
+
+
+
diff --git a/DataCenter_Windows/WindowsDataCenter/CardReaderService/CardReaderService.csproj b/DataCenter_Windows/WindowsDataCenter/CardReaderService/CardReaderService.csproj
index 2f275a1..9ce3d75 100644
--- a/DataCenter_Windows/WindowsDataCenter/CardReaderService/CardReaderService.csproj
+++ b/DataCenter_Windows/WindowsDataCenter/CardReaderService/CardReaderService.csproj
@@ -9,9 +9,10 @@
Properties
CardReaderService
CardReaderService
- v4.5.2
+ v4.5
512
true
+
AnyCPU
@@ -85,6 +86,7 @@
+
Component
diff --git a/DataCenter_Windows/WindowsDataCenter/CardReaderService/DefaultComponents/LogFileLogger.cs b/DataCenter_Windows/WindowsDataCenter/CardReaderService/DefaultComponents/LogFileLogger.cs
new file mode 100644
index 0000000..2a12080
--- /dev/null
+++ b/DataCenter_Windows/WindowsDataCenter/CardReaderService/DefaultComponents/LogFileLogger.cs
@@ -0,0 +1,122 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using Interfaces;
+
+namespace CardReaderService.DefaultComponents
+{
+ class LogFileLogger: ILogger
+ {
+ public bool IsDebugEnabled => true;
+ public bool IsErrorEnabled => true;
+ public bool IsFatalEnabled => true;
+ public bool IsInfoEnabled => true;
+ public bool IsTraceEnabled => true;
+ public bool IsWarnEnabled => true;
+
+ public void Debug(Exception exception)
+ {
+ Log(exception.ToString());
+ }
+
+ public void Debug(string format, params object[] args)
+ {
+ Log(string.Format(format, args));
+ }
+
+ public void Debug(Exception exception, string format, params object[] args)
+ {
+ Log(exception.ToString());
+ Log(string.Format(format, args));
+ }
+
+ public void Error(Exception exception)
+ {
+ Log(exception.ToString());
+ }
+
+ public void Error(string format, params object[] args)
+ {
+ Log(string.Format(format, args));
+ }
+
+ public void Error(Exception exception, string format, params object[] args)
+ {
+ Log(exception.ToString());
+ Log(string.Format(format, args));
+ }
+
+ public void Fatal(Exception exception)
+ {
+ Log(exception.ToString());
+ }
+
+ public void Fatal(string format, params object[] args)
+ {
+ Log(string.Format(format, args));
+ }
+
+ public void Fatal(Exception exception, string format, params object[] args)
+ {
+ Log(exception.ToString());
+ Log(string.Format(format, args));
+ }
+
+ public void Info(Exception exception)
+ {
+ Log(exception.ToString());
+ }
+
+ public void Info(string format, params object[] args)
+ {
+ Log(string.Format(format, args));
+ }
+
+ public void Info(Exception exception, string format, params object[] args)
+ {
+ Log(exception.ToString());
+ Log(string.Format(format, args));
+ }
+
+ public void Trace(Exception exception)
+ {
+ Log(exception.ToString());
+ }
+
+ public void Trace(string format, params object[] args)
+ {
+ Log(string.Format(format, args));
+ }
+
+ public void Trace(Exception exception, string format, params object[] args)
+ {
+ Log(exception.ToString());
+ Log(string.Format(format, args));
+ }
+
+ public void Warn(Exception exception)
+ {
+ Log(exception.ToString());
+ }
+
+ public void Warn(string format, params object[] args)
+ {
+ Log(string.Format(format, args));
+ }
+
+ public void Warn(Exception exception, string format, params object[] args)
+ {
+ Log(exception.ToString());
+ Log(string.Format(format, args));
+ }
+
+ private static string _logPath = "log.txt";
+
+ public static void Log(string message)
+ {
+ System.IO.File.WriteAllText(_logPath, string.Format("{0} | {1}", DateTime.Now, message));
+ }
+ }
+}
diff --git a/DataCenter_Windows/WindowsDataCenter/CardReaderService/NinjectConfig.xml b/DataCenter_Windows/WindowsDataCenter/CardReaderService/NinjectConfig.xml
index 71ad73d..e9e7cb1 100644
--- a/DataCenter_Windows/WindowsDataCenter/CardReaderService/NinjectConfig.xml
+++ b/DataCenter_Windows/WindowsDataCenter/CardReaderService/NinjectConfig.xml
@@ -1,5 +1,5 @@
+ to="CardReaderService.DefaultComponents.LogFileLogger, CardReaderService" scope="singleton" />
\ No newline at end of file
diff --git a/DataCenter_Windows/WindowsDataCenter/CardReaderService/packages.config b/DataCenter_Windows/WindowsDataCenter/CardReaderService/packages.config
index 4bf2383..ac42eb0 100644
--- a/DataCenter_Windows/WindowsDataCenter/CardReaderService/packages.config
+++ b/DataCenter_Windows/WindowsDataCenter/CardReaderService/packages.config
@@ -1,7 +1,7 @@
-
-
-
-
+
+
+
+
\ No newline at end of file
diff --git a/DataCenter_Windows/WindowsDataCenter/CardReaderServiceHost/App.config b/DataCenter_Windows/WindowsDataCenter/CardReaderServiceHost/App.config
index 6fda695..ed16304 100644
--- a/DataCenter_Windows/WindowsDataCenter/CardReaderServiceHost/App.config
+++ b/DataCenter_Windows/WindowsDataCenter/CardReaderServiceHost/App.config
@@ -1,10 +1,18 @@
-
+
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DataCenter_Windows/WindowsDataCenter/ConfigurationHandler/ConfigurationHandler.csproj b/DataCenter_Windows/WindowsDataCenter/ConfigurationHandler/ConfigurationHandler.csproj
index 461434d..456c1dc 100644
--- a/DataCenter_Windows/WindowsDataCenter/ConfigurationHandler/ConfigurationHandler.csproj
+++ b/DataCenter_Windows/WindowsDataCenter/ConfigurationHandler/ConfigurationHandler.csproj
@@ -9,8 +9,9 @@
Properties
ConfigurationHandler
ConfigurationHandler
- v4.5.2
+ v4.5
512
+
true
diff --git a/DataCenter_Windows/WindowsDataCenter/Interfaces/IRepository.cs b/DataCenter_Windows/WindowsDataCenter/Interfaces/IRepository.cs
index e5e4f59..63402ab 100644
--- a/DataCenter_Windows/WindowsDataCenter/Interfaces/IRepository.cs
+++ b/DataCenter_Windows/WindowsDataCenter/Interfaces/IRepository.cs
@@ -1,114 +1,116 @@
-using System;
-using System.Collections.Generic;
-
-namespace Interfaces
-{
- public interface IRepository
- {
- ///
- /// Get a list of Users
- ///
- ///
- /// Returns with full list of users,
- /// plus a total user count. Pagination options are supported.
- ///
- UserList GetUsers(int pageNumber = -1, int pageSize = -1, int groupId = -1);
- ///
- /// Search the user list for the following string
- ///
- /// string to search the user store for.
- ///
- /// Returns with full list of users,
- /// plus a total user count. Pagination options are supported.
- ///
- UserList Search(string searchParam);
- ///
- /// Get details about a single user in the system base on their Id
- ///
- ///
- /// integer data type, the Id of the User to get details about.
- ///
- /// object with full details,
- /// including full
- ///
- User GetUser(int id);
- ///
- /// Get a list of the timelogs available for the specified user
- /// for the current Calendar Week
- ///
- ///
- /// integer data type, the Id of the user to get time logs for
- ///
- ///
- /// with nested objects
- /// for the current calendar week
- ///
- TimeLogList GetTimeLogs(int userId);
- ///
- /// Get a list of the timelogs available for the specified user
- /// for the specified calendar week
- ///
- ///
- /// integer data type, the Id of the user to get time logs for
- ///
- ///
- /// datetime data type, the date to receive time logs for (will scope out to calendar week).
- ///
- ///
- /// with nested objects
- /// for the current calendar week
- ///
- TimeLogList GetTimeLogs(int userId, DateTime selectedDate);
- ///
- /// Get a full list of Identifiers which are not associated to a user.
- ///
- ///
- /// with nested list
- ///
- IdentifierList GetUnassignedIdentifierList();
- ///
- /// Remove all unassigned identifiers from the system.
- ///
- void ClearUnassignedIdentifiers();
-
- ///
- /// Update a user in the system with the new values.
- ///
- ///
- /// If the user object passed does not exist, it will be created.
- ///
- ///
- /// object detailing the new properties to assign to the user.
- /// The Id Field should not be changed, or should be -1 for new users.
- ///
- ///
- /// int - ref param, value will be the UserId of the inserted or updated user
- ///
- ///
- /// to indicate procedure status.
- ///
- OperationResponse UpdateUser(User user, out int userId);
-
- ///
- /// Create a new TimeLog Event in the repository.
- ///
- ///
- /// object with the Unique Id triggering the event
- ///
- /// The resultant Id of the inserted TimeLog
- ///
- /// to indicate procedure status.
- ///
- LogEventResponse LogEventTime(Identifier identifier, out int logId);
-
- OperationResponse CreateGroup(Group group, out int groupId);
- List GetGroups(int userId = -1);
- Group GetGroup(int groupId);
- OperationResponse UpdateGroup(Group group);
- OperationResponse DeleteGroup(int groupId);
-
- OperationResponse DeleteLog(TimeLog log);
- OperationResponse CreateLog(TimeLog log);
- OperationResponse UpdateLog(TimeLog log);
- }
-}
+using System;
+using System.Collections.Generic;
+
+namespace Interfaces
+{
+ public interface IRepository
+ {
+ ///
+ /// Get a list of Users
+ ///
+ ///
+ /// Returns with full list of users,
+ /// plus a total user count. Pagination options are supported.
+ ///
+ UserList GetUsers(int pageNumber = -1, int pageSize = -1, int groupId = -1);
+ ///
+ /// Search the user list for the following string
+ ///
+ /// string to search the user store for.
+ ///
+ /// Returns with full list of users,
+ /// plus a total user count. Pagination options are supported.
+ ///
+ UserList Search(string searchParam);
+ ///
+ /// Get details about a single user in the system base on their Id
+ ///
+ ///
+ /// integer data type, the Id of the User to get details about.
+ ///
+ /// object with full details,
+ /// including full
+ ///
+ User GetUser(int id);
+ ///
+ /// Get a list of the timelogs available for the specified user
+ /// for the current Calendar Week
+ ///
+ ///
+ /// integer data type, the Id of the user to get time logs for
+ ///
+ ///
+ /// with nested objects
+ /// for the current calendar week
+ ///
+ TimeLogList GetTimeLogs(int userId);
+ ///
+ /// Get a list of the timelogs available for the specified user
+ /// for the specified calendar week
+ ///
+ ///
+ /// integer data type, the Id of the user to get time logs for
+ ///
+ ///
+ /// datetime data type, the date to receive time logs for (will scope out to calendar week).
+ ///
+ ///
+ /// with nested objects
+ /// for the current calendar week
+ ///
+ TimeLogList GetTimeLogs(int userId, DateTime selectedDate);
+ ///
+ /// Get a full list of Identifiers which are not associated to a user.
+ ///
+ ///
+ /// with nested list
+ ///
+ IdentifierList GetUnassignedIdentifierList();
+ ///
+ /// Remove all unassigned identifiers from the system.
+ ///
+ void ClearUnassignedIdentifiers();
+
+ ///
+ /// Update a user in the system with the new values.
+ ///
+ ///
+ /// If the user object passed does not exist, it will be created.
+ ///
+ ///
+ /// object detailing the new properties to assign to the user.
+ /// The Id Field should not be changed, or should be -1 for new users.
+ ///
+ ///
+ /// int - ref param, value will be the UserId of the inserted or updated user
+ ///
+ ///
+ /// to indicate procedure status.
+ ///
+ OperationResponse UpdateUser(User user, out int userId);
+
+ ///
+ /// Create a new TimeLog Event in the repository.
+ ///
+ ///
+ /// object with the Unique Id triggering the event
+ ///
+ /// The resultant Id of the inserted TimeLog
+ /// Optional - To set the log time of the swipe.
+ /// Particularly useful for buffering logs in nodes if they cannot contact server for whatever reason to minimise data loss
+ ///
+ /// to indicate procedure status.
+ ///
+ LogEventResponse LogEventTime(Identifier identifier, out int logId, DateTime logTime = default(DateTime));
+
+ OperationResponse CreateGroup(Group group, out int groupId);
+ List GetGroups(int userId = -1);
+ Group GetGroup(int groupId);
+ OperationResponse UpdateGroup(Group group);
+ OperationResponse DeleteGroup(int groupId);
+
+ OperationResponse DeleteLog(TimeLog log);
+ OperationResponse CreateLog(TimeLog log);
+ OperationResponse UpdateLog(TimeLog log);
+ }
+}
diff --git a/DataCenter_Windows/WindowsDataCenter/Interfaces/Interfaces.csproj b/DataCenter_Windows/WindowsDataCenter/Interfaces/Interfaces.csproj
index 2a53dee..84f5ae8 100644
--- a/DataCenter_Windows/WindowsDataCenter/Interfaces/Interfaces.csproj
+++ b/DataCenter_Windows/WindowsDataCenter/Interfaces/Interfaces.csproj
@@ -9,8 +9,9 @@
Properties
Interfaces
Interfaces
- v4.5.2
+ v4.5
512
+
true
diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs
index 29f6716..67ca87a 100644
--- a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs
+++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs
@@ -1,889 +1,901 @@
-using System;
-using System.Collections.Generic;
-using System.Globalization;
-using System.IO;
-using System.Linq;
-using System.Net;
-using System.Reflection;
-using Interfaces;
-using SQLite.Net;
-using SQLite.Net.Platform.Win32;
-using SQLiteRepository.Converters;
-using SQLiteRepository.Extensions;
-using SQLiteRepository.Properties;
-
-namespace SQLiteRepository
-{
- public class SQLiteRepository : IRepository
- {
- private readonly SQLiteConnection _connection;
- private readonly ILogger _logger;
- private readonly string _path;
- private const string DATABASE_NAME = "flexitimedb.db";
- private const string UPGRADE_SCRIPT_PREFIX = "SQLiteRepository.UpgradeScripts.";
-
- public SQLiteRepository(ILogger logger)
- {
- _path =
- new Uri(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().CodeBase), DATABASE_NAME))
- .LocalPath;
- if (logger == null) throw new ArgumentNullException(nameof(logger));
- _logger = logger;
-
- _connection = new SQLiteConnection(new SQLitePlatformWin32(), _path);
-
- _connection.CreateTable();
- _connection.CreateTable();
- _connection.CreateTable();
- _connection.CreateTable();
- _connection.CreateTable();
- _connection.CreateTable();
- _logger.Trace("Initialised SQLite Repository");
- _logger.Trace("Checking For Upgrades");
- CheckForDbUpgrade();
- }
-
- public UserList GetUsers(int pageNumber = -1, int pageSize = -1, int groupId = -1)
- {
- var ret = new UserList();
- List users = GetUserList(groupId, pageSize, pageNumber);
-
- var userCount = GetUserCount();
-
- if (pageNumber == -1 && pageSize == -1)
- {
- ret.PageNumber = 1;
- ret.PageSize = 20;
- }
- else
- {
- ret.PageNumber = pageNumber;
- ret.PageSize = pageSize;
- }
-
- if (!users.Any())
- {
- return ret;
- }
-
- foreach (var user in users)
- {
- var userObj = UserConverter.ConvertToUserDto(user);
-
- userObj.AssociatedIdentifiers = GetAssociatedIdentifiers(user.Id);
- userObj.State = GetUserState(GetLogDirection(user.Id));
- userObj.LastEventDateTime = GetLastLogDateTime(GetLastTimeLog(user.Id));
- userObj.Groups = GetGroups(user.Id);
- ret.Users.Add(userObj);
- }
-
- ret.TotalUserCount = userCount;
- return ret;
- }
-
- public UserList Search(string searchParam)
- {
- _logger.Trace("Searching SQLite database for the term: {0}", searchParam);
- var ret = new UserList();
- searchParam = string.Format("%{0}%", searchParam);
- var users = _connection.Query(
- SQLiteProcedures.SEARCH_USER_LIST,
- searchParam, searchParam);
-
- _logger.Trace("Got {0} results for term: {1}", users.Count, searchParam);
- if (!users.Any())
- {
- ret.PageNumber = 1;
- ret.PageSize = 20;
- return ret;
- }
-
- foreach (var user in users)
- {
- var userObj = UserConverter.ConvertToUserDto(user);
- var cards = _connection.Query(
- SQLiteProcedures.GET_CARDS_BY_USER_ID,
- user.Id);
-
- foreach (var card in cards)
- {
- userObj.AssociatedIdentifiers.Add(IdentifierConverter.ConvertToIdentifierDto(card));
- }
- userObj.State = GetUserState(GetLogDirection(user.Id));
- ret.Users.Add(userObj);
- }
- ret.PageSize = 20;
- ret.PageNumber = (int)Math.Ceiling((double)ret.Users.Count/(double)ret.PageSize);
-
- return ret;
- }
-
- public User GetUser(int id)
- {
- var ret = new User();
-
- try
- {
- var users = _connection.Query(
- SQLiteProcedures.GET_USER_BY_ID,
- id);
-
- if (!users.Any()) return ret;
-
- var user = users.First();
- ret = UserConverter.ConvertToUserDto(user);
- ret.Groups = GetGroups();
- var usersGroups = GetGroups(user.Id);
- foreach (var group in usersGroups)
- {
- ret.Groups.First(x => x.Id == group.Id).IsAssociatedToUser = true;
- }
- var cards = _connection.Query(
- SQLiteProcedures.GET_CARDS_BY_USER_ID,
- user.Id);
-
- foreach (var card in cards)
- {
- ret.AssociatedIdentifiers.Add(IdentifierConverter.ConvertToIdentifierDto(card));
- }
- }
- catch (Exception ex)
- {
- _logger.Error(ex, "Error in GetUser with Id: {0}", id);
- ret.UserId = id;
- ret.FirstName = ret.LastName = string.Empty;
- ret.HoursPerWeek = -1.0f;
- ret.IsContractor = false;
- ret.AssociatedIdentifiers.Clear();
- }
-
- return ret;
- }
-
- public TimeLogList GetTimeLogs(int userId)
- {
- return GetTimeLogs(userId, DateTime.UtcNow);
- }
-
- public TimeLogList GetTimeLogs(int userId, DateTime selectedDate)
- {
- var ret = new TimeLogList { SelectedDate = selectedDate.Date };
- var calendarWeek = GetIso8601CalendarWeek(selectedDate);
- ret.CalendarWeek = calendarWeek;
-
- try
- {
- ret.TimeLogs = GetTimeLogList(userId, calendarWeek, selectedDate.Year);
- }
- catch (Exception ex)
- {
- _logger.Error(ex, "Error in GetTimeLogs with Id: {0} and selected date: {1}, Exception: {2}", userId, selectedDate, ex);
- }
-
- try
- {
- ret.HoursPerWeekMinutes = GetUserContractedHours(userId) * 60.0f;
- }
- catch (Exception ex)
- {
- _logger.Error(ex, "Error in GetUserContracterHours with Id: {0} and selected date: {1}, Exception: {2}", userId, selectedDate, ex);
- }
-
- ret.UserInformation = GetUser(userId);
- return ret;
- }
-
- private float GetUserContractedHours(int userId)
- {
- var hoursQuery = _connection.Query(SQLiteProcedures.GET_USER_CONTRACTED_HOURS, userId);
- if (hoursQuery.Any())
- {
- return hoursQuery.First().HoursPerWeek;
- }
- return -1.0f;
- }
-
- public IdentifierList GetUnassignedIdentifierList()
- {
- var ret = new IdentifierList();
- var cardQuery = _connection.Query(
- SQLiteProcedures.GET_UNASSIGNED_CARD_LIST,
- Constants.UNASSIGNED_CARD_USER_ID);
-
- foreach (var card in cardQuery)
- {
- ret.data.Add(IdentifierConverter.ConvertToIdentifierDto(card));
- // new Identifier
- //{
- // Id = card.Id,
- // IsAssociatedToUser = card.UserId_FK != Constants.UNASSIGNED_CARD_USER_ID,
- // UniqueId = card.CardUId,
- // LastUsed = card.LastUsed.DateTime
- //});
- }
- return ret;
- }
-
- public void ClearUnassignedIdentifiers()
- {
- var unassignedIdentifiers = _connection.Query(SQLiteProcedures.GET_UNASSIGNED_CARD_LIST);
-
- //remove the logs from the timelog db
- _connection.Query(
- SQLiteProcedures.FormatInQuery(SQLiteProcedures.DELETE_TIMELOG_ENTRIES,
- unassignedIdentifiers.Select(x => x.Id.ToString()).ToList()));
-
- //now remove the unassigned identifiers/cards
- _connection.Execute(
- SQLiteProcedures.CLEAR_UNASSIGNED_CARDS,
- Constants.UNASSIGNED_CARD_USER_ID);
- }
-
- public OperationResponse UpdateUser(User user, out int userIdResult)
- {
- var ret = OperationResponse.NONE;
- //Get a list of current associated identifiers, convert into a list of Identifier Objects..
- var currentCards =
- _connection.Query(SQLiteProcedures.GET_CARDS_BY_USER_ID, user.UserId)
- .Select(IdentifierConverter.ConvertToIdentifierDto).ToList();
- var cardsToRemove = currentCards.Exclude(user.AssociatedIdentifiers, x => x.Id).Select(x => x.Id).ToList();
-
- #region Update/Create User
- int userId;
-
- if (user.UserId != -1)
- {
- UpdateUserDetails(user.FirstName, user.LastName, user.HoursPerWeek, user.IsContractor, user.UserId);
- userId = user.UserId;
- }
- else
- {
- var userInsert = UserConverter.ConvertFromUserDto(user);
- _connection.Insert(userInsert);
- userId = userInsert.Id;
- if (ret < OperationResponse.CREATED)
- ret = OperationResponse.CREATED;
- }
- #endregion
-
- #region GetUnique Identifiers
-
- var existingCards = _connection.Query(SQLiteProcedures.FormatInQuery(
- SQLiteProcedures.GET_CARDS_BY_UNIQUE_ID_LIST,
- user.AssociatedIdentifiers.Select(x => x.UniqueId.ToString()).ToList()));
-
- foreach (var card in user.AssociatedIdentifiers)
- {
- if (existingCards.All(x => x.CardUId != card.UniqueId))
- {
- //this card is not currently in the system..
- var cardInsert = IdentifierConverter.ConvertFromIdentifierDto(card, user.UserId);
- _connection.Insert(cardInsert);
- existingCards.Add(cardInsert);
- if (ret < OperationResponse.CREATED)
- ret = OperationResponse.CREATED; //only change it if my status supercedes.
- }
- }
- #endregion
-
- #region Update Card/Unique Id entries/associations
- //make sure all identifiers are associated to the right user
- UpdateIdentifierUserId(existingCards.Select(x=>x.Id).ToList(), userId);
-
- //make sure to remove all identifiers that have been deselected in edit are removed from user
- UpdateIdentifierUserId(cardsToRemove, Constants.UNASSIGNED_CARD_USER_ID);
- #endregion
-
- #region Update Group Associations
-
- SetUserGroups(userId, user.Groups.Where(x => x.IsAssociatedToUser).ToList());
-
- #endregion
-
- userIdResult = userId;
- return ret;
- }
-
- public LogEventResponse LogEventTime(Identifier identifier, out int logId)
- {
- var ret = new LogEventResponse();
- var cardIdQuery = _connection.Query(
- SQLiteProcedures.GET_CARDS_BY_UNIQUE_ID,
- identifier.UniqueId);
-
- #region Get/Insert the PK Id Identifier to associate the time log to.
- var ident = new CardUniqueId();
- if (!cardIdQuery.Any())
- {
- //new card, create it!
- ident.UserId_FK = -1;
- ident.CardUId = identifier.UniqueId;
- _connection.Insert(ident);
- UpdateIdentifierLastUsed(DateTimeOffset.UtcNow, ident.Id);
- logId = -1;
- //dont try to log any timelogs against this card, as it is unassigned to a user.
- ret.ProcessResponse=OperationResponse.SUCCESS;
- ret.Direction = LogDirection.UNKNOWN;
- return ret;
- }
-
- ident = cardIdQuery.First();
- _logger.Warn("More than 1 Identifier returned with ID {0}, card ids returned: {2}",
- ident.CardUId,
- string.Join(",", cardIdQuery.Select(x => x.CardUId).ToList()));
- #endregion
-
- // Get The User Direction (are they going in or out)?
- var logDirection = GetLogDirection(ident.UserId_FK);
-
- #region Check the user hasnt registered an event in the last few minutes..
-
- if (ident.UserId_FK != -1)
- { //only check log gap if the card is associated to a user
- var hysteresisThresholdMinutes = Convert.ToInt32(ConfigurationHandler.ConfigurationHandler.GetConfiguration("SwipeTimeGap") ?? "3");
- var threshold = DateTime.UtcNow.AddMinutes(0 - hysteresisThresholdMinutes);
- var logs = _connection.Query(
- SQLiteProcedures.GET_LOGS_IN_LAST_X_MINUTES,
- threshold.Ticks, ident.UserId_FK);
- _logger.Trace("Checking last swipe event gap");
- if (logs.Any())
- {
- _logger.Error("Not logging event for user id: {0}, logged event within TimeGap Threshold of {1}", ident.UserId_FK, threshold);
- logId = -1;
- ret.ProcessResponse = OperationResponse.FAILED;
- ret.Direction = LogDirection.UNKNOWN;
- return ret;
- }
- }
-
- #endregion
-
- #region Get the current time (for swiping). and calendar week/year to help recall the data.
- var logTime = DateTime.UtcNow;
- var calendarWeek = GetIso8601CalendarWeek(logTime);
- var year = logTime.Year;
- #endregion
-
- var timeLog = new TimeLogDb
- {
- SwipeEventDateTime = DateTime.UtcNow,
- UserId_FK = ident.UserId_FK,
- IdentifierId = ident.Id,
- Direction = logDirection,
- Year = year,
- CalendarWeek = calendarWeek,
- Source = LogSourceDb.IDENTIFIER
- };
-
- _connection.Insert(timeLog);
- UpdateIdentifierLastUsed(timeLog.SwipeEventDateTime, timeLog.IdentifierId);
-
- logId = timeLog.Id;
- ret.Direction = (LogDirection)(int)logDirection;
- ret.ProcessResponse = OperationResponse.SUCCESS;
- return ret;
- }
-
- public OperationResponse CreateGroup(Group group, out int groupId)
- {
- var query = _connection.Query(SQLiteProcedures.GET_GROUP_BY_NAME, group.Name);
- if (query.Any())
- {
- groupId = query[0].GroupId;
- return OperationResponse.NONE;
- }
- var groupDb = new GroupDb { GroupName = group.Name };
- var resp = _connection.Insert(groupDb);
- groupId = groupDb.GroupId;
- return OperationResponse.CREATED;
- }
-
- public List GetGroups(int userId = -1)
- {
- var ret = new List();
- List query;
- if (userId == -1)
- {
- query = _connection.Query(SQLiteProcedures.GET_GROUPS);
- }
- else
- {
- query =
- _connection.Query(SQLiteProcedures.GET_GROUPS_FOR_USER,
- userId);
- }
- foreach (var group in query)
- {
- ret.Add(new Group
- {
- Id = group.GroupId,
- Name = group.GroupName,
- UserCount = int.Parse(group.AssignedUserCount ?? "0")
- });
- }
- return ret;
- }
-
- public Group GetGroup(int groupId)
- {
- var query = _connection.Query(SQLiteProcedures.GET_GROUP_BY_ID, groupId);
- if (query.Any())
- {
- var group = query.First();
- return new Group
- {
- Id = group.GroupId,
- Name = group.GroupName,
- UserCount = 0
- };
- }
- return new Group();
- }
-
- public OperationResponse UpdateGroup(Group group)
- {
- _connection.Query(SQLiteProcedures.UPDATE_GROUP, @group.Name, @group.Id);
-
- return OperationResponse.UPDATED;
- }
-
- public OperationResponse DeleteGroup(int groupId)
- {
- _connection.Delete(groupId);
- return OperationResponse.DELETED;
- }
-
- public OperationResponse DeleteLog(TimeLog log)
- {
- var query = _connection.Query(
- SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id);
-
- if (!query.Any())
- return OperationResponse.FAILED;
-
- UpdateExistingLogDirections(log);
-
- _connection.ExecuteScalar(SQLiteProcedures.DELETE_TIMELOG_ENTRY, log.Id);
-
- return OperationResponse.DELETED;
- }
-
- public OperationResponse CreateLog(TimeLog log)
- {
- log.CalendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime);
- log.Year= log.EventTime.Year;
-
- var dbLog = TimeLogConverter.ConvertFromTimeLogDto(log);
- dbLog.IdentifierId = ConvertSourceToIdentifierId(log.Source);
-
- #region update in/out directions for manual logs.
- UpdateExistingLogDirections(log);
- #endregion
- //and now insert the new log.
- _connection.Insert(dbLog);
- return OperationResponse.CREATED;
- }
-
- public OperationResponse UpdateLog(TimeLog log)
- {
- var query = _connection.Query(
- SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id);
-
- if(!query.Any())
- return OperationResponse.FAILED;
-
- if (log.CalendarWeek > 52 || log.CalendarWeek < 1)
- {
- log.CalendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime);
- }
- if (log.Year < 2017)
- {
- log.Year = log.EventTime.Year;
- }
- _connection.ExecuteScalar(
- SQLiteProcedures.UPDATE_TIMELOG_ENTRY,
- log.UserId, (LogDirectionDb) (int) log.Direction, log.EventTime, log.CalendarWeek, log.Year,
- (LogSourceDb) (int) log.Source, log.Id);
-
- return OperationResponse.UPDATED;
- }
-
- private int GetUserCount()
- {
- return _connection.ExecuteScalar(SQLiteProcedures.GET_TOTAL_USER_COUNT);
- }
-
- private List GetUserList(int groupId = -1, int pageSize=-1, int pageNumber=-1)
- {
- List users;
- if (pageNumber != -1 && pageSize != -1)
- {
- users = _connection.Query(SQLiteProcedures.GET_ALL_USERS_PAGINATE,
- pageSize, (pageNumber - 1) * pageSize);
- }
- else if (groupId != -1)
- {
- users =
- _connection.Query(
- SQLiteProcedures.GET_ALL_USERS_BY_GROUP,
- groupId);
- }
- else
- {
- users = _connection.Query(SQLiteProcedures.GET_ALL_USERS);
- }
-
- return users;
- }
-
- private void CheckForDbUpgrade()
- {
- var data = _connection.Query(SQLiteProcedures.GET_DB_VERSION);
- if (!data.Any())
- {
- //Pre-Upgrade database, need upgrading
- _logger.Trace("Pre version 0.2 RC database found, performing update..");
- ExecuteUpgradeFromVersion("0.1"); //execute 0.2 upgrade scripts onwards.
- }
- else
- {
- var installedVersion = new Version(data.First().VersionNumber);
- var currentVersion = new Version(AssemblyInfo.ASSEMBLY_VERSION);
- if (currentVersion.CompareTo(installedVersion) > 0) //greater than 0 - current version is newer
- {
- _logger.Trace("Installed Database Version: {0} is older than current version {1}");
- ExecuteUpgradeFromVersion(installedVersion.ToString());
- }
- }
- }
-
- private void ExecuteUpgradeFromVersion(string installedVersion)
- {
- var instVers = new Version(installedVersion);
- //so we have established that each script for upgrade will be .sql, so now start at lowest version and work up!
- var assembly = Assembly.GetExecutingAssembly();
- var upgradeScripts = assembly.GetManifestResourceNames()
- .Where(x => x.StartsWith(UPGRADE_SCRIPT_PREFIX))
- .OrderBy(x =>
- new Version(Path.GetFileNameWithoutExtension(x.Replace(UPGRADE_SCRIPT_PREFIX, string.Empty))))
- .Where(x =>
- {
- var scriptVersion =
- new Version(Path.GetFileNameWithoutExtension(x.Replace(UPGRADE_SCRIPT_PREFIX, string.Empty)))
- .CompareTo(instVers);
- return scriptVersion > 0;
- })
- .ToList();
- //now have an ordered list of upgrade script files, so execute in order!
- foreach (var upgradeScript in upgradeScripts)
- {
- using (var stream = assembly.GetManifestResourceStream(upgradeScript))
- using(var str = new StreamReader(stream))
- {
- var script = str.ReadToEnd();
- _logger.Trace("Executing upgrade script with name: {0}", upgradeScript);
- _connection.Execute(script);
- }
- }
- SetDbVersion(AssemblyInfo.ASSEMBLY_VERSION);
- }
-
- private void SetDbVersion(string vers)
- {
- _connection.DeleteAll();
- _connection.Insert(new DbVersion {VersionNumber = vers});
- _logger.Trace("Set Database version to: {0}", vers);
- }
-
- private DateTime GetLastLogDateTime(TimeLogDb timeLog)
- {
- if (timeLog != null)
- {
- return timeLog.SwipeEventDateTime.DateTime;
- }
- return DateTime.MinValue;
- }
-
- private bool GetUserState(LogDirectionDb logDirection)
- {
- switch (logDirection)
- {
- case LogDirectionDb.OUT:
- return true;
- default:
- return false;
- }
- }
-
- private int ConvertSourceToIdentifierId(LogSource logSource)
- {
- switch (logSource)
- {
- case LogSource.UI:
- return -100;
- case LogSource.TRAYAPP:
- return -200;
- default:
- return -10;
- }
- }
-
- private bool SetUserGroups(int userId, List groups)
- {
- var groupIds = GetGroupIds(groups.Select(x => x.Name).ToList());
- return SetUserGroups(userId, groupIds);
- }
-
- private bool SetUserGroups(int userId, int[] groupIds)
- {
- //remove the existing user>group associations
- _connection.Query("delete from UserGroupJoinDb where UserId_FK = ?", userId);
- //add the new group associations.
- _connection.InsertAll(groupIds.Select(x => new UserGroupJoinDb { GroupId_FK = x, UserId_FK = userId }));
- return true;
- }
-
- private int[] GetGroupIds(List groupNames)
- {
- var ret = new List();
-
- foreach (var g in groupNames)
- {
- var query = _connection.Query("select GroupId from GroupDb where GroupName=?", g);
- if (!query.Any()) continue;
- var id = query.First();
- ret.Add(id.GroupId);
- }
- return ret.ToArray();
- }
-
- private List GetTimeLogList(int userId, int calendarWeek, int year)
- {
- var timeLogList = _connection.Query(
- SQLiteProcedures.GET_TIMELOGS,
- userId, calendarWeek, year);
-
- var timeLogs = timeLogList.Select(x => new TimeLog
- {
- Id = x.Id,
- CalendarWeek = x.CalendarWeek,
- Direction = (LogDirection)x.Direction,
- IdentifierId = x.IdentifierId,
- EventTime = x.SwipeEventDateTime,
- UserId = x.UserId_FK,
- Year = x.Year
- }).OrderBy(x=>x.EventTime.UtcDateTime).ToList();
-
- var dict = new Dictionary();
- var logList = new List();
-
- //make sure each day of the week is accounted for in the dictionary.
- foreach (DayOfWeek day in Enum.GetValues(typeof(DayOfWeek)))
- {
- dict.Add(day, new DailyLogs());
- }
-
- //add the logs to the respective day of the week.
- foreach (var log in timeLogs.OrderBy(x=>x.EventTime))
- {
- dict[log.EventTime.DayOfWeek].Logs.Add(log);
- }
- var logGroups = timeLogs.GroupBy(x => x.EventTime.DayOfWeek);
- foreach (var group in logGroups)
- {
- var groupLogs = group.ToList();
- var dailyLog = new DailyLogs
- {
- Logs = groupLogs,
- Day = group.Key,
- DayOfWeek = group.Key.ToString()
- };
- dailyLog.DailyTotal = CalculateDailyTotal(dailyLog);
- logList.Add(dailyLog);
- }
- foreach (DayOfWeek day in Enum.GetValues(typeof(DayOfWeek)))
- {
- if (logList.Any(x => x.Day == day)) continue;
- var dailyLog = new DailyLogs { Day = day, DayOfWeek = day.ToString() };
- logList.Add(dailyLog);
- }
-
- foreach (var dailyCollection in dict)
- {
- dailyCollection.Value.DailyTotal = CalculateDailyTotal(dailyCollection.Value);
- }
-
- return logList.OrderBy(x => ((int)x.Day + 6) % 7).ToList();
- }
-
- private double CalculateDailyTotal(DailyLogs dailyLogs)
- {
- var totalInTime = TimeSpan.FromSeconds(0);
- var logs = dailyLogs.Logs.OrderBy(x => x.EventTime.UtcDateTime).ToArray();
- var totalCalcMax = IsOdd(logs.Length) ? logs.Length - 1 : logs.Length;
- for (int i = 0; i < totalCalcMax; i += 2)
- {
- totalInTime += (logs[i + 1].EventTime - logs[i].EventTime);
- }
- return Math.Round(totalInTime.TotalMinutes, 2);
- }
-
- ///
- /// determines if the number is an odd or even value
- ///
- /// number to determine is odd or even
- /// true - number is odd
- private bool IsOdd(int value)
- {
- return value % 2 != 0;
- }
-
- ///
- /// Get the new direction for the user based on previous entry logs in the system.
- ///
- ///
- /// If the user has not logged in today, the direction will be In.
- /// If the user has logged in already today, the direction will be the opposite of the last
- /// recorded log direction. ("out" if "in", "in" if "out")
- ///
- /// Id of the user to get the log direction of.
- /// indicating what direction the new log is.
- private LogDirectionDb GetLogDirection(int userId)
- {
- var logDirection = LogDirectionDb.UNKNOWN;
- if (userId != -1)
- {
- var lastEntry = GetLastTimeLog(userId);
- if (lastEntry != null)
- {
- // See if the datetime retrieved is yesterday. If yesterday, logDirection = true (in)
- if (IsLogDateTimeYesterdayOrOlder(lastEntry.SwipeEventDateTime.DateTime))
- {
- logDirection = LogDirectionDb.IN;
- }
- else
- {
- // we have a time log from today already, so just do the opposite of what we last did!
- logDirection = LogDirectionConverter.InvertLogDirectionDb(lastEntry.Direction);
- }
- }
- else
- {
- //assume its the first then!
- logDirection = LogDirectionDb.IN;
- }
- }
- return logDirection;
- }
-
- private TimeLogDb GetLastTimeLog(int userId)
- {
- var lastEntry = _connection.Query(
- SQLiteProcedures.GET_LAST_TIMELOG_DIRECTION,
- userId);
- if (lastEntry.Any())
- {
- return lastEntry.First();
- }
- return null;
- }
-
- private void UpdateIdentifierLastUsed(DateTimeOffset dt, int cardId)
- {
- _connection.ExecuteScalar(SQLiteProcedures.UPDATE_CARD_LAST_USED,
- dt,
- cardId);
- }
-
- private List GetAssociatedIdentifiers(int userId)
- {
- var cards = _connection.Query(
- SQLiteProcedures.GET_CARDS_BY_USER_ID,
- userId);
- var ret = new List();
- foreach (var card in cards)
- {
- ret.Add(new Identifier()
- {
- UniqueId = card.CardUId,
- IsAssociatedToUser = true,
- Id = card.Id
- });
- }
- return ret;
- }
-
- ///
- /// Get the calendar week of the year according to the ISO8601 standard (starts monday).
- ///
- /// the date to get the calendar week of.
- /// the calendar week of the year in integer form (1-52)
- private int GetIso8601CalendarWeek(DateTime date)
- {
- var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(date);
- if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
- {
- date = date.AddDays(3);
- }
- return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek,
- DayOfWeek.Monday);
- }
-
- ///
- /// Check whether the specified DateTime is from yesterday or older.
- ///
- /// the DateTime object to check is yesterday or older
- /// true - is yesterday or older.
- private bool IsLogDateTimeYesterdayOrOlder(DateTime dt)
- {
- return dt.Date.CompareTo(DateTime.Today.Date) < 0;
- }
-
- private void UpdateExistingLogDirections(TimeLog log)
- {
- //need to make this generic so that both create and delete will update the log directions.. but ARGH.
- //if you want to use this as a delete, you would delete and call this, if you want to create, call this then create.
- //should look at how to improve this method so that it will compensate for if the log hasnt been deleted yet, but ott?
- var weekLogs = GetTimeLogList(log.UserId, log.CalendarWeek, log.Year);
-
- //Get the same logs of the day that the log has been entered for
- var todaysLogs = weekLogs.FirstOrDefault(x => x.Day == log.EventTime.DayOfWeek);
- if (todaysLogs != null)
- {
- //Get the days logs that are after the manually created date
- var logs = todaysLogs.Logs.Where(x => x.EventTime.CompareTo(log.EventTime) >= 0).OrderBy(x => x.EventTime).ToList();
- //Update each log with the inverse progressively
- var currentlogDirection = log.Direction;
- for (var i = 0; i < logs.Count; i++)
- {
- logs[i].Direction = LogDirectionConverter.InvertLogDirection(currentlogDirection);
- UpdateLog(logs[i]);
- currentlogDirection = logs[i].Direction;
- }
- }
- }
-
- private void UpdateIdentifierUserId(List cardsToUpdate, int userId)
- {
- foreach (var card in cardsToUpdate)
- {
- _connection.Query(
- SQLiteProcedures.UPDATE_CARD_USER_ID,
- userId, card);
- }
- }
-
- private void UpdateUserDetails(string firstName, string lastName, float hoursPerWeek, bool isContractor,
- int userId)
- {
- _connection.Query(
- SQLiteProcedures.UPDATE_USER_DETAILS,
- firstName,
- lastName,
- hoursPerWeek,
- isContractor,
- userId
- );
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Reflection;
+using Interfaces;
+using SQLite.Net;
+using SQLite.Net.Platform.Win32;
+using SQLiteRepository.Converters;
+using SQLiteRepository.Extensions;
+using SQLiteRepository.Properties;
+
+namespace SQLiteRepository
+{
+ public class SQLiteRepository : IRepository
+ {
+ private readonly SQLiteConnection _connection;
+ private readonly ILogger _logger;
+ private readonly string _path;
+ private const string DATABASE_NAME = "flexitimedb.db";
+ private const string UPGRADE_SCRIPT_PREFIX = "SQLiteRepository.UpgradeScripts.";
+
+ public SQLiteRepository(ILogger logger)
+ {
+ _path =
+ new Uri(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().CodeBase), DATABASE_NAME))
+ .LocalPath;
+ if (logger == null) throw new ArgumentNullException(nameof(logger));
+ _logger = logger;
+
+ _connection = new SQLiteConnection(new SQLitePlatformWin32(), _path);
+
+ _connection.CreateTable();
+ _connection.CreateTable();
+ _connection.CreateTable();
+ _connection.CreateTable();
+ _connection.CreateTable();
+ _connection.CreateTable();
+ _logger.Trace("Initialised SQLite Repository");
+ _logger.Trace("Checking For Upgrades");
+ CheckForDbUpgrade();
+ }
+
+ public UserList GetUsers(int pageNumber = -1, int pageSize = -1, int groupId = -1)
+ {
+ var ret = new UserList();
+ List users = GetUserList(groupId, pageSize, pageNumber);
+
+ var userCount = GetUserCount();
+
+ if (pageNumber == -1 && pageSize == -1)
+ {
+ ret.PageNumber = 1;
+ ret.PageSize = 20;
+ }
+ else
+ {
+ ret.PageNumber = pageNumber;
+ ret.PageSize = pageSize;
+ }
+
+ if (!users.Any())
+ {
+ return ret;
+ }
+
+ foreach (var user in users)
+ {
+ var userObj = UserConverter.ConvertToUserDto(user);
+
+ userObj.AssociatedIdentifiers = GetAssociatedIdentifiers(user.Id);
+ userObj.State = GetUserState(GetLogDirection(user.Id));
+ userObj.LastEventDateTime = GetLastLogDateTime(GetLastTimeLog(user.Id));
+ userObj.Groups = GetGroups(user.Id);
+ ret.Users.Add(userObj);
+ }
+
+ ret.TotalUserCount = userCount;
+ return ret;
+ }
+
+ public UserList Search(string searchParam)
+ {
+ _logger.Trace("Searching SQLite database for the term: {0}", searchParam);
+ var ret = new UserList();
+ searchParam = string.Format("%{0}%", searchParam);
+ var users = _connection.Query(
+ SQLiteProcedures.SEARCH_USER_LIST,
+ searchParam, searchParam);
+
+ _logger.Trace("Got {0} results for term: {1}", users.Count, searchParam);
+ if (!users.Any())
+ {
+ ret.PageNumber = 1;
+ ret.PageSize = 20;
+ return ret;
+ }
+
+ foreach (var user in users)
+ {
+ var userObj = UserConverter.ConvertToUserDto(user);
+ var cards = _connection.Query(
+ SQLiteProcedures.GET_CARDS_BY_USER_ID,
+ user.Id);
+
+ foreach (var card in cards)
+ {
+ userObj.AssociatedIdentifiers.Add(IdentifierConverter.ConvertToIdentifierDto(card));
+ }
+ userObj.State = GetUserState(GetLogDirection(user.Id));
+ ret.Users.Add(userObj);
+ }
+ ret.PageSize = 20;
+ ret.PageNumber = (int)Math.Ceiling((double)ret.Users.Count/(double)ret.PageSize);
+
+ return ret;
+ }
+
+ public User GetUser(int id)
+ {
+ var ret = new User();
+
+ try
+ {
+ var users = _connection.Query(
+ SQLiteProcedures.GET_USER_BY_ID,
+ id);
+
+ if (!users.Any()) return ret;
+
+ var user = users.First();
+ ret = UserConverter.ConvertToUserDto(user);
+ ret.Groups = GetGroups();
+ var usersGroups = GetGroups(user.Id);
+ foreach (var group in usersGroups)
+ {
+ ret.Groups.First(x => x.Id == group.Id).IsAssociatedToUser = true;
+ }
+ var cards = _connection.Query(
+ SQLiteProcedures.GET_CARDS_BY_USER_ID,
+ user.Id);
+
+ foreach (var card in cards)
+ {
+ ret.AssociatedIdentifiers.Add(IdentifierConverter.ConvertToIdentifierDto(card));
+ }
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, "Error in GetUser with Id: {0}", id);
+ ret.UserId = id;
+ ret.FirstName = ret.LastName = string.Empty;
+ ret.HoursPerWeek = -1.0f;
+ ret.IsContractor = false;
+ ret.AssociatedIdentifiers.Clear();
+ }
+
+ return ret;
+ }
+
+ public TimeLogList GetTimeLogs(int userId)
+ {
+ return GetTimeLogs(userId, DateTime.UtcNow);
+ }
+
+ public TimeLogList GetTimeLogs(int userId, DateTime selectedDate)
+ {
+ var ret = new TimeLogList { SelectedDate = selectedDate.Date };
+ var calendarWeek = GetIso8601CalendarWeek(selectedDate);
+ ret.CalendarWeek = calendarWeek;
+
+ try
+ {
+ ret.TimeLogs = GetTimeLogList(userId, calendarWeek, selectedDate.Year);
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, "Error in GetTimeLogs with Id: {0} and selected date: {1}, Exception: {2}", userId, selectedDate, ex);
+ }
+
+ try
+ {
+ ret.HoursPerWeekMinutes = GetUserContractedHours(userId) * 60.0f;
+ }
+ catch (Exception ex)
+ {
+ _logger.Error(ex, "Error in GetUserContracterHours with Id: {0} and selected date: {1}, Exception: {2}", userId, selectedDate, ex);
+ }
+
+ ret.UserInformation = GetUser(userId);
+ return ret;
+ }
+
+ private float GetUserContractedHours(int userId)
+ {
+ var hoursQuery = _connection.Query(SQLiteProcedures.GET_USER_CONTRACTED_HOURS, userId);
+ if (hoursQuery.Any())
+ {
+ return hoursQuery.First().HoursPerWeek;
+ }
+ return -1.0f;
+ }
+
+ public IdentifierList GetUnassignedIdentifierList()
+ {
+ var ret = new IdentifierList();
+ var cardQuery = _connection.Query(
+ SQLiteProcedures.GET_UNASSIGNED_CARD_LIST,
+ Constants.UNASSIGNED_CARD_USER_ID);
+
+ foreach (var card in cardQuery)
+ {
+ ret.data.Add(IdentifierConverter.ConvertToIdentifierDto(card));
+ // new Identifier
+ //{
+ // Id = card.Id,
+ // IsAssociatedToUser = card.UserId_FK != Constants.UNASSIGNED_CARD_USER_ID,
+ // UniqueId = card.CardUId,
+ // LastUsed = card.LastUsed.DateTime
+ //});
+ }
+ return ret;
+ }
+
+ public void ClearUnassignedIdentifiers()
+ {
+ var unassignedIdentifiers = _connection.Query(SQLiteProcedures.GET_UNASSIGNED_CARD_LIST);
+
+ //remove the logs from the timelog db
+ _connection.Query(
+ SQLiteProcedures.FormatInQuery(SQLiteProcedures.DELETE_TIMELOG_ENTRIES,
+ unassignedIdentifiers.Select(x => x.Id.ToString()).ToList()));
+
+ //now remove the unassigned identifiers/cards
+ _connection.Execute(
+ SQLiteProcedures.CLEAR_UNASSIGNED_CARDS,
+ Constants.UNASSIGNED_CARD_USER_ID);
+ }
+
+ public OperationResponse UpdateUser(User user, out int userIdResult)
+ {
+ var ret = OperationResponse.NONE;
+ //Get a list of current associated identifiers, convert into a list of Identifier Objects..
+ var currentCards =
+ _connection.Query(SQLiteProcedures.GET_CARDS_BY_USER_ID, user.UserId)
+ .Select(IdentifierConverter.ConvertToIdentifierDto).ToList();
+ var cardsToRemove = currentCards.Exclude(user.AssociatedIdentifiers, x => x.Id).Select(x => x.Id).ToList();
+
+ #region Update/Create User
+ int userId;
+
+ if (user.UserId != -1)
+ {
+ UpdateUserDetails(user.FirstName, user.LastName, user.HoursPerWeek, user.IsContractor, user.UserId);
+ userId = user.UserId;
+ }
+ else
+ {
+ var userInsert = UserConverter.ConvertFromUserDto(user);
+ _connection.Insert(userInsert);
+ userId = userInsert.Id;
+ if (ret < OperationResponse.CREATED)
+ ret = OperationResponse.CREATED;
+ }
+ #endregion
+
+ #region GetUnique Identifiers
+
+ var existingCards = _connection.Query(SQLiteProcedures.FormatInQuery(
+ SQLiteProcedures.GET_CARDS_BY_UNIQUE_ID_LIST,
+ user.AssociatedIdentifiers.Select(x => x.UniqueId.ToString()).ToList()));
+
+ foreach (var card in user.AssociatedIdentifiers)
+ {
+ if (existingCards.All(x => x.CardUId != card.UniqueId))
+ {
+ //this card is not currently in the system..
+ var cardInsert = IdentifierConverter.ConvertFromIdentifierDto(card, user.UserId);
+ _connection.Insert(cardInsert);
+ existingCards.Add(cardInsert);
+ if (ret < OperationResponse.CREATED)
+ ret = OperationResponse.CREATED; //only change it if my status supercedes.
+ }
+ }
+ #endregion
+
+ #region Update Card/Unique Id entries/associations
+ //make sure all identifiers are associated to the right user
+ UpdateIdentifierUserId(existingCards.Select(x=>x.Id).ToList(), userId);
+
+ //make sure to remove all identifiers that have been deselected in edit are removed from user
+ UpdateIdentifierUserId(cardsToRemove, Constants.UNASSIGNED_CARD_USER_ID);
+ #endregion
+
+ #region Update Group Associations
+
+ SetUserGroups(userId, user.Groups.Where(x => x.IsAssociatedToUser).ToList());
+
+ #endregion
+
+ userIdResult = userId;
+ return ret;
+ }
+
+ public LogEventResponse LogEventTime(Identifier identifier, out int logId, DateTime logTime = default(DateTime))
+ {
+ #region Set the LogTime before we start querying anything.
+ if (logTime == default(DateTime))
+ {
+ logTime = DateTime.UtcNow;
+ _logger.Debug("Using own log time: {0}", logTime.ToString("o"));
+ }
+ else
+ {
+ _logger.Debug("Using supplied log time: {0}", logTime.ToString("o"));
+ }
+ #endregion
+
+ var ret = new LogEventResponse();
+ var cardIdQuery = _connection.Query(
+ SQLiteProcedures.GET_CARDS_BY_UNIQUE_ID,
+ identifier.UniqueId);
+
+ #region Get/Insert the PK Id Identifier to associate the time log to.
+ var ident = new CardUniqueId();
+ if (!cardIdQuery.Any())
+ {
+ //new card, create it!
+ ident.UserId_FK = -1;
+ ident.CardUId = identifier.UniqueId;
+ _connection.Insert(ident);
+ UpdateIdentifierLastUsed(DateTimeOffset.UtcNow, ident.Id);
+ logId = -1;
+ //dont try to log any timelogs against this card, as it is unassigned to a user.
+ ret.ProcessResponse=OperationResponse.SUCCESS;
+ ret.Direction = LogDirection.UNKNOWN;
+ return ret;
+ }
+
+ ident = cardIdQuery.First();
+ _logger.Warn("More than 1 Identifier returned with ID {0}, card ids returned: {2}",
+ ident.CardUId,
+ string.Join(",", cardIdQuery.Select(x => x.CardUId).ToList()));
+ #endregion
+
+ // Get The User Direction (are they going in or out)?
+ var logDirection = GetLogDirection(ident.UserId_FK);
+
+ #region Check the user hasnt registered an event in the last few minutes..
+
+ if (ident.UserId_FK != -1)
+ { //only check log gap if the card is associated to a user
+ var hysteresisThresholdMinutes = Convert.ToInt32(ConfigurationHandler.ConfigurationHandler.GetConfiguration("SwipeTimeGap") ?? "3");
+ var threshold = DateTime.UtcNow.AddMinutes(0 - hysteresisThresholdMinutes);
+ var logs = _connection.Query(
+ SQLiteProcedures.GET_LOGS_IN_LAST_X_MINUTES,
+ threshold.Ticks, ident.UserId_FK);
+ _logger.Trace("Checking last swipe event gap");
+ if (logs.Any())
+ {
+ _logger.Error("Not logging event for user id: {0}, logged event within TimeGap Threshold of {1}", ident.UserId_FK, threshold);
+ logId = -1;
+ ret.ProcessResponse = OperationResponse.FAILED;
+ ret.Direction = LogDirection.UNKNOWN;
+ return ret;
+ }
+ }
+
+ #endregion
+
+ #region Get the current time (for swiping). and calendar week/year to help recall the data.
+
+ var calendarWeek = GetIso8601CalendarWeek(logTime);
+ var year = logTime.Year;
+ #endregion
+
+ var timeLog = new TimeLogDb
+ {
+ SwipeEventDateTime = DateTime.UtcNow,
+ UserId_FK = ident.UserId_FK,
+ IdentifierId = ident.Id,
+ Direction = logDirection,
+ Year = year,
+ CalendarWeek = calendarWeek,
+ Source = LogSourceDb.IDENTIFIER
+ };
+
+ _connection.Insert(timeLog);
+ UpdateIdentifierLastUsed(timeLog.SwipeEventDateTime, timeLog.IdentifierId);
+
+ logId = timeLog.Id;
+ ret.Direction = (LogDirection)(int)logDirection;
+ ret.ProcessResponse = OperationResponse.SUCCESS;
+ return ret;
+ }
+
+ public OperationResponse CreateGroup(Group group, out int groupId)
+ {
+ var query = _connection.Query(SQLiteProcedures.GET_GROUP_BY_NAME, group.Name);
+ if (query.Any())
+ {
+ groupId = query[0].GroupId;
+ return OperationResponse.NONE;
+ }
+ var groupDb = new GroupDb { GroupName = group.Name };
+ var resp = _connection.Insert(groupDb);
+ groupId = groupDb.GroupId;
+ return OperationResponse.CREATED;
+ }
+
+ public List GetGroups(int userId = -1)
+ {
+ var ret = new List();
+ List query;
+ if (userId == -1)
+ {
+ query = _connection.Query(SQLiteProcedures.GET_GROUPS);
+ }
+ else
+ {
+ query =
+ _connection.Query(SQLiteProcedures.GET_GROUPS_FOR_USER,
+ userId);
+ }
+ foreach (var group in query)
+ {
+ ret.Add(new Group
+ {
+ Id = group.GroupId,
+ Name = group.GroupName,
+ UserCount = int.Parse(group.AssignedUserCount ?? "0")
+ });
+ }
+ return ret;
+ }
+
+ public Group GetGroup(int groupId)
+ {
+ var query = _connection.Query(SQLiteProcedures.GET_GROUP_BY_ID, groupId);
+ if (query.Any())
+ {
+ var group = query.First();
+ return new Group
+ {
+ Id = group.GroupId,
+ Name = group.GroupName,
+ UserCount = 0
+ };
+ }
+ return new Group();
+ }
+
+ public OperationResponse UpdateGroup(Group group)
+ {
+ _connection.Query(SQLiteProcedures.UPDATE_GROUP, @group.Name, @group.Id);
+
+ return OperationResponse.UPDATED;
+ }
+
+ public OperationResponse DeleteGroup(int groupId)
+ {
+ _connection.Delete(groupId);
+ return OperationResponse.DELETED;
+ }
+
+ public OperationResponse DeleteLog(TimeLog log)
+ {
+ var query = _connection.Query(
+ SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id);
+
+ if (!query.Any())
+ return OperationResponse.FAILED;
+
+ UpdateExistingLogDirections(log);
+
+ _connection.ExecuteScalar(SQLiteProcedures.DELETE_TIMELOG_ENTRY, log.Id);
+
+ return OperationResponse.DELETED;
+ }
+
+ public OperationResponse CreateLog(TimeLog log)
+ {
+ log.CalendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime);
+ log.Year= log.EventTime.Year;
+
+ var dbLog = TimeLogConverter.ConvertFromTimeLogDto(log);
+ dbLog.IdentifierId = ConvertSourceToIdentifierId(log.Source);
+
+ #region update in/out directions for manual logs.
+ UpdateExistingLogDirections(log);
+ #endregion
+ //and now insert the new log.
+ _connection.Insert(dbLog);
+ return OperationResponse.CREATED;
+ }
+
+ public OperationResponse UpdateLog(TimeLog log)
+ {
+ var query = _connection.Query(
+ SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id);
+
+ if(!query.Any())
+ return OperationResponse.FAILED;
+
+ if (log.CalendarWeek > 52 || log.CalendarWeek < 1)
+ {
+ log.CalendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime);
+ }
+ if (log.Year < 2017)
+ {
+ log.Year = log.EventTime.Year;
+ }
+ _connection.ExecuteScalar(
+ SQLiteProcedures.UPDATE_TIMELOG_ENTRY,
+ log.UserId, (LogDirectionDb) (int) log.Direction, log.EventTime, log.CalendarWeek, log.Year,
+ (LogSourceDb) (int) log.Source, log.Id);
+
+ return OperationResponse.UPDATED;
+ }
+
+ private int GetUserCount()
+ {
+ return _connection.ExecuteScalar(SQLiteProcedures.GET_TOTAL_USER_COUNT);
+ }
+
+ private List GetUserList(int groupId = -1, int pageSize=-1, int pageNumber=-1)
+ {
+ List users;
+ if (pageNumber != -1 && pageSize != -1)
+ {
+ users = _connection.Query(SQLiteProcedures.GET_ALL_USERS_PAGINATE,
+ pageSize, (pageNumber - 1) * pageSize);
+ }
+ else if (groupId != -1)
+ {
+ users =
+ _connection.Query(
+ SQLiteProcedures.GET_ALL_USERS_BY_GROUP,
+ groupId);
+ }
+ else
+ {
+ users = _connection.Query(SQLiteProcedures.GET_ALL_USERS);
+ }
+
+ return users;
+ }
+
+ private void CheckForDbUpgrade()
+ {
+ var data = _connection.Query(SQLiteProcedures.GET_DB_VERSION);
+ if (!data.Any())
+ {
+ //Pre-Upgrade database, need upgrading
+ _logger.Trace("Pre version 0.2 RC database found, performing update..");
+ ExecuteUpgradeFromVersion("0.1"); //execute 0.2 upgrade scripts onwards.
+ }
+ else
+ {
+ var installedVersion = new Version(data.First().VersionNumber);
+ var currentVersion = new Version(AssemblyInfo.ASSEMBLY_VERSION);
+ if (currentVersion.CompareTo(installedVersion) > 0) //greater than 0 - current version is newer
+ {
+ _logger.Trace("Installed Database Version: {0} is older than current version {1}");
+ ExecuteUpgradeFromVersion(installedVersion.ToString());
+ }
+ }
+ }
+
+ private void ExecuteUpgradeFromVersion(string installedVersion)
+ {
+ var instVers = new Version(installedVersion);
+ //so we have established that each script for upgrade will be .sql, so now start at lowest version and work up!
+ var assembly = Assembly.GetExecutingAssembly();
+ var upgradeScripts = assembly.GetManifestResourceNames()
+ .Where(x => x.StartsWith(UPGRADE_SCRIPT_PREFIX))
+ .OrderBy(x =>
+ new Version(Path.GetFileNameWithoutExtension(x.Replace(UPGRADE_SCRIPT_PREFIX, string.Empty))))
+ .Where(x =>
+ {
+ var scriptVersion =
+ new Version(Path.GetFileNameWithoutExtension(x.Replace(UPGRADE_SCRIPT_PREFIX, string.Empty)))
+ .CompareTo(instVers);
+ return scriptVersion > 0;
+ })
+ .ToList();
+ //now have an ordered list of upgrade script files, so execute in order!
+ foreach (var upgradeScript in upgradeScripts)
+ {
+ using (var stream = assembly.GetManifestResourceStream(upgradeScript))
+ using(var str = new StreamReader(stream))
+ {
+ var script = str.ReadToEnd();
+ _logger.Trace("Executing upgrade script with name: {0}", upgradeScript);
+ _connection.Execute(script);
+ }
+ }
+ SetDbVersion(AssemblyInfo.ASSEMBLY_VERSION);
+ }
+
+ private void SetDbVersion(string vers)
+ {
+ _connection.DeleteAll();
+ _connection.Insert(new DbVersion {VersionNumber = vers});
+ _logger.Trace("Set Database version to: {0}", vers);
+ }
+
+ private DateTime GetLastLogDateTime(TimeLogDb timeLog)
+ {
+ if (timeLog != null)
+ {
+ return timeLog.SwipeEventDateTime.DateTime;
+ }
+ return DateTime.MinValue;
+ }
+
+ private bool GetUserState(LogDirectionDb logDirection)
+ {
+ switch (logDirection)
+ {
+ case LogDirectionDb.OUT:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private int ConvertSourceToIdentifierId(LogSource logSource)
+ {
+ switch (logSource)
+ {
+ case LogSource.UI:
+ return -100;
+ case LogSource.TRAYAPP:
+ return -200;
+ default:
+ return -10;
+ }
+ }
+
+ private bool SetUserGroups(int userId, List groups)
+ {
+ var groupIds = GetGroupIds(groups.Select(x => x.Name).ToList());
+ return SetUserGroups(userId, groupIds);
+ }
+
+ private bool SetUserGroups(int userId, int[] groupIds)
+ {
+ //remove the existing user>group associations
+ _connection.Query("delete from UserGroupJoinDb where UserId_FK = ?", userId);
+ //add the new group associations.
+ _connection.InsertAll(groupIds.Select(x => new UserGroupJoinDb { GroupId_FK = x, UserId_FK = userId }));
+ return true;
+ }
+
+ private int[] GetGroupIds(List groupNames)
+ {
+ var ret = new List();
+
+ foreach (var g in groupNames)
+ {
+ var query = _connection.Query("select GroupId from GroupDb where GroupName=?", g);
+ if (!query.Any()) continue;
+ var id = query.First();
+ ret.Add(id.GroupId);
+ }
+ return ret.ToArray();
+ }
+
+ private List GetTimeLogList(int userId, int calendarWeek, int year)
+ {
+ var timeLogList = _connection.Query(
+ SQLiteProcedures.GET_TIMELOGS,
+ userId, calendarWeek, year);
+
+ var timeLogs = timeLogList.Select(x => new TimeLog
+ {
+ Id = x.Id,
+ CalendarWeek = x.CalendarWeek,
+ Direction = (LogDirection)x.Direction,
+ IdentifierId = x.IdentifierId,
+ EventTime = x.SwipeEventDateTime,
+ UserId = x.UserId_FK,
+ Year = x.Year
+ }).OrderBy(x=>x.EventTime.UtcDateTime).ToList();
+
+ var dict = new Dictionary();
+ var logList = new List();
+
+ //make sure each day of the week is accounted for in the dictionary.
+ foreach (DayOfWeek day in Enum.GetValues(typeof(DayOfWeek)))
+ {
+ dict.Add(day, new DailyLogs());
+ }
+
+ //add the logs to the respective day of the week.
+ foreach (var log in timeLogs.OrderBy(x=>x.EventTime))
+ {
+ dict[log.EventTime.DayOfWeek].Logs.Add(log);
+ }
+ var logGroups = timeLogs.GroupBy(x => x.EventTime.DayOfWeek);
+ foreach (var group in logGroups)
+ {
+ var groupLogs = group.ToList();
+ var dailyLog = new DailyLogs
+ {
+ Logs = groupLogs,
+ Day = group.Key,
+ DayOfWeek = group.Key.ToString()
+ };
+ dailyLog.DailyTotal = CalculateDailyTotal(dailyLog);
+ logList.Add(dailyLog);
+ }
+ foreach (DayOfWeek day in Enum.GetValues(typeof(DayOfWeek)))
+ {
+ if (logList.Any(x => x.Day == day)) continue;
+ var dailyLog = new DailyLogs { Day = day, DayOfWeek = day.ToString() };
+ logList.Add(dailyLog);
+ }
+
+ foreach (var dailyCollection in dict)
+ {
+ dailyCollection.Value.DailyTotal = CalculateDailyTotal(dailyCollection.Value);
+ }
+
+ return logList.OrderBy(x => ((int)x.Day + 6) % 7).ToList();
+ }
+
+ private double CalculateDailyTotal(DailyLogs dailyLogs)
+ {
+ var totalInTime = TimeSpan.FromSeconds(0);
+ var logs = dailyLogs.Logs.OrderBy(x => x.EventTime.UtcDateTime).ToArray();
+ var totalCalcMax = IsOdd(logs.Length) ? logs.Length - 1 : logs.Length;
+ for (int i = 0; i < totalCalcMax; i += 2)
+ {
+ totalInTime += (logs[i + 1].EventTime - logs[i].EventTime);
+ }
+ return Math.Round(totalInTime.TotalMinutes, 2);
+ }
+
+ ///
+ /// determines if the number is an odd or even value
+ ///
+ /// number to determine is odd or even
+ /// true - number is odd
+ private bool IsOdd(int value)
+ {
+ return value % 2 != 0;
+ }
+
+ ///
+ /// Get the new direction for the user based on previous entry logs in the system.
+ ///
+ ///
+ /// If the user has not logged in today, the direction will be In.
+ /// If the user has logged in already today, the direction will be the opposite of the last
+ /// recorded log direction. ("out" if "in", "in" if "out")
+ ///
+ /// Id of the user to get the log direction of.
+ /// indicating what direction the new log is.
+ private LogDirectionDb GetLogDirection(int userId)
+ {
+ var logDirection = LogDirectionDb.UNKNOWN;
+ if (userId != -1)
+ {
+ var lastEntry = GetLastTimeLog(userId);
+ if (lastEntry != null)
+ {
+ // See if the datetime retrieved is yesterday. If yesterday, logDirection = true (in)
+ if (IsLogDateTimeYesterdayOrOlder(lastEntry.SwipeEventDateTime.DateTime))
+ {
+ logDirection = LogDirectionDb.IN;
+ }
+ else
+ {
+ // we have a time log from today already, so just do the opposite of what we last did!
+ logDirection = LogDirectionConverter.InvertLogDirectionDb(lastEntry.Direction);
+ }
+ }
+ else
+ {
+ //assume its the first then!
+ logDirection = LogDirectionDb.IN;
+ }
+ }
+ return logDirection;
+ }
+
+ private TimeLogDb GetLastTimeLog(int userId)
+ {
+ var lastEntry = _connection.Query(
+ SQLiteProcedures.GET_LAST_TIMELOG_DIRECTION,
+ userId);
+ if (lastEntry.Any())
+ {
+ return lastEntry.First();
+ }
+ return null;
+ }
+
+ private void UpdateIdentifierLastUsed(DateTimeOffset dt, int cardId)
+ {
+ _connection.ExecuteScalar(SQLiteProcedures.UPDATE_CARD_LAST_USED,
+ dt,
+ cardId);
+ }
+
+ private List GetAssociatedIdentifiers(int userId)
+ {
+ var cards = _connection.Query(
+ SQLiteProcedures.GET_CARDS_BY_USER_ID,
+ userId);
+ var ret = new List();
+ foreach (var card in cards)
+ {
+ ret.Add(new Identifier()
+ {
+ UniqueId = card.CardUId,
+ IsAssociatedToUser = true,
+ Id = card.Id
+ });
+ }
+ return ret;
+ }
+
+ ///
+ /// Get the calendar week of the year according to the ISO8601 standard (starts monday).
+ ///
+ /// the date to get the calendar week of.
+ /// the calendar week of the year in integer form (1-52)
+ private int GetIso8601CalendarWeek(DateTime date)
+ {
+ var day = CultureInfo.InvariantCulture.Calendar.GetDayOfWeek(date);
+ if (day >= DayOfWeek.Monday && day <= DayOfWeek.Wednesday)
+ {
+ date = date.AddDays(3);
+ }
+ return CultureInfo.InvariantCulture.Calendar.GetWeekOfYear(date, CalendarWeekRule.FirstFourDayWeek,
+ DayOfWeek.Monday);
+ }
+
+ ///
+ /// Check whether the specified DateTime is from yesterday or older.
+ ///
+ /// the DateTime object to check is yesterday or older
+ /// true - is yesterday or older.
+ private bool IsLogDateTimeYesterdayOrOlder(DateTime dt)
+ {
+ return dt.Date.CompareTo(DateTime.Today.Date) < 0;
+ }
+
+ private void UpdateExistingLogDirections(TimeLog log)
+ {
+ //need to make this generic so that both create and delete will update the log directions.. but ARGH.
+ //if you want to use this as a delete, you would delete and call this, if you want to create, call this then create.
+ //should look at how to improve this method so that it will compensate for if the log hasnt been deleted yet, but ott?
+ var weekLogs = GetTimeLogList(log.UserId, log.CalendarWeek, log.Year);
+
+ //Get the same logs of the day that the log has been entered for
+ var todaysLogs = weekLogs.FirstOrDefault(x => x.Day == log.EventTime.DayOfWeek);
+ if (todaysLogs != null)
+ {
+ //Get the days logs that are after the manually created date
+ var logs = todaysLogs.Logs.Where(x => x.EventTime.CompareTo(log.EventTime) >= 0).OrderBy(x => x.EventTime).ToList();
+ //Update each log with the inverse progressively
+ var currentlogDirection = log.Direction;
+ for (var i = 0; i < logs.Count; i++)
+ {
+ logs[i].Direction = LogDirectionConverter.InvertLogDirection(currentlogDirection);
+ UpdateLog(logs[i]);
+ currentlogDirection = logs[i].Direction;
+ }
+ }
+ }
+
+ private void UpdateIdentifierUserId(List cardsToUpdate, int userId)
+ {
+ foreach (var card in cardsToUpdate)
+ {
+ _connection.Query(
+ SQLiteProcedures.UPDATE_CARD_USER_ID,
+ userId, card);
+ }
+ }
+
+ private void UpdateUserDetails(string firstName, string lastName, float hoursPerWeek, bool isContractor,
+ int userId)
+ {
+ _connection.Query(
+ SQLiteProcedures.UPDATE_USER_DETAILS,
+ firstName,
+ lastName,
+ hoursPerWeek,
+ isContractor,
+ userId
+ );
+ }
+ }
+}
diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/App.config b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/App.config
index ebf5f25..0dd4b37 100644
--- a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/App.config
+++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/App.config
@@ -3,9 +3,9 @@
-
+
-
+
@@ -18,7 +18,7 @@
-
+
@@ -36,6 +36,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/CardData.cs b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/CardData.cs
index eee79f0..a019bea 100644
--- a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/CardData.cs
+++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/CardData.cs
@@ -1,7 +1,10 @@
-namespace WindowsDataCenter
-{
- public class CardData
- {
- public string CardUId { get; set; }
- }
+using System;
+
+namespace WindowsDataCenter
+{
+ public class CardData
+ {
+ public DateTime? UtcTimeStamp { get; set; }
+ public string CardUId { get; set; }
+ }
}
\ No newline at end of file
diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/SwipeDataController.cs b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/SwipeDataController.cs
index ed31a9f..91e5c96 100644
--- a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/SwipeDataController.cs
+++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/SwipeDataController.cs
@@ -1,47 +1,53 @@
-using System;
-using System.Net;
-using System.Net.Http;
-using System.Web.Http;
-using Interfaces;
-
-namespace WindowsDataCenter
-{
- ///
- ///
- ///
- [RoutePrefix("api/swipedata")]
- public class SwipeDataController : ApiController
- {
- private readonly IRepository _repo;
- private readonly ILogger _logger;
-
- ///
- ///
- ///
- ///
- ///
- public SwipeDataController(IRepository repo, ILogger logger)
- {
- if(repo == null) throw new ArgumentNullException(nameof(repo));
- _repo = repo;
- if(logger == null) throw new ArgumentNullException(nameof(logger));
- _logger = logger;
- }
-
- ///
- ///
- ///
- ///
- ///
- [HttpPost]
- [Route("")]
- public IHttpActionResult PostData([FromBody] CardData cData)
- {
- int logId;
- var resp = _repo.LogEventTime(new Identifier {UniqueId = cData.CardUId}, out logId);
- _logger.Trace("Received new \"Swipe Event\" for UId: {0} at {1}, direction is : {2}", cData.CardUId,
- DateTime.UtcNow, resp.Direction);
- return Ok(new {Id = logId, resp.Direction});
- }
- }
+using System;
+using System.Net;
+using System.Net.Http;
+using System.Web.Http;
+using Interfaces;
+
+namespace WindowsDataCenter
+{
+ ///
+ ///
+ ///
+ [RoutePrefix("api/swipedata")]
+ public class SwipeDataController : ApiController
+ {
+ private readonly IRepository _repo;
+ private readonly ILogger _logger;
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ public SwipeDataController(IRepository repo, ILogger logger)
+ {
+ if(repo == null) throw new ArgumentNullException(nameof(repo));
+ _repo = repo;
+ if(logger == null) throw new ArgumentNullException(nameof(logger));
+ _logger = logger;
+ }
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ [HttpPost]
+ [Route("")]
+ public IHttpActionResult PostData([FromBody] CardData cData)
+ {
+ int logId;
+
+ var id = new Identifier {UniqueId = cData.CardUId};
+
+ var resp = cData.UtcTimeStamp.HasValue
+ ? _repo.LogEventTime(id, out logId, cData.UtcTimeStamp.Value)
+ : _repo.LogEventTime(id, out logId);
+
+ _logger.Trace("Received new \"Swipe Event\" for UId: {0} at {1}, direction is : {2}", cData.CardUId,
+ DateTime.UtcNow, resp.Direction);
+ return Ok(new {Id = logId, resp.Direction});
+ }
+ }
}
\ No newline at end of file
diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/packages.config b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/packages.config
index 0363aa3..1535601 100644
--- a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/packages.config
+++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/packages.config
@@ -1,5 +1,6 @@
+
@@ -8,21 +9,22 @@
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataServiceHost/App.config b/DataCenter_Windows/WindowsDataCenter/WindowsDataServiceHost/App.config
index d2ebb4c..2677a94 100644
--- a/DataCenter_Windows/WindowsDataCenter/WindowsDataServiceHost/App.config
+++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataServiceHost/App.config
@@ -4,7 +4,7 @@
-
+
@@ -31,6 +31,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file