public void PurgeClient(ClientRecord clientRecord) { if (!this.Connected) throw new InvalidOperationException("Cannot purge the client because the database is not connected."); if (!this.Authenticated) throw new InvalidOperationException("Cannot purge the client because the current user is not authenticated with the Database."); if (clientRecord == null) throw new ArgumentNullException("clientRecord"); int id; if (!_clients.TryGetKey(clientRecord, out id)) throw new ArgumentException("Cannot purge this client because it does not exist in this database."); //delete entries and associated values (takes care of both memory and DB) clientRecord.RemoveEntries(clientRecord.Entries.ToList()); CommitClient(clientRecord); //delete client in DB var purgeCommand = new SqlCommand("sp_PurgeClient", _connection) { CommandType = System.Data.CommandType.StoredProcedure }; purgeCommand.Parameters.Add(new SqlParameter("token", "null_token")); //TODO: token will go here purgeCommand.Parameters.Add(new SqlParameter("client_id", id)); purgeCommand.ExecuteNonQuery(); //delete client in memory _clients.Remove(clientRecord); OnClientsRemoved(new ClientRecordEventArgs(clientRecord)); AddLogEntryInternal(UserLogEntryType.Delete, null, String.Format("Purged client: {0}", clientRecord.Name)); }
/// <summary> /// Populates a ClientRecord's Security and ClientEntries list from the database. /// </summary> /// <param name="client"></param> /// <remarks> /// This method is horrifically long and is due for refactoring. /// </remarks> public void Refresh(ClientRecord client) { //preconditions if (!this.Connected) throw new InvalidOperationException("Cannot get the list of entries for this client because the database is not connected."); if (!this.Authenticated) throw new InvalidOperationException("Cannot get the list of entries for this client because the current user is not authenticated with the Database."); RefreshDefaultSecurity(); RefreshClientSecurityInternal(client); if ((client.Security.Count == 0 && this.DefaultSecurity.CheckIsAllowedView(this.CurrentUser)) || client.Security.CheckIsAllowedView(this.CurrentUser)) { RefreshClientEntriesInternal(client); } else { client.RemoveEntries(client.Entries); } }
private void RefreshClientEntriesInternal(ClientRecord client) { //preparation int clientId = _clients[client]; if (!_clients.TryGetKey(client, out clientId)) throw new ArgumentException("The specified client is not in this database."); var newEntries = new List<ClientEntry>(); var prevEntryIds = client.Entries.Select(e => _entries[e]).ToList(); //Query the Database var getListCommand = new SqlCommand("sp_GetClientEntries", _connection) { CommandType = System.Data.CommandType.StoredProcedure }; getListCommand.Parameters.Add(new SqlParameter("token", "null_token")); //TODO: token will go here getListCommand.Parameters.Add(new SqlParameter("client_id", clientId)); using (var reader = getListCommand.ExecuteReader()) { //result set 1: entry list for the specified client while (reader.Read()) { ClientEntry entry; int clientEntryDbId = (int)reader[0]; //index the entry if it is new if (!_entries.TryGetItem(clientEntryDbId, out entry)) { entry = new ClientEntry(); _entries.Add(clientEntryDbId, entry); newEntries.Add(entry); } //update the properties of the entry, regardless if it existed before entry.Name = (string)reader[2]; entry.IconIndex = (int)reader[3]; entry.Notes = WebUtility.HtmlDecode((reader[5] as string ?? String.Empty).Replace("<br>", Environment.NewLine)); //set the template, it will get updated later if it doesn't exist yet //we index the new template right away EntryTemplate template; int templateId = (reader[4] == DBNull.Value) ? -1 : (int)reader[4]; if (templateId == -1) { template = null; //orphaned record } else if (!_templates.TryGetItem(templateId, out template)) { template = new EntryTemplate(); _templates.Add(templateId, template); } entry.Template = template; } //result set 2: template definition reader.NextResult(); while (reader.Read()) { EntryTemplate template; int templateDbId = (int)reader[0]; if (!_templates.TryGetItem(templateDbId, out template)) throw new InvalidOperationException("A template was returned that was not part of the first result set."); //update the properties template.Name = reader[1] as string; template.IconIndex = (int)reader[2]; template.AllowCustomFields = (bool)reader[3]; } //result set 3: fields for the previous templates reader.NextResult(); while (reader.Read()) { EntryField templateField; EntryTemplate template; int templateFieldId = (int)reader[0]; int templateId = (int)reader[1]; if (!_templates.TryGetItem(templateId, out template)) throw new InvalidOperationException("A template field was returned that belongs to a template that was not returned in the previous result set."); if (!_templateFields.TryGetItem(templateFieldId, out templateField)) { templateField = new EntryField(); _templateFields.Add(templateFieldId, templateField); } if (!template.Fields.Contains(templateField)) template.AddField(templateField); //update the properties templateField.Name = reader[2] as string; templateField.EntryType = (EntryFieldType)reader[3]; templateField.DefaultValue = reader[4] as string; } //TODO: remove any fields that were not returned //result set 4: field values reader.NextResult(); while (reader.Read()) { int fieldValueId = (int)reader[0]; int entryId = (int)reader[1]; ClientEntry entry; if (!_entries.TryGetItem(entryId, out entry)) throw new InvalidOperationException("A ClientEntry was returned that was not defined in a previous result set."); int templateFieldId = (reader[2] == DBNull.Value) ? -1 : (int)reader[2]; string entryValue = reader[4] as string; //indexing of fields values: // template field values are indexed by TFVR objects in the _templateFieldsById dictionary // custom field values are indexed by just the EntryField object in the _customFieldsById dictionary if (templateFieldId == -1) { //custom field string fieldName = reader[3] as string; EntryField customField; if (!_customFields.TryGetItem(fieldValueId, out customField)) { customField = new EntryField() { Name = fieldName }; //todo: type entry.AddCustomField(customField); _customFields.Add(fieldValueId, customField); } //update the name and value customField.Name = fieldName; entry.SetValue(customField, DataSecurity.DecryptStringAES(entryValue)); } else { //find the template EntryField by ID EntryField templateField; if (_templateFields.TryGetItem(templateFieldId, out templateField)) { //save the ID of the field value for saving later if (!_templateValues.Values.Any(tfvr => tfvr.ClientEntry == entry && tfvr.TemplateField == templateField)) _templateValues.Add(fieldValueId, new TemplateFieldValueRelation() { ClientEntry = entry, TemplateField = templateField }); entry.SetValue(templateField, DataSecurity.DecryptStringAES(entryValue)); } else { throw new InvalidOperationException("A template field was returned that cannot be matched to an existing template."); } } } //TODO: remove any fields that were not returned } //clean up the internal list, and raise events for the UI var deletedEntryIds = prevEntryIds.Except(_entries.Keys).ToList(); if (deletedEntryIds.Any()) { var deletedEntries = new List<ClientEntry>(); foreach (var id in deletedEntryIds) { var entry = _entries[id]; deletedEntries.Add(entry); _entries.Remove(entry); } client.RemoveEntries(deletedEntries); } if (newEntries.Any()) client.AddEntries(newEntries); }