예제 #1
0
        public AddEditClientDialog(ClientRecord clientToEdit)
        {
            InitializeComponent();

            this.ClientRecord = new ClientRecord() { Name = clientToEdit.Name, ClientId = clientToEdit.ClientId };
            clientRecordBindingSource.DataSource = this.ClientRecord;

            this.Text = "Rename Client";
            commitButton.Text = "Save";
        }
예제 #2
0
        public PurgeClientDialog(ClientRecord client)
        {
            InitializeComponent();

            mainInstructionLabel.Text = String.Format(mainInstructionLabel.Text, client.Name);
        }
예제 #3
0
 public ClientRecordEventArgs(ClientRecord client)
 {
     this.ClientRecords = new[] { client };
 }
예제 #4
0
        private void DisplayClient(ClientRecord currentClient)
        {
            if (_editMode)
                EndEditMode();

            //stop listening to the old client
            if (_activeClient != null)
            {
                _activeClient.EntriesAdded -= ClientRecord_EntryAdded;
                _activeClient.EntriesRemoved -= ClientRecord_EntryRemoved;

                foreach (var e in _activeClient.Entries)
                {
                    e.PropertyChanged -= ClientEntry_PropertyChanged;
                }
            }

            entryListView.Items.Clear();
            _currentClientFields.Clear();
            _entryNotes.Clear();

            entryListView.Enabled = (currentClient != null);
            clientNameLabel.Enabled = (currentClient != null);

            _activeClient = currentClient;

            if (currentClient != null)
            {
                activeClientBindingSource.DataSource = currentClient;

                _activeClient.EntriesAdded += new EventHandler<ClientEntryEventArgs>(ClientRecord_EntryAdded);
                _activeClient.EntriesRemoved += new EventHandler<ClientEntryEventArgs>(ClientRecord_EntryRemoved);

                //since the listview doesn't support databinding, we need to simulate it by populating it and listening
                //for changes for both the entry list and each entry
                foreach (var entry in currentClient.Entries)
                {
                    AddEntryToListView(entry);
                }

                entryListView.SelectedItems.Clear();
                if (entryListView.Items.Count > 0)
                    entryListView.Items[0].Selected = true;
                else
                    DisplaySelectedEntry();

                bool editAllowed = currentClient.Security.CheckIsAllowedEdit(this.CurrentDatabase.CurrentUser);

                renameClientToolStripMenuItem.Enabled = editAllowed;
                editButton.Enabled = editAllowed;
                purgeClientToolStripMenuItem.Enabled = editAllowed;
                editModeToolStripMenuItem.Enabled = editAllowed;
                addEntryToolStripMenuItem.Enabled = editAllowed;
                addEntryButton.Enabled = editAllowed;
                deleteEntryToolStripMenuItem.Enabled = editAllowed;
                renameEntryToolStripMenuItem.Enabled = editAllowed;
                securityToolStripMenuItem.Enabled = this.CurrentDatabase.CurrentUser.IsAdmin;
                securityToolStripMenuItem1.Enabled = this.CurrentDatabase.CurrentUser.IsAdmin;
            }
            else
            {
                activeClientBindingSource.DataSource = typeof(ClientRecord);

                renameClientToolStripMenuItem.Enabled = false;
                editButton.Enabled = false;
                purgeClientToolStripMenuItem.Enabled = false;
                editModeToolStripMenuItem.Enabled = false;
                addEntryButton.Enabled = false;
                addEntryToolStripMenuItem.Enabled = false;
                deleteEntryToolStripMenuItem.Enabled = false;
                renameEntryToolStripMenuItem.Enabled = false;
                securityToolStripMenuItem.Enabled = false;
                securityToolStripMenuItem1.Enabled = false;
            }
        }
예제 #5
0
        private void RecordCurrentClientOnHeaderMouseDown(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.RowIndex != -1)
                return;

            _presortClient = clientListBindingSource.Current as ClientRecord;
        }
예제 #6
0
        /// <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);
            }
        }
예제 #7
0
        /// <summary>
        /// Refreshes the list of clients from the database.
        /// </summary>
        public void RefreshClientList()
        {
            if (!this.Connected)
                throw new InvalidOperationException("Cannot get the list of clients because the database is not connected.");
            if (!this.Authenticated)
                throw new InvalidOperationException("Cannot get the list of clients because the current user is not authenticated with the Database.");

            var getListCommand = new SqlCommand("sp_GetClientList", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
            getListCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here

            var newClients = new List<ClientRecord>();
            var prevClientIds = _clients.Keys.ToList();

            using (var reader = getListCommand.ExecuteReader())
            {
                while (reader.Read())
                {
                    ClientRecord client;
                    int clientDbId = (int)reader[0];

                    if (!_clients.TryGetItem(clientDbId, out client))
                    {
                        client = new ClientRecord();
                        client.Security.Parent = this.DefaultSecurity;
                        _clients.Add(clientDbId, client);
                        newClients.Add(client);
                    }

                    //update the properties of the client, regardless if it existed before
                    client.Name = (string)reader[1];
                    client.ClientId = reader[2] as string;
                }
            }

            //clean up the internal list, and raise events for the UI
            var deletedClientIds = prevClientIds.Except(_clients.Keys);
            if (deletedClientIds.Any())
            {
                var deletedClients = new List<ClientRecord>();
                foreach (var id in deletedClientIds)
                {
                    deletedClients.Add(_clients[id]);
                    _clients.Remove(id);
                }

                OnClientsRemoved(new ClientRecordEventArgs(deletedClients));
            }

            if (newClients.Any())
                OnClientsAdded(new ClientRecordEventArgs(newClients));
        }
예제 #8
0
        public void CommitClientSecurity(ClientRecord clientRecord)
        {
            if (clientRecord == null)
                throw new ArgumentNullException("clientRecord");

            int clientId;
            if (!_clients.TryGetKey(clientRecord, out clientId))
                throw new ArgumentException("The client specified does not exist in this database.");
            if (!this.Connected)
                throw new InvalidOperationException("Cannot commit the security settings because the database is not connected.");
            if (!this.Authenticated)
                throw new InvalidOperationException("Cannot commit the security settings because the current user is not authenticated with the Database.");

            //prepare the query in a format understood by sp_UpdateEntryValues
            var query = new XElement("Security");
            foreach (var descriptor in clientRecord.Security)
            {
                XElement descriptorElement = new XElement("Descriptor",
                    new XAttribute("view", descriptor.ViewAllowed),
                    new XAttribute("edit", descriptor.EditingAllowed));

                if (descriptor.SecurityPrincipal is UserPrincipal)
                {
                    int userId;
                    if (!_users.TryGetKey((UserPrincipal)descriptor.SecurityPrincipal, out userId))
                        throw new ArgumentException(String.Format("The user '{0}' does not have a valid user ID.", descriptor.SecurityPrincipal.Name));

                    descriptorElement.Add(new XAttribute("userId", userId));
                }
                else if (descriptor.SecurityPrincipal is GroupPrincipal)
                {
                    if (descriptor.SecurityPrincipal != GroupPrincipal.Everyone)
                    {
                        int groupId;
                        if (!_groups.TryGetKey((GroupPrincipal)descriptor.SecurityPrincipal, out groupId))
                            throw new ArgumentException(String.Format("The group '{0}' does not have a valid user ID.", descriptor.SecurityPrincipal.Name));

                        descriptorElement.Add(new XAttribute("groupId", groupId));
                    }
                }
                else
                {
                    throw new NotSupportedException(String.Format("Security Principals of type '{0}' are not supported by PogsDatabase.", descriptor.SecurityPrincipal.GetType().Name));
                }

                query.Add(descriptorElement);
            }

            //Query the Database
            var updateCommand = new SqlCommand("sp_UpdateClientSecurity", _connection) { CommandType = CommandType.StoredProcedure };
            updateCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here
            updateCommand.Parameters.Add(new SqlParameter("clientId", clientId));
            updateCommand.Parameters.Add(new SqlParameter("updateXml", query.ToString()));

            updateCommand.ExecuteNonQuery();

            AddLogEntryInternal(UserLogEntryType.Edit, clientRecord, "Changed Security Settings");
        }
예제 #9
0
        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));
        }
예제 #10
0
        /// <summary>
        /// Updates the Database with any changed client name, id, or entry additions or deletions.
        /// </summary>
        /// <param name="clientRecord"></param>
        public void CommitClient(ClientRecord clientRecord)
        {
            if (clientRecord == null)
                throw new ArgumentNullException("clientRecord");

            int clientId;
            if (!_clients.TryGetKey(clientRecord, out clientId))
                throw new ArgumentException("Cannot commit this client because it does not exist in this database.");

            //update general information about the client
            var renameCommand = new SqlCommand("sp_UpdateClientName", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
            renameCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here
            renameCommand.Parameters.Add(new SqlParameter("clientId", clientId));
            renameCommand.Parameters.Add(new SqlParameter("clientName", clientRecord.Name));
            renameCommand.Parameters.Add(new SqlParameter("clientNumber", clientRecord.ClientId));
            renameCommand.ExecuteNonQuery();

            //add new entries
            var newEntries = clientRecord.Entries.Where(e => !_entries.ContainsItem(e)).ToList();
            if (newEntries.Any())
            {
                var query = new XElement("Entries",
                    from e in newEntries
                    select new XElement("Entry",
                        new XAttribute("client_id", clientId),
                        new XAttribute("template_id", e.Template == null ? 0 : _templates[e.Template]),
                        new XAttribute("icon_id", e.IconIndex),
                        new XAttribute("name", e.Name)));

                var updateCommand = new SqlCommand("sp_AddEntries", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
                updateCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here
                updateCommand.Parameters.Add(new SqlParameter("addXml", query.ToString()));

                //assign ids to the new entries
                using (var reader = updateCommand.ExecuteReader())
                {
                    int i = 0;
                    while (reader.Read())
                    {
                        if (i >= newEntries.Count)
                            throw new InvalidOperationException("The database returned more new entires than expected.");

                        int entryId = (int)reader[0];
                        _entries.Add(entryId, newEntries[i]);

                        i++;
                    }

                    if (i < newEntries.Count)
                        throw new InvalidOperationException("The database returned less new entries than expected.");
                }

                foreach (var e in newEntries)
                    AddLogEntry(e, UserLogEntryType.Add);
            }

            //delete
            var deletedEntries = _entries.Items.Where(e => e.Client == clientRecord).Except(clientRecord.Entries).ToList();
            if (deletedEntries.Any())
            {
                var query = new XElement("Entries",
                    from e in deletedEntries
                    select new XElement("Entry",
                        new XAttribute("id", _entries[e])));

                var deleteCommand = new SqlCommand("sp_DeleteEntries", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
                deleteCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here
                deleteCommand.Parameters.Add(new SqlParameter("deleteXml", query.ToString()));
                deleteCommand.ExecuteNonQuery();

                //TODO: check count

                foreach (var entry in deletedEntries)
                {
                    //remove the custom field values from memory
                    foreach (var field in entry.CustomFields)
                    {
                        _customFields.Remove(field);
                    }

                    //remove the template field values from memory
                    if (entry.Template != null)
                    {
                        var values = _templateValues
                                .Where(kvp => kvp.Value.ClientEntry == entry)
                                .ToList();

                        foreach (var v in values)
                        {
                            _templateValues.Remove(v.Key);
                        }
                    }

                    //remove the IDs from memory
                    _entries.Remove(entry);
                }

                foreach (var e in deletedEntries)
                    AddLogEntry(e, UserLogEntryType.Delete);
            }
        }
예제 #11
0
        private void RefreshClientSecurityInternal(ClientRecord client)
        {
            var getDefaultSecurityCommand = new SqlCommand("sp_GetClientSecurity", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
            getDefaultSecurityCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here
            getDefaultSecurityCommand.Parameters.Add(new SqlParameter("clientId", _clients[client]));

            using (var reader = getDefaultSecurityCommand.ExecuteReader())
            {
                client.Security.Clear();

                while (reader.Read())
                {
                    int userId = reader.IsDBNull(0) ? -1 : (int)reader[0];
                    int groupId = reader.IsDBNull(1) ? -1 : (int)reader[1];

                    if (userId != -1 && groupId != -1)
                        throw new InvalidOperationException("An invalid default security record was received from the Database.");

                    SecurityPrincipal target;
                    bool createdNew = false;
                    if (userId != -1)
                        target = CreateOrUpdateUser(reader, 0, -1, -1, out createdNew);
                    else if (groupId != -1)
                        target = CreateOrUpdateGroup(reader, 1, -1, -1, out createdNew);
                    else
                        target = GroupPrincipal.Everyone;   //both null means everyone

                    if (createdNew)
                        OnPrincipalsAdded(new SecurityPrincipalsEventArgs(target));

                    client.Security.Add(new SecurityDescriptor(target, (bool)reader[3], (bool)reader[2]));
                }
            }
        }
예제 #12
0
        public void AddNewClient(ClientRecord clientRecord)
        {
            if (!this.Connected)
                throw new InvalidOperationException("Cannot add the client because the database is not connected.");
            if (!this.Authenticated)
                throw new InvalidOperationException("Cannot add the client because the current user is not authenticated with the Database.");
            if (clientRecord == null)
                throw new ArgumentNullException("clientRecord");
            if (_clients.ContainsItem(clientRecord))
                throw new ArgumentException("Cannot add this client because it already exists in this database.");

            //execute the stored procedure
            var addCommand = new SqlCommand("sp_AddClient", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
            addCommand.Parameters.Add(new SqlParameter("token", "null_token"));    //TODO: token will go here
            addCommand.Parameters.Add(new SqlParameter("client_name", clientRecord.Name));
            addCommand.Parameters.Add(new SqlParameter("client_id", clientRecord.ClientId));

            //assign the IDs
            int newId = (int)addCommand.ExecuteScalar();
            _clients.Add(newId, clientRecord);
            clientRecord.Security.Parent = this.DefaultSecurity;

            //raise events
            OnClientsAdded(new ClientRecordEventArgs(clientRecord));

            AddLogEntryInternal(UserLogEntryType.Add, clientRecord, String.Format("Added new client: {0}", clientRecord.Name));
        }
예제 #13
0
        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);
        }
예제 #14
0
        private void AddLogEntryInternal(UserLogEntryType entryType, ClientRecord client, string description)
        {
            //send the command
            var addLogEntryCommand = new SqlCommand("sp_AddLogEntry", _connection) { CommandType = System.Data.CommandType.StoredProcedure };
            addLogEntryCommand.Parameters.Add(new SqlParameter("username", this.CurrentUser.Name));
            addLogEntryCommand.Parameters.Add(new SqlParameter("actiontype", (int)entryType));
            addLogEntryCommand.Parameters.Add(new SqlParameter("clientid", client == null ? -1 : _clients[client]));
            addLogEntryCommand.Parameters.Add(new SqlParameter("description", description));

            addLogEntryCommand.ExecuteNonQuery();
        }