using Coscine.Database.DataModel; using Coscine.Database.ReturnObjects; using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; namespace Coscine.Database.Models { // ------------------------------------------------------------------------------------ // This Class makes use of "GetAllWhere(...Id)" method rather than "GetById(...Id)" // to make it future proof in case on a later stage more than a single entry // is allowed inside the ContactChange table (e.g. history of contact change requests). // To achieve that, remove usage of "DeleteAllDbEntries(...Id)" method. // The line in quesiton is marked with an appropiate comment. // ------------------------------------------------------------------------------------ public class ContactChangeModel : DatabaseModel<ContactChange> { public bool UserHasEmailsToConfirm(Guid userId) { // Perform deletion of all expired entries (older than 24 Hours). DeleteExpiredDbEntries(userId); IEnumerable<ContactChange> emailData = GetAllWhere((contactChange) => contactChange.UserId == userId); // Return True if entries for a user exist inside the database table ContactChange. Else return False. if (emailData.Count() > 0) { return true; } else { return false; } } public ContactChangeObject NewEmailChangeRequest(Guid userId, string email) { if (UserHasEmailsToConfirm(userId)) { DeleteAllDbEntries(userId); // <--- REMOVE THIS LINE IF YOU WANT TO KEEP HISTORY OF EMAIL CHANGES. } ContactChangeObject contactChangeObject = AddDbEntry(userId, email); // Sending a confirmation email after an addition to the database is handled by the Controller. return contactChangeObject; } public List<ContactChangeObject> GetEmailsForConfirmation(Guid userId) { List<ContactChangeObject> contactChangeObjects = new List<ContactChangeObject>(); IEnumerable<ContactChange> emailData = GetAllWhere((contactChange) => contactChange.UserId == userId); foreach (var entry in emailData) { contactChangeObjects.Add(ToObject(entry)); } return contactChangeObjects; } public UserObject ExecuteConfirmation(Guid token) { ContactChange emailData = GetWhere((contactChange) => contactChange.ConfirmationToken == token); if (emailData != null) { if (emailData.EditDate != null) { // Add 23 Hours, 59 Minutes and 59 Seconds to EditDate, see when the token has to expire and compare with Now. DateTime expirationDateTime = emailData.EditDate.Value.AddHours(23).AddMinutes(59).AddSeconds(59); var compareDateTime = DateTime.Compare(expirationDateTime, DateTime.Now); // Token EXPIRED when expirationDateTime = -1 (Expiration is BEFORE Now) // Token VALID when expirationDateTime = 0 OR = 1 (Expiration IS Now or AFTER Now) if (compareDateTime >= 0) { // VALID UserModel userModel = new UserModel(); User user = userModel.GetById(emailData.UserId); user.EmailAddress = emailData.NewEmail; // Overwrite old Email with New. userModel.Update(user); // Update Database (User Table). Delete(emailData); // Delete Entry from Database (ContactChange Table). UserObject userObject = userModel.CreateReturnObjectFromDatabaseObject(userModel.GetWhere((usr) => usr.Id == emailData.UserId)); return userObject; } else { throw new Exception("EXPIRED: Token " + token.ToString() + " has expired."); } } else { throw new ArgumentNullException("INVALID: Value EditDate is NULL for Token " + token.ToString() + "."); } } else { throw new MissingFieldException("INVALID: The Token " + token.ToString() + " is not valid. No entry inside the Database."); } } private void DeleteExpiredDbEntries(Guid userId) { IEnumerable<ContactChange> emailData = GetAllWhere((contactChange) => contactChange.UserId == userId); foreach (var entry in emailData) { // Add 23 Hours, 59 Minutes and 59 Seconds to EditDate, see when the token has to expire and compare with Now. DateTime expirationDateTime = entry.EditDate.Value.AddHours(23).AddMinutes(59).AddSeconds(59); var compareDateTime = DateTime.Compare(expirationDateTime, DateTime.Now); // Token EXPIRED when expirationDateTime = -1 (Expiration is BEFORE Now) // Token VALID when expirationDateTime = 0 OR = 1 (Expiration IS Now or AFTER Now) if (compareDateTime < 0) { Delete(entry); } } } private void DeleteAllDbEntries(Guid userId) { IEnumerable<ContactChange> emailData = GetAllWhere((contactChange) => contactChange.UserId == userId); foreach (var entry in emailData) { Delete(entry); } } private ContactChangeObject AddDbEntry(Guid userId, string email) { // Create new entry inside the Database for an Email Change Request for the specific User with an Id. ContactChange contactChange = new ContactChange() { RelationId = Guid.NewGuid(), UserId = userId, NewEmail = email, EditDate = DateTime.Now, ConfirmationToken = Guid.NewGuid() }; Insert(contactChange); return ToObject(contactChange); } public static ContactChangeObject ToObject(ContactChange contactChange) { return new ContactChangeObject( contactChange.RelationId, contactChange.UserId, contactChange.NewEmail, contactChange.EditDate, contactChange.ConfirmationToken ); } public static ContactChange FromObject(ContactChangeObject contactChangeObject) { return new ContactChange() { RelationId = contactChangeObject.RelationId, UserId = contactChangeObject.UserId, NewEmail = contactChangeObject.NewEmail, EditDate = contactChangeObject.EditDate, ConfirmationToken = contactChangeObject.ConfirmationToken }; } public override Expression<Func<ContactChange, Guid>> GetIdFromObject() { return (contactChange) => contactChange.RelationId; } public override Microsoft.EntityFrameworkCore.DbSet<ContactChange> GetITableFromDatabase(CoscineDB db) { return db.ContactChanges; } public override void SetObjectId(ContactChange databaseObject, Guid id) { databaseObject.RelationId = id; } } }