diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/LogDirectionConverter.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/LogDirectionConverter.cs new file mode 100644 index 0000000..72a536e --- /dev/null +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/LogDirectionConverter.cs @@ -0,0 +1,51 @@ +using Interfaces; + +namespace SQLiteRepository.Converters +{ + static class LogDirectionConverter + { + public static LogDirection ConvertToLogDirectionDto(LogDirectionDb direction) + { + switch (direction) + { + case LogDirectionDb.IN: + return LogDirection.IN; + case LogDirectionDb.OUT: + return LogDirection.OUT; + default: + return LogDirection.UNKNOWN; + } + } + + public static LogDirectionDb ConvertFromLogDirectionDto(LogDirection direction) + { + switch (direction) + { + case LogDirection.IN: + return LogDirectionDb.IN; + case LogDirection.OUT: + return LogDirectionDb.OUT; + default: + return LogDirectionDb.UNKNOWN; + } + } + + public static LogDirectionDb InvertLogDirectionDb(LogDirectionDb direction) + { + return (LogDirectionDb)(int)InvertLogDirection((LogDirection)(int)direction); + } + + public static LogDirection InvertLogDirection(LogDirection direction) + { + switch (direction) + { + case LogDirection.IN: + return LogDirection.OUT; + case LogDirection.OUT: + return LogDirection.IN; + default: + return LogDirection.UNKNOWN; + } + } + } +} \ No newline at end of file diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/LogSourceConverter.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/LogSourceConverter.cs new file mode 100644 index 0000000..6ebc7c1 --- /dev/null +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/LogSourceConverter.cs @@ -0,0 +1,37 @@ +using Interfaces; + +namespace SQLiteRepository.Converters +{ + static class LogSourceConverter + { + public static LogSource ConvertToLogSourceDto(LogSourceDb source) + { + switch (source) + { + case LogSourceDb.IDENTIFIER: + return LogSource.IDENTIFIER; + case LogSourceDb.TRAYAPP: + return LogSource.TRAYAPP; + case LogSourceDb.UI: + return LogSource.UI; + default: + return LogSource.UNKNOWN; + } + } + + public static LogSourceDb ConvertFromLogSourceDto(LogSource source) + { + switch (source) + { + case LogSource.IDENTIFIER: + return LogSourceDb.IDENTIFIER; + case LogSource.TRAYAPP: + return LogSourceDb.TRAYAPP; + case LogSource.UI: + return LogSourceDb.UI; + default: + return LogSourceDb.UNKNOWN; + } + } + } +} \ No newline at end of file diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/TimeLogConverter.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/TimeLogConverter.cs new file mode 100644 index 0000000..a118836 --- /dev/null +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/TimeLogConverter.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Interfaces; + +namespace SQLiteRepository.Converters +{ + static class TimeLogConverter + { + public static TimeLog ConvertToTimeLogDto(TimeLogDb log) + { + return new TimeLog + { + CalendarWeek = log.CalendarWeek, + Direction = LogDirectionConverter.ConvertToLogDirectionDto(log.Direction), + EventTime = log.SwipeEventDateTime, + Id = log.Id, + IdentifierId = log.IdentifierId, + UserId = log.UserId_FK, + Source = LogSourceConverter.ConvertToLogSourceDto(log.Source), + Year = log.Year + }; + } + + public static TimeLogDb ConvertFromTimeLogDto(TimeLog log) + { + return new TimeLogDb + { + CalendarWeek = log.CalendarWeek, + Year = log.Year, + UserId_FK = log.UserId, + IdentifierId = log.IdentifierId, + Direction = LogDirectionConverter.ConvertFromLogDirectionDto(log.Direction), + Id = log.Id, + Source = LogSourceConverter.ConvertFromLogSourceDto(log.Source), + SwipeEventDateTime = log.EventTime + }; + } + } +} diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/UserConverter.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/UserConverter.cs new file mode 100644 index 0000000..60f8c59 --- /dev/null +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/Converters/UserConverter.cs @@ -0,0 +1,57 @@ +using System; +using Interfaces; + +namespace SQLiteRepository.Converters +{ + static class UserConverter + { + public static User ConvertToUserDto(UserIdentity user) + { + return new User + { + UserId = user.Id, + FirstName = user.FirstName, + LastName = user.LastName, + IsContractor = user.IsContractor, + HoursPerWeek = user.HoursPerWeek, + }; + } + + public static UserIdentity ConvertFromUserDto(User user) + { + return new UserIdentity + { + Id = user.UserId, + FirstName = user.FirstName, + LastName = user.LastName, + HoursPerWeek = user.HoursPerWeek, + IsContractor = user.IsContractor + }; + } + } + + static class IdentifierConverter + { + public static Identifier ConvertToIdentifierDto(CardUniqueId ident) + { + return new Identifier + { + Id = ident.Id, + UniqueId = ident.CardUId, + IsAssociatedToUser = ident.UserId_FK != Constants.UNASSIGNED_CARD_USER_ID, + LastUsed = ident.LastUsed.DateTime + }; + } + + public static CardUniqueId ConvertFromIdentifierDto(Identifier ident, int userId) + { + return new CardUniqueId + { + CardUId = ident.UniqueId, + Id = ident.Id, + UserId_FK = userId, + LastUsed = ident.LastUsed + }; + } + } +} diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteProcedures.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteProcedures.cs index bcded4e..56611d7 100644 --- a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteProcedures.cs +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteProcedures.cs @@ -1,3 +1,8 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.Design; +using System.Linq; + namespace SQLiteRepository { internal static class SQLiteProcedures @@ -60,6 +65,9 @@ namespace SQLiteRepository public const string GET_CARDS_BY_UNIQUE_ID = "select * from " + nameof(CardUniqueId) + " where " + nameof(CardUniqueId.CardUId) + "=?"; + public const string GET_CARDS_BY_UNIQUE_ID_LIST = + "select * from " + nameof(CardUniqueId) + " where " + nameof(CardUniqueId.CardUId) + " in (#IN#)"; + public const string GET_UNASSIGNED_CARD_LIST = "select * from " + nameof(CardUniqueId) + " where " + nameof(CardUniqueId.UserId_FK) + "=?"; @@ -92,5 +100,67 @@ namespace SQLiteRepository public const string GET_USER_CONTRACTED_HOURS = "select " + nameof(UserIdentity.HoursPerWeek) + " From UserIdentity where " + nameof(UserIdentity.Id) + "=?"; + + public const string GET_GROUPS = "select gp."+ nameof(GroupDb.GroupId)+ ", gp."+nameof(GroupDb.GroupName)+", " + + "sum(case when gp." + nameof(GroupDb.GroupId) + " = ujdb." + nameof(UserGroupJoinDb.GroupId_FK) + " then 1 else 0 end) as " + nameof(GroupDb.AssignedUserCount) + + " from " + nameof(GroupDb) + " gp" + + " left join " + nameof(UserGroupJoinDb) + " ujdb " + + "on ujdb." + nameof(UserGroupJoinDb.GroupId_FK) + " = gp." + nameof(GroupDb.GroupId) + + " group by gp." + nameof(GroupDb.GroupId); + + public const string GET_GROUPS_FOR_USER = "select gdb." + nameof(GroupDb.GroupId) + ", gdb." + nameof(GroupDb.GroupName) + ", gdb.AssignedUserCount" + + " from " + nameof(GroupDb) + " gdb" + + " left join " + nameof(UserGroupJoinDb) + " ujdb" + + " on gdb." + nameof(GroupDb.GroupId) + " = ujdb." + nameof(UserGroupJoinDb.GroupId_FK) + + " where ujdb." + nameof(UserGroupJoinDb.UserId_FK) + " = ?"; + + public const string GET_GROUP_BY_ID = + "select * from " + nameof(GroupDb) + " where " + nameof(GroupDb.GroupId) + " =?"; + + public const string UPDATE_GROUP = "update " + nameof(GroupDb) + " set " + nameof(GroupDb.GroupName) + + "=? where " + nameof(GroupDb.GroupId) + "=?"; + + public const string GET_GROUP_BY_NAME = + "select 1 from " + nameof(GroupDb)+" where "+nameof(GroupDb.GroupName)+"= ?"; + + public const string GET_TIMELOG_ENTRY = + "select * from " + nameof(TimeLogDb) + " where " + nameof(TimeLogDb.Id) + "=?"; + + public const string DELETE_TIMELOG_ENTRY = + "delete from " + nameof(TimeLogDb) + " where " + nameof(TimeLogDb.Id) + "=?"; + + public const string DELETE_TIMELOG_ENTRIES = + "delete from " + nameof(TimeLogDb) + " where " + nameof(TimeLogDb.Id) + "in (#IN#)"; + + public const string UPDATE_TIMELOG_ENTRY = "update " + nameof(TimeLogDb) + + " set " + nameof(TimeLogDb.UserId_FK) + "=?, " + + nameof(TimeLogDb.Direction) + "=?," + + nameof(TimeLogDb.SwipeEventDateTime) + "=?," + + nameof(TimeLogDb.CalendarWeek) + "=?," + + nameof(TimeLogDb.Year) + "=?," + + nameof(TimeLogDb.Source) + "=? " + + "where " + nameof(TimeLogDb.Id) + "=?"; + + public const string GET_DB_VERSION = "select * from DbVersion"; + + /// + /// This works on the tokenisation of the query string. + /// where the list of params is to be inserted, the query should have #IN# + /// + /// the query to add the list of parameters to + /// the parameters to add to the query. + /// + public static string FormatInQuery(string query, List args) + { + if (!query.Contains("#IN#")) + { + throw new ArgumentException("query doesnt contain any #IN# tokenisation"); + } + //Convert to a comma separated list e.g.: val1,val2,val3 + //but we need to use string.. so.. enclose in single quotes 'val1','val2'..etc + var argsFormatted = string.Join(",", args.Select(x=>$"'{x}'")); + + return query.Replace("#IN#", argsFormatted); + } } } \ No newline at end of file diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs index 89c510b..94e09ed 100644 --- a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.cs @@ -8,6 +8,7 @@ using System.Reflection; using Interfaces; using SQLite.Net; using SQLite.Net.Platform.Win32; +using SQLiteRepository.Converters; using SQLiteRepository.Properties; namespace SQLiteRepository @@ -16,12 +17,14 @@ namespace SQLiteRepository { private readonly SQLiteConnection _connection; private readonly ILogger _logger; - private string _path = "flexitimedb.db"; + 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), "flexitimedb.db")) + new Uri(Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().CodeBase), DATABASE_NAME)) .LocalPath; if (logger == null) throw new ArgumentNullException(nameof(logger)); _logger = logger; @@ -39,107 +42,32 @@ namespace SQLiteRepository CheckForDbUpgrade(); } - private void CheckForDbUpgrade() - { - var data = _connection.Query("select * from DbVersion"); - 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) - { - const string PREFIX = "SQLiteRepository.UpgradeScripts."; - 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(PREFIX)) - .OrderBy(x=>new Version(Path.GetFileNameWithoutExtension(x.Replace(PREFIX, "")))) - .Where(x => - { - var scriptVersion = new Version(Path.GetFileNameWithoutExtension(x.Replace(PREFIX, ""))).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); - } - public UserList GetUsers(int pageNumber = -1, int pageSize = -1, int groupId = -1) { var ret = new UserList(); - List users; - int userCount; - if (pageNumber != -1 && pageSize != -1) + List users = GetUserList(groupId, pageSize, pageNumber); + + var userCount = GetUserCount(); + + if (pageNumber == -1 && pageSize == -1) { - users = _connection.Query(SQLiteProcedures.GET_ALL_USERS_PAGINATE, - pageSize, (pageNumber - 1) * pageSize); - userCount = _connection.ExecuteScalar(SQLiteProcedures.GET_TOTAL_USER_COUNT); - } - else if (groupId != -1) - { - users = - _connection.Query( - SQLiteProcedures.GET_ALL_USERS_BY_GROUP, - groupId); - userCount = users.Count; + ret.PageNumber = 1; + ret.PageSize = 20; } else { - users = _connection.Query(SQLiteProcedures.GET_ALL_USERS); - userCount = users.Count; + ret.PageNumber = pageNumber; + ret.PageSize = pageSize; } if (!users.Any()) { - if (pageNumber == -1 && pageSize == -1) - { - ret.PageNumber = 1; - ret.PageSize = 20; - } - else - { - ret.PageNumber = pageNumber; - ret.PageSize = pageSize; - } return ret; } foreach (var user in users) { - var userObj = ChangeToUserObject(user); + var userObj = UserConverter.ConvertToUserDto(user); userObj.AssociatedIdentifiers = GetAssociatedIdentifiers(user.Id); userObj.State = GetUserState(GetLogDirection(user.Id)); @@ -147,20 +75,11 @@ namespace SQLiteRepository userObj.Groups = GetGroups(user.Id); ret.Users.Add(userObj); } - if (pageNumber == -1 && pageSize == -1) - { - ret.PageSize = 10; - ret.PageNumber = 1; - } - else - { - ret.PageSize = pageSize; - ret.PageNumber = pageNumber; - } + ret.TotalUserCount = userCount; return ret; } - + public UserList Search(string searchParam) { _logger.Trace("Searching SQLite database for the term: {0}", searchParam); @@ -180,26 +99,20 @@ namespace SQLiteRepository foreach (var user in users) { - var userObj = ChangeToUserObject(user); + 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(new Identifier() - { - UniqueId = card.CardUId, - IsAssociatedToUser = true, - Id = card.Id - }); + userObj.AssociatedIdentifiers.Add(IdentifierConverter.ConvertToIdentifierDto(card)); } userObj.State = GetUserState(GetLogDirection(user.Id)); ret.Users.Add(userObj); } - //TODO: figure out paging here. - should there be any? ret.PageSize = 20; - ret.PageNumber = 1; + ret.PageNumber = (int)Math.Ceiling((double)ret.Users.Count/(double)ret.PageSize); return ret; } @@ -217,7 +130,7 @@ namespace SQLiteRepository if (!users.Any()) return ret; var user = users.First(); - ret = ChangeToUserObject(user); + ret = UserConverter.ConvertToUserDto(user); ret.Groups = GetGroups(); var usersGroups = GetGroups(user.Id); foreach (var group in usersGroups) @@ -230,7 +143,7 @@ namespace SQLiteRepository foreach (var card in cards) { - ret.AssociatedIdentifiers.Add(new Identifier { UniqueId = card.CardUId, IsAssociatedToUser = true, Id = card.Id }); + ret.AssociatedIdentifiers.Add(IdentifierConverter.ConvertToIdentifierDto(card)); } } catch (Exception ex) @@ -298,86 +211,54 @@ namespace SQLiteRepository foreach (var card in cardQuery) { - ret.data.Add(new Identifier - { - Id = card.Id, - IsAssociatedToUser = card.UserId_FK != Constants.UNASSIGNED_CARD_USER_ID, - UniqueId = card.CardUId, - LastUsed = card.LastUsed.DateTime - }); + 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); } - //TODO: Check time logs table on update to ensure associated cards/unique identifiers are removed/added as appropriate. public OperationResponse UpdateUser(User user, out int userIdResult) { - //if(user.UserId <=0) return OperationResponse.FAILED; - var ret = OperationResponse.NONE; - var cardIds = new List(); //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(x => new Identifier { Id = x.Id, IsAssociatedToUser = true, UniqueId = x.CardUId }); + .Select(IdentifierConverter.ConvertToIdentifierDto); var cardsToRemove = currentCards.Except(user.AssociatedIdentifiers).Select(x => x.Id).ToList(); - - #region GetUnique Identifiers - foreach (var card in user.AssociatedIdentifiers) - { - var existingCard = _connection.Query( - SQLiteProcedures.GET_CARDS_BY_UNIQUE_ID, card.UniqueId); - - if (!existingCard.Any()) - { - var cardInsert = new CardUniqueId { CardUId = card.UniqueId, UserId_FK = -1 }; - _connection.Insert(cardInsert); - cardIds.Add(cardInsert.Id); - if (ret < OperationResponse.CREATED) - ret = OperationResponse.CREATED; //only change it if my status supercedes. - } - else - { - cardIds.Add(existingCard.First().Id); - if (ret < OperationResponse.UPDATED) - ret = OperationResponse.UPDATED; - } - } - #endregion - + #region Update/Create User int userId; if (user.UserId != -1) { - //edit.. - _connection.Query( - SQLiteProcedures.UPDATE_USER_DETAILS, - user.FirstName, - user.LastName, - user.HoursPerWeek, - user.IsContractor, - user.UserId - ); + UpdateUserDetails(user.FirstName, user.LastName, user.HoursPerWeek, user.IsContractor, user.UserId); userId = user.UserId; } else { - var userInsert = new UserIdentity - { - FirstName = user.FirstName, - LastName = user.LastName, - HoursPerWeek = user.HoursPerWeek, - IsContractor = user.IsContractor - }; + var userInsert = UserConverter.ConvertFromUserDto(user); _connection.Insert(userInsert); userId = userInsert.Id; if (ret < OperationResponse.CREATED) @@ -385,21 +266,34 @@ namespace SQLiteRepository } #endregion - #region Update Card/Unique Id entries. - foreach (var cardId in cardIds) + #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) { - _connection.Query( - SQLiteProcedures.UPDATE_CARD_USER_ID, - userId, cardId); - } - foreach (var card in cardsToRemove) - { - _connection.Query( - SQLiteProcedures.UPDATE_CARD_USER_ID, - -1, card); + 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()); @@ -432,11 +326,11 @@ namespace SQLiteRepository ret.Direction = LogDirection.UNKNOWN; return ret; } - else - { - //TODO: log when more than one comes back. should NEVER happen but.... - ident = cardIdQuery.First(); - } + + 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)? @@ -469,7 +363,7 @@ namespace SQLiteRepository var calendarWeek = GetIso8601CalendarWeek(logTime); var year = logTime.Year; #endregion - + var timeLog = new TimeLogDb { SwipeEventDateTime = DateTime.UtcNow, @@ -489,11 +383,15 @@ namespace SQLiteRepository ret.ProcessResponse = OperationResponse.SUCCESS; return ret; } - - /*Groups*/ - //TODO: check group name can only be entered once. + 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; @@ -506,22 +404,12 @@ namespace SQLiteRepository List query; if (userId == -1) { - query = _connection.Query("select gp.GroupId, gp.GroupName, " + - "sum(case when gp.GroupId = ujdb.GroupId_FK then 1 else 0 end) as AssignedUserCount " + - "from GroupDb gp " + - "left join UserGroupJoinDb ujdb " + - "on ujdb.GroupId_FK = gp.GroupId " + - "group by gp.GroupId"); + query = _connection.Query(SQLiteProcedures.GET_GROUPS); } else { query = - _connection.Query( - "select gdb.GroupId, gdb.GroupName, gdb.AssignedUserCount" + - " from GroupDb gdb" + - " left join UserGroupJoinDb ujdb" + - " on gdb.GroupId = ujdb.GroupId_FK" + - " where ujdb.UserId_FK = ?", + _connection.Query(SQLiteProcedures.GET_GROUPS_FOR_USER, userId); } foreach (var group in query) @@ -538,7 +426,7 @@ namespace SQLiteRepository public Group GetGroup(int groupId) { - var query = _connection.Query("select * from GroupDb where GroupId = ?", groupId); + var query = _connection.Query(SQLiteProcedures.GET_GROUP_BY_ID, groupId); if (query.Any()) { var group = query.First(); @@ -554,8 +442,7 @@ namespace SQLiteRepository public OperationResponse UpdateGroup(Group group) { - //TODO: I would probably prefer to do this manually.... - var resp = _connection.Query("update GroupDb set GroupName=? where GroupId=?", group.Name, group.Id); + _connection.Query(SQLiteProcedures.UPDATE_GROUP, @group.Name, @group.Id); return OperationResponse.UPDATED; } @@ -569,34 +456,26 @@ namespace SQLiteRepository public OperationResponse DeleteLog(TimeLog log) { var query = _connection.Query( - "select * from TimeLogDb where Id=?", log.Id); + SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id); if (!query.Any()) return OperationResponse.FAILED; UpdateExistingLogDirections(log); - _connection.ExecuteScalar("delete from TimeLogDb where Id=?", log.Id); + _connection.ExecuteScalar(SQLiteProcedures.DELETE_TIMELOG_ENTRY, log.Id); return OperationResponse.DELETED; } public OperationResponse CreateLog(TimeLog log) { - var calendarWeek = GetIso8601CalendarWeek(log.EventTime.UtcDateTime); - var year = log.EventTime.Year; - log.CalendarWeek = calendarWeek; - log.Year = year; - var dbLog = new TimeLogDb - { - SwipeEventDateTime = log.EventTime, - Direction = (LogDirectionDb)(int)log.Direction, - Year = year, - CalendarWeek = calendarWeek, - Source = (LogSourceDb)(int)log.Source, - UserId_FK = log.UserId, - IdentifierId = ConvertSourceToIdentifierId(log.Source), - }; + 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 @@ -608,7 +487,8 @@ namespace SQLiteRepository public OperationResponse UpdateLog(TimeLog log) { var query = _connection.Query( - "select * from TimeLogDb where Id=?", log.Id); + SQLiteProcedures.GET_TIMELOG_ENTRY, log.Id); + if(!query.Any()) return OperationResponse.FAILED; @@ -621,12 +501,99 @@ namespace SQLiteRepository log.Year = log.EventTime.Year; } _connection.ExecuteScalar( - "update TimeLogDb set UserId_FK=?, Direction=?,SwipeEventDateTime=?,CalendarWeek=?,Year=?,Source=? where Id=?", + 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) { @@ -797,7 +764,7 @@ namespace SQLiteRepository else { // we have a time log from today already, so just do the opposite of what we last did! - logDirection = InvertLogDirectionDb(lastEntry.Direction); + logDirection = LogDirectionConverter.InvertLogDirectionDb(lastEntry.Direction); } } else @@ -823,7 +790,7 @@ namespace SQLiteRepository private void UpdateIdentifierLastUsed(DateTimeOffset dt, int cardId) { - var res = _connection.ExecuteScalar(SQLiteProcedures.UPDATE_CARD_LAST_USED, + _connection.ExecuteScalar(SQLiteProcedures.UPDATE_CARD_LAST_USED, dt, cardId); } @@ -872,18 +839,6 @@ namespace SQLiteRepository return dt.Date.CompareTo(DateTime.Today.Date) < 0; } - private User ChangeToUserObject(UserIdentity user) - { - return new User - { - UserId = user.Id, - FirstName = user.FirstName, - LastName = user.LastName, - HoursPerWeek = user.HoursPerWeek, - IsContractor = user.IsContractor - }; - } - private void UpdateExistingLogDirections(TimeLog log) { //need to make this generic so that both create and delete will update the log directions.. but ARGH. @@ -901,29 +856,35 @@ namespace SQLiteRepository var currentlogDirection = log.Direction; for (var i = 0; i < logs.Count; i++) { - logs[i].Direction = InvertLogDirection(currentlogDirection); + logs[i].Direction = LogDirectionConverter.InvertLogDirection(currentlogDirection); UpdateLog(logs[i]); currentlogDirection = logs[i].Direction; } } } - private LogDirectionDb InvertLogDirectionDb(LogDirectionDb direction) + private void UpdateIdentifierUserId(List cardsToUpdate, int userId) { - return (LogDirectionDb) (int) InvertLogDirection((LogDirection) (int) direction); - } - - private LogDirection InvertLogDirection(LogDirection direction) - { - switch (direction) + foreach (var card in cardsToUpdate) { - case LogDirection.IN: - return LogDirection.OUT; - case LogDirection.OUT: - return LogDirection.IN; - default: - return LogDirection.UNKNOWN; + _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/SQLiteRepository/SQLiteRepository.csproj b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.csproj index 46517fc..a666342 100644 --- a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.csproj +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/SQLiteRepository.csproj @@ -78,6 +78,10 @@ + + + + diff --git a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/UpgradeScripts/0.2.sql b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/UpgradeScripts/0.2.sql index 5eeccd7..8eb6cd4 100644 --- a/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/UpgradeScripts/0.2.sql +++ b/DataCenter_Windows/WindowsDataCenter/SQLiteRepository/UpgradeScripts/0.2.sql @@ -1 +1,3 @@ -insert into GroupDb values ((select max(groupId) from GroupDb)+1,'Archived',0) \ No newline at end of file +insert into GroupDb(GroupId, GroupName, AssignedUserCount) +select (select max(GroupId) from GroupDb)+1, 'Archived', 0 +WHERE NOT EXISTS(select * from GroupDb where GroupName='Archived'); \ No newline at end of file diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/UsersController.cs b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/UsersController.cs index 763ffe6..675c33a 100644 --- a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/UsersController.cs +++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/Controllers/UsersController.cs @@ -93,8 +93,7 @@ namespace WindowsDataCenter { int userId; _repo.UpdateUser(user, out userId); - //TODO return ID. - return ResponseMessage(new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent("unknownIdTODO")}); + return ResponseMessage(new HttpResponseMessage(HttpStatusCode.OK) {Content = new StringContent(userId.ToString())}); } [HttpPost] diff --git a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/WindowsDataCenter.csproj b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/WindowsDataCenter.csproj index 4dee973..e18caab 100644 --- a/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/WindowsDataCenter.csproj +++ b/DataCenter_Windows/WindowsDataCenter/WindowsDataCenter/WindowsDataCenter.csproj @@ -55,6 +55,7 @@ prompt MinimumRecommendedRules.ruleset true + bin\ReleaseInstallers\WindowsDataCenter.XML