fix UpdateUser to use Exclude rather than Except method for linq. #98
890 lines
33 KiB
C#
890 lines
33 KiB
C#
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<CardUniqueId>();
|
|
_connection.CreateTable<UserIdentity>();
|
|
_connection.CreateTable<TimeLogDb>();
|
|
_connection.CreateTable<GroupDb>();
|
|
_connection.CreateTable<UserGroupJoinDb>();
|
|
_connection.CreateTable<DbVersion>();
|
|
_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<UserIdentity> 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<UserIdentity>(
|
|
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<CardUniqueId>(
|
|
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<UserIdentity>(
|
|
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<CardUniqueId>(
|
|
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<UserIdentity>(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<CardUniqueId>(
|
|
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<CardUniqueId>(SQLiteProcedures.GET_UNASSIGNED_CARD_LIST);
|
|
|
|
//remove the logs from the timelog db
|
|
_connection.Query<TimeLogDb>(
|
|
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<CardUniqueId>(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<CardUniqueId>(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<CardUniqueId>(
|
|
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<TimeLogDb>(
|
|
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<GroupDb>(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<Group> GetGroups(int userId = -1)
|
|
{
|
|
var ret = new List<Group>();
|
|
List<GroupDb> query;
|
|
if (userId == -1)
|
|
{
|
|
query = _connection.Query<GroupDb>(SQLiteProcedures.GET_GROUPS);
|
|
}
|
|
else
|
|
{
|
|
query =
|
|
_connection.Query<GroupDb>(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<GroupDb>(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<GroupDb>(SQLiteProcedures.UPDATE_GROUP, @group.Name, @group.Id);
|
|
|
|
return OperationResponse.UPDATED;
|
|
}
|
|
|
|
public OperationResponse DeleteGroup(int groupId)
|
|
{
|
|
_connection.Delete<GroupDb>(groupId);
|
|
return OperationResponse.DELETED;
|
|
}
|
|
|
|
public OperationResponse DeleteLog(TimeLog log)
|
|
{
|
|
var query = _connection.Query<TimeLogDb>(
|
|
SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id);
|
|
|
|
if (!query.Any())
|
|
return OperationResponse.FAILED;
|
|
|
|
UpdateExistingLogDirections(log);
|
|
|
|
_connection.ExecuteScalar<TimeLogDb>(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<TimeLogDb>(
|
|
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<TimeLogDb>(
|
|
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<int>(SQLiteProcedures.GET_TOTAL_USER_COUNT);
|
|
}
|
|
|
|
private List<UserIdentity> GetUserList(int groupId = -1, int pageSize=-1, int pageNumber=-1)
|
|
{
|
|
List<UserIdentity> users;
|
|
if (pageNumber != -1 && pageSize != -1)
|
|
{
|
|
users = _connection.Query<UserIdentity>(SQLiteProcedures.GET_ALL_USERS_PAGINATE,
|
|
pageSize, (pageNumber - 1) * pageSize);
|
|
}
|
|
else if (groupId != -1)
|
|
{
|
|
users =
|
|
_connection.Query<UserIdentity>(
|
|
SQLiteProcedures.GET_ALL_USERS_BY_GROUP,
|
|
groupId);
|
|
}
|
|
else
|
|
{
|
|
users = _connection.Query<UserIdentity>(SQLiteProcedures.GET_ALL_USERS);
|
|
}
|
|
|
|
return users;
|
|
}
|
|
|
|
private void CheckForDbUpgrade()
|
|
{
|
|
var data = _connection.Query<DbVersion>(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 <version>.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<DbVersion>();
|
|
_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<Group> 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<UserGroupJoinDb>("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<string> groupNames)
|
|
{
|
|
var ret = new List<int>();
|
|
|
|
foreach (var g in groupNames)
|
|
{
|
|
var query = _connection.Query<GroupDb>("select GroupId from GroupDb where GroupName=?", g);
|
|
if (!query.Any()) continue;
|
|
var id = query.First();
|
|
ret.Add(id.GroupId);
|
|
}
|
|
return ret.ToArray();
|
|
}
|
|
|
|
private List<DailyLogs> GetTimeLogList(int userId, int calendarWeek, int year)
|
|
{
|
|
var timeLogList = _connection.Query<TimeLogDb>(
|
|
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<DayOfWeek, DailyLogs>();
|
|
var logList = new List<DailyLogs>();
|
|
|
|
//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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// determines if the number is an odd or even value
|
|
/// </summary>
|
|
/// <param name="value">number to determine is odd or even</param>
|
|
/// <returns>true - number is odd</returns>
|
|
private bool IsOdd(int value)
|
|
{
|
|
return value % 2 != 0;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the new direction for the user based on previous entry logs in the system.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 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")
|
|
/// </remarks>
|
|
/// <param name="userId">Id of the user to get the log direction of.</param>
|
|
/// <returns><see cref="LogDirectionDb"/> indicating what direction the new log is.</returns>
|
|
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<TimeLogDb>(
|
|
SQLiteProcedures.GET_LAST_TIMELOG_DIRECTION,
|
|
userId);
|
|
if (lastEntry.Any())
|
|
{
|
|
return lastEntry.First();
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private void UpdateIdentifierLastUsed(DateTimeOffset dt, int cardId)
|
|
{
|
|
_connection.ExecuteScalar<CardUniqueId>(SQLiteProcedures.UPDATE_CARD_LAST_USED,
|
|
dt,
|
|
cardId);
|
|
}
|
|
|
|
private List<Identifier> GetAssociatedIdentifiers(int userId)
|
|
{
|
|
var cards = _connection.Query<CardUniqueId>(
|
|
SQLiteProcedures.GET_CARDS_BY_USER_ID,
|
|
userId);
|
|
var ret = new List<Identifier>();
|
|
foreach (var card in cards)
|
|
{
|
|
ret.Add(new Identifier()
|
|
{
|
|
UniqueId = card.CardUId,
|
|
IsAssociatedToUser = true,
|
|
Id = card.Id
|
|
});
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get the calendar week of the year according to the ISO8601 standard (starts monday).
|
|
/// </summary>
|
|
/// <param name="date">the date to get the calendar week of.</param>
|
|
/// <returns>the calendar week of the year in integer form (1-52)</returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check whether the specified DateTime is from yesterday or older.
|
|
/// </summary>
|
|
/// <param name="dt">the DateTime object to check is yesterday or older</param>
|
|
/// <returns>true - is yesterday or older.</returns>
|
|
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<int> cardsToUpdate, int userId)
|
|
{
|
|
foreach (var card in cardsToUpdate)
|
|
{
|
|
_connection.Query<CardUniqueId>(
|
|
SQLiteProcedures.UPDATE_CARD_USER_ID,
|
|
userId, card);
|
|
}
|
|
}
|
|
|
|
private void UpdateUserDetails(string firstName, string lastName, float hoursPerWeek, bool isContractor,
|
|
int userId)
|
|
{
|
|
_connection.Query<UserIdentity>(
|
|
SQLiteProcedures.UPDATE_USER_DETAILS,
|
|
firstName,
|
|
lastName,
|
|
hoursPerWeek,
|
|
isContractor,
|
|
userId
|
|
);
|
|
}
|
|
}
|
|
}
|