using System; using System.Collections.Generic; using System.Text; using ScrewTurn.Wiki.PluginFramework; using System.Data.Common; namespace ScrewTurn.Wiki.Plugins.SqlCommon { /// /// Implements a base class for a SQL users storage provider. /// public abstract class SqlUsersStorageProviderBase : SqlStorageProviderBase, IUsersStorageProviderV30 { #region IUsersStorageProvider Members /// /// Tests a Password for a User account. /// /// The User account. /// The Password to test. /// True if the Password is correct. /// If or are null. public bool TestAccount(UserInfo user, string password) { if(user == null) throw new ArgumentNullException("user"); if(password == null) throw new ArgumentNullException("password"); return TryManualLogin(user.Username, password) != null; } /// /// Gets the complete list of Users. /// /// All the Users, sorted by username. public UserInfo[] GetUsers() { ICommandBuilder builder = GetCommandBuilder(); string query = QueryBuilder.NewQuery(builder).SelectFrom( "User", "UserGroupMembership", "Username", "User", Join.LeftJoin, new string[] { "Username", "DisplayName", "Email", "Active", "DateTime" }, new string[] { "UserGroup" }); DbCommand command = builder.GetCommand(connString, query, new List()); DbDataReader reader = ExecuteReader(command); if(reader != null) { List result = new List(100); string prevUsername = "|||"; string username = null; string displayName; string email; bool active; DateTime dateTime; List groups = new List(5); while(reader.Read()) { username = reader["User_Username"] as string; if(username != prevUsername) { // Set previous user's groups if(prevUsername != "|||") { result[result.Count - 1].Groups = groups.ToArray(); groups.Clear(); } // Read new data displayName = GetNullableColumn(reader, "User_DisplayName", null); email = reader["User_Email"] as string; active = (bool)reader["User_Active"]; dateTime = (DateTime)reader["User_DateTime"]; // Append new user result.Add(new UserInfo(username, displayName, email, active, dateTime, this)); } // Keep reading groups prevUsername = username; if(!IsDBNull(reader, "UserGroupMembership_UserGroup")) { groups.Add(reader["UserGroupMembership_UserGroup"] as string); } } if(result.Count > 0) { result[result.Count - 1].Groups = groups.ToArray(); } CloseReader(command, reader); return result.ToArray(); } else return null; } /// /// Adds a new User. /// /// The Username. /// The display name (can be null). /// The Password. /// The Email address. /// A value indicating whether the account is active. /// The Account creation Date/Time. /// The correct object or null. /// If , or are null. /// If , or are empty. public UserInfo AddUser(string username, string displayName, string password, string email, bool active, DateTime dateTime) { if(username == null) throw new ArgumentNullException("username"); if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username"); if(password == null) throw new ArgumentNullException("password"); if(password.Length == 0) throw new ArgumentException("Password cannot be empty", "password"); if(email == null) throw new ArgumentNullException("email"); if(email.Length == 0) throw new ArgumentException("Email cannot be empty", "email"); ICommandBuilder builder = GetCommandBuilder(); string query = QueryBuilder.NewQuery(builder).InsertInto("User", new string[] { "Username", "PasswordHash", "DisplayName", "Email", "Active", "DateTime" }, new string[] { "Username", "PasswordHash", "DisplayName", "Email", "Active", "DateTime" }); List parameters = new List(6); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "PasswordHash", Hash.Compute(password))); if(string.IsNullOrEmpty(displayName)) parameters.Add(new Parameter(ParameterType.String, "DisplayName", DBNull.Value)); else parameters.Add(new Parameter(ParameterType.String, "DisplayName", displayName)); parameters.Add(new Parameter(ParameterType.String, "Email", email)); parameters.Add(new Parameter(ParameterType.Boolean, "Active", active)); parameters.Add(new Parameter(ParameterType.DateTime, "DateTime", dateTime)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); if(rows == 1) { return new UserInfo(username, displayName, email, active, dateTime, this); } else return null; } /// /// Gets the user groups of a user. /// /// A database transaction. /// The username. /// The groups. private string[] GetUserGroups(DbTransaction transaction, string username) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("UserGroupMembership", new string[] { "UserGroup" }); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(transaction, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List result = new List(5); while(reader.Read()) { result.Add(reader["UserGroup"] as string); } CloseReader(reader); return result.ToArray(); } else return null; } /// /// Gets the user groups of a user. /// /// A database connection. /// The username. /// The groups. private string[] GetUserGroups(DbConnection connection, string username) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("UserGroupMembership", new string[] { "UserGroup" }); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List result = new List(5); while(reader.Read()) { result.Add(reader["UserGroup"] as string); } CloseReader(reader); return result.ToArray(); } else return null; } /// /// Modifies a User. /// /// The Username of the user to modify. /// The new display name (can be null). /// The new Password (null or blank to keep the current password). /// The new Email address. /// A value indicating whether the account is active. /// The correct object or null. /// If user or newEmail are null. /// If newEmail is empty. public UserInfo ModifyUser(UserInfo user, string newDisplayName, string newPassword, string newEmail, bool newActive) { if(user == null) throw new ArgumentNullException("user"); if(newEmail == null) throw new ArgumentNullException("newEmail"); if(newEmail.Length == 0) throw new ArgumentException("New Email cannot be empty", "newEmail"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = ""; if(string.IsNullOrEmpty(newPassword)) { query = queryBuilder.Update("User", new string[] { "DisplayName", "Email", "Active", }, new string[] { "DisplayName", "Email", "Active", }); } else { query = queryBuilder.Update("User", new string[] { "PasswordHash", "DisplayName", "Email", "Active", }, new string[] { "PasswordHash", "DisplayName", "Email", "Active", }); } query = queryBuilder.Where(query, "Username", WhereOperator.Equals, "Username"); List parameters = new List(5); if(!string.IsNullOrEmpty(newPassword)) { parameters.Add(new Parameter(ParameterType.String, "PasswordHash", Hash.Compute(newPassword))); } if(string.IsNullOrEmpty(newDisplayName)) parameters.Add(new Parameter(ParameterType.String, "DisplayName", DBNull.Value)); else parameters.Add(new Parameter(ParameterType.String, "DisplayName", newDisplayName)); parameters.Add(new Parameter(ParameterType.String, "Email", newEmail)); parameters.Add(new Parameter(ParameterType.Boolean, "Active", newActive)); parameters.Add(new Parameter(ParameterType.String, "Username", user.Username)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) { UserInfo result = new UserInfo(user.Username, newDisplayName, newEmail, newActive, user.DateTime, this); result.Groups = GetUserGroups(transaction, user.Username); CommitTransaction(transaction); return result; } else { RollbackTransaction(transaction); return null; } } /// /// Removes a User. /// /// The User to remove. /// True if the User has been removed successfully. /// If user is null. public bool RemoveUser(UserInfo user) { if(user == null) throw new ArgumentNullException("user"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("User"); query = queryBuilder.Where(query, "Username", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", user.Username)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); return rows == 1; } /// /// Gets all the user groups. /// /// All the groups, sorted by name. public UserGroup[] GetUserGroups() { ICommandBuilder builder = GetCommandBuilder(); string query = QueryBuilder.NewQuery(builder).SelectFrom( "UserGroup", "UserGroupMembership", "Name", "UserGroup", Join.LeftJoin, new string[] { "Name", "Description" }, new string[] { "User" }); DbCommand command = builder.GetCommand(connString, query, new List()); DbDataReader reader = ExecuteReader(command); string previousName = "|||"; string name = null; string description; List users = new List(50); if(reader != null) { List result = new List(5); while(reader.Read()) { name = reader["UserGroup_Name"] as string; if(name != previousName) { // Set previous group's users if(previousName != "|||") { result[result.Count - 1].Users = users.ToArray(); users.Clear(); } // Read new data description = reader["UserGroup_Description"] as string; // Append new group result.Add(new UserGroup(name, description, this)); } // Keep reading users previousName = name; if(!IsDBNull(reader, "UserGroupMembership_User")) { users.Add(reader["UserGroupMembership_User"] as string); } } if(result.Count > 0) { result[result.Count - 1].Users = users.ToArray(); } CloseReader(command, reader); return result.ToArray(); } else return null; } /// /// Adds a new user group. /// /// The name of the group. /// The description of the group. /// The correct object or null. /// If name or description are null. /// If name is empty. public UserGroup AddUserGroup(string name, string description) { if(name == null) throw new ArgumentNullException("name"); if(name.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); if(description == null) throw new ArgumentNullException("description"); ICommandBuilder builder = GetCommandBuilder(); string query = QueryBuilder.NewQuery(builder).InsertInto("UserGroup", new string[] { "Name", "Description" }, new string[] { "Name", "Description" }); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Name", name)); parameters.Add(new Parameter(ParameterType.String, "Description", description)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); if(rows == 1) { return new UserGroup(name, description, this); } else return null; } /// /// Gets the users of a group. /// /// A database transaction. /// The group. /// The users. private string[] GetUserGroupUsers(DbTransaction transaction, string group) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("UserGroupMembership", new string[] { "User" }); query = queryBuilder.Where(query, "UserGroup", WhereOperator.Equals, "UserGroup"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "UserGroup", group)); DbCommand command = builder.GetCommand(transaction, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List result = new List(100); while(reader.Read()) { result.Add(reader["User"] as string); } CloseReader(reader); return result.ToArray(); } else return null; } /// /// Gets the users of a group. /// /// A database connection. /// The group. /// The users. private string[] GetUserGroupUsers(DbConnection connection, string group) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("UserGroupMembership", new string[] { "User" }); query = queryBuilder.Where(query, "UserGroup", WhereOperator.Equals, "UserGroup"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "UserGroup", group)); DbCommand command = builder.GetCommand(connection, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { List result = new List(100); while(reader.Read()) { result.Add(reader["User"] as string); } CloseReader(reader); return result.ToArray(); } else return null; } /// /// Modifies a user group. /// /// The group to modify. /// The new description of the group. /// The correct object or null. /// If group or description are null. public UserGroup ModifyUserGroup(UserGroup group, string description) { if(group == null) throw new ArgumentNullException("group"); if(description == null) throw new ArgumentNullException("description"); ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.Update("UserGroup", new string[] { "Description" }, new string[] { "Description" }); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Description", description)); parameters.Add(new Parameter(ParameterType.String, "Name", group.Name)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) { UserGroup result = new UserGroup(group.Name, description, this); result.Users = GetUserGroupUsers(transaction, group.Name); CommitTransaction(transaction); return result; } else { RollbackTransaction(transaction); return null; } } /// /// Removes a user group. /// /// The group to remove. /// true if the group is removed, false otherwise. /// If group is null. public bool RemoveUserGroup(UserGroup group) { if(group == null) throw new ArgumentNullException("group"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("UserGroup"); query = queryBuilder.Where(query, "Name", WhereOperator.Equals, "Name"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Name", group.Name)); DbCommand command = builder.GetCommand(connString, query, parameters); int rows = ExecuteNonQuery(command); return rows == 1; } /// /// Verifies that a user exists. /// /// A database transaction. /// The username. /// true if the user exists, false otherwise. private bool UserExists(DbTransaction transaction, string username) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("User"); query = queryBuilder.Where(query, "Username", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(transaction, query, parameters); int count = ExecuteScalar(command, -1, false); return count == 1; } /// /// Verifies that a user exists. /// /// A database connection. /// The username. /// true if the user exists, false otherwise. private bool UserExists(DbConnection connection, string username) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectCountFrom("User"); query = queryBuilder.Where(query, "Username", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(connection, query, parameters); int count = ExecuteScalar(command, -1, false); return count == 1; } /// /// Removes the user group membership for a user. /// /// A database transaction. /// The username. private void RemoveUserGroupMembership(DbTransaction transaction, string username) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("UserGroupMembership"); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(transaction, query, parameters); ExecuteNonQuery(command, false); } /// /// Sets the group memberships of a user account. /// /// The user account. /// The groups the user account is member of. /// The correct object or null. /// If user or groups are null. public UserInfo SetUserMembership(UserInfo user, string[] groups) { if(user == null) throw new ArgumentNullException("user"); if(groups == null) throw new ArgumentNullException("groups"); // 1. Remove old user group membership // 2. Add new memberships, one by one ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); if(!UserExists(transaction, user.Username)) { RollbackTransaction(transaction); return null; } RemoveUserGroupMembership(transaction, user.Username); string query = QueryBuilder.NewQuery(builder).InsertInto("UserGroupMembership", new string[] { "User", "UserGroup" }, new string[] { "User", "UserGroup" }); foreach(string group in groups) { List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "User", user.Username)); parameters.Add(new Parameter(ParameterType.String, "UserGroup", group)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows != 1) { RollbackTransaction(transaction); return null; } } UserInfo result = new UserInfo(user.Username, user.DisplayName, user.Email, user.Active, user.DateTime, this); result.Groups = groups; CommitTransaction(transaction); return result; } /// /// Tries to login a user directly through the provider. /// /// The username. /// The password. /// The correct UserInfo object, or null. /// If username or password are null. public UserInfo TryManualLogin(string username, string password) { if(username == null) throw new ArgumentNullException("username"); if(password == null) throw new ArgumentNullException("password"); // Shortcut if(username.Length == 0) return null; if(password.Length == 0) return null; ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom( "User", "UserGroupMembership", "Username", "User", Join.LeftJoin, new string[] { "Username", "PasswordHash", "DisplayName", "Email", "Active", "DateTime" }, new string[] { "UserGroup" }); query = queryBuilder.Where(query, "User", "Username", WhereOperator.Equals, "Username"); query = queryBuilder.AndWhere(query, "User", "PasswordHash", WhereOperator.Equals, "PasswordHash"); string providedPasswordHash = Hash.Compute(password); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "PasswordHash", providedPasswordHash)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { UserInfo result = null; string realUsername = null; string passwordHash = null; string displayName; string email; bool active; DateTime dateTime; List groups = new List(5); while(reader.Read()) { if(result == null) { // Read data realUsername = reader["User_Username"] as string; passwordHash = reader["User_PasswordHash"] as string; displayName = GetNullableColumn(reader, "User_DisplayName", null); email = reader["User_Email"] as string; active = (bool)reader["User_Active"]; dateTime = (DateTime)reader["User_DateTime"]; // Create user result = new UserInfo(realUsername, displayName, email, active, dateTime, this); } // Keep reading groups if(!IsDBNull(reader, "UserGroupMembership_UserGroup")) { groups.Add(reader["UserGroupMembership_UserGroup"] as string); } } if(result != null) { result.Groups = groups.ToArray(); } CloseReader(command, reader); if(result != null) { if(result.Active && string.CompareOrdinal(result.Username, username) == 0 && string.CompareOrdinal(passwordHash, providedPasswordHash) == 0) { return result; } else return null; } else return null; } else return null; } /// /// Tries to login a user directly through the provider using /// the current HttpContext and without username/password. /// /// The current HttpContext. /// The correct UserInfo object, or null. /// If context is null. public UserInfo TryAutoLogin(System.Web.HttpContext context) { if(context == null) throw new ArgumentNullException("context"); return null; } /// /// Gets a user account. /// /// The username. /// The , or null. /// If username is null. /// If username is empty. public UserInfo GetUser(string username) { if(username == null) throw new ArgumentNullException("username"); if(username.Length == 0) throw new ArgumentException("Username cannot be empty", "username"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom( "User", "UserGroupMembership", "Username", "User", Join.LeftJoin, new string[] { "Username", "DisplayName", "Email", "Active", "DateTime" }, new string[] { "UserGroup" }); query = queryBuilder.Where(query, "User", "Username", WhereOperator.Equals, "Username"); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Username", username)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { UserInfo result = null; string realUsername = null; string displayName; string email; bool active; DateTime dateTime; List groups = new List(5); while(reader.Read()) { if(result == null) { // Read data realUsername = reader["User_Username"] as string; displayName = GetNullableColumn(reader, "User_DisplayName", null); email = reader["User_Email"] as string; active = (bool)reader["User_Active"]; dateTime = (DateTime)reader["User_DateTime"]; // Create user result = new UserInfo(realUsername, displayName, email, active, dateTime, this); } // Keep reading groups if(!IsDBNull(reader, "UserGroupMembership_UserGroup")) { groups.Add(reader["UserGroupMembership_UserGroup"] as string); } } if(result != null) { result.Groups = groups.ToArray(); } CloseReader(command, reader); return result; } else return null; } /// /// Gets a user account. /// /// The email address. /// The first user found with the specified email address, or null. /// If email is null. /// If email is empty. public UserInfo GetUserByEmail(string email) { if(email == null) throw new ArgumentNullException("email"); if(email.Length == 0) throw new ArgumentException("Email cannot be empty", "email"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom( "User", "UserGroupMembership", "Username", "User", Join.LeftJoin, new string[] { "Username", "DisplayName", "Email", "Active", "DateTime" }, new string[] { "UserGroup" }); query = queryBuilder.Where(query, "User", "Email", WhereOperator.Equals, "Email"); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Email", email)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { UserInfo result = null; string username = null; string displayName; string realEmail = null; bool active; DateTime dateTime; List groups = new List(5); while(reader.Read()) { if(result == null) { // Read data username = reader["User_Username"] as string; displayName = GetNullableColumn(reader, "User_DisplayName", null); realEmail = reader["User_Email"] as string; active = (bool)reader["User_Active"]; dateTime = (DateTime)reader["User_DateTime"]; // Create user result = new UserInfo(username, displayName, realEmail, active, dateTime, this); } // Keep reading groups if(!IsDBNull(reader, "UserGroupMembership_UserGroup")) { groups.Add(reader["UserGroupMembership_UserGroup"] as string); } } if(result != null) { result.Groups = groups.ToArray(); } CloseReader(command, reader); return result; } else return null; } /// /// Notifies the provider that a user has logged in through the authentication cookie. /// /// The user who has logged in. /// If user is null. public void NotifyCookieLogin(UserInfo user) { if(user == null) throw new ArgumentNullException("user"); // Nothing to do } /// /// Notifies the provider that a user has logged out. /// /// The user who has logged out. /// If user is null. public void NotifyLogout(UserInfo user) { if(user == null) throw new ArgumentNullException("user"); // Nothing to do } /// /// Removes a user data element. /// /// A database transaction. /// The username. /// The key. /// true if the data element is removed, false otherwise. private bool RemoveUserData(DbTransaction transaction, string username, string key) { ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.DeleteFrom("UserData"); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); query = queryBuilder.AndWhere(query, "Key", WhereOperator.Equals, "Key"); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Username", username)); parameters.Add(new Parameter(ParameterType.String, "Key", key)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); return rows != -1; // Success also if no elements are removed } /// /// Stores a user data element, overwriting the previous one if present. /// /// The user the data belongs to. /// The key of the data element (case insensitive). /// The value of the data element, null for deleting the data. /// true if the data element is stored, false otherwise. /// If user or key are null. /// If key is empty. public bool StoreUserData(UserInfo user, string key, string value) { if(user == null) throw new ArgumentNullException("user"); if(key == null) throw new ArgumentNullException("key"); if(key.Length == 0) throw new ArgumentException("Key cannot be empty", "key"); // 1. Remove previous key, if present // 2. Add new key, if value != null ICommandBuilder builder = GetCommandBuilder(); DbConnection connection = builder.GetConnection(connString); DbTransaction transaction = BeginTransaction(connection); bool done = RemoveUserData(transaction, user.Username, key); if(done) { if(value != null) { string query = QueryBuilder.NewQuery(builder).InsertInto("UserData", new string[] { "User", "Key", "Data" }, new string[] { "Username", "Key", "Data" }); List parameters = new List(3); parameters.Add(new Parameter(ParameterType.String, "Username", user.Username)); parameters.Add(new Parameter(ParameterType.String, "Key", key)); parameters.Add(new Parameter(ParameterType.String, "Data", value)); DbCommand command = builder.GetCommand(transaction, query, parameters); int rows = ExecuteNonQuery(command, false); if(rows == 1) CommitTransaction(transaction); else RollbackTransaction(transaction); return rows == 1; } else { CommitTransaction(transaction); return true; } } else { RollbackTransaction(transaction); return false; } } /// /// Gets a user data element, if any. /// /// The user the data belongs to. /// The key of the data element. /// The value of the data element, or null if the element is not found. /// If user or key are null. /// If key is empty. public string RetrieveUserData(UserInfo user, string key) { if(user == null) throw new ArgumentNullException("user"); if(key == null) throw new ArgumentNullException("key"); if(key.Length == 0) throw new ArgumentException("Key cannot be empty", "key"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("UserData", new string[] { "Data" }); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); query = queryBuilder.AndWhere(query, "Key", WhereOperator.Equals, "Key"); List parameters = new List(2); parameters.Add(new Parameter(ParameterType.String, "Username", user.Username)); parameters.Add(new Parameter(ParameterType.String, "Key", key)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { string data = null; if(reader.Read()) { data = reader["Data"] as string; } CloseReader(command, reader); return data; } else return null; } /// /// Retrieves all the user data elements for a user. /// /// The user. /// The user data elements (key->value). /// If user is null. public IDictionary RetrieveAllUserData(UserInfo user) { if(user == null) throw new ArgumentNullException("user"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("UserData", new string[] { "Key", "Data" }); query = queryBuilder.Where(query, "User", WhereOperator.Equals, "Username"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Username", user.Username)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { Dictionary result = new Dictionary(10); while(reader.Read()) { result.Add(reader["Key"] as string, reader["Data"] as string); } CloseReader(command, reader); return result; } else return null; } /// /// Gets all the users that have the specified element in their data. /// /// The key of the data. /// The users and the data. /// If key is null. /// If key is empty. public IDictionary GetUsersWithData(string key) { if(key == null) throw new ArgumentNullException("key"); if(key.Length == 0) throw new ArgumentException("Key cannot be empty", "key"); ICommandBuilder builder = GetCommandBuilder(); QueryBuilder queryBuilder = new QueryBuilder(builder); string query = queryBuilder.SelectFrom("User", "UserData", "Username", "User", Join.RightJoin, new string[] { "Username", "DisplayName", "Email", "Active", "DateTime" }, new string[] { "Data" }, "UserGroupMembership", "User", Join.LeftJoin, new string[] { "UserGroup" }); query = queryBuilder.Where(query, "UserData", "Key", WhereOperator.Equals, "Key"); List parameters = new List(1); parameters.Add(new Parameter(ParameterType.String, "Key", key)); DbCommand command = builder.GetCommand(connString, query, parameters); DbDataReader reader = ExecuteReader(command); if(reader != null) { Dictionary result = new Dictionary(100); string prevUsername = "|||"; UserInfo prevUser = null; string username = null; string displayName; string email; bool active; DateTime dateTime; string data; List groups = new List(5); while(reader.Read()) { username = reader["User_Username"] as string; if(username != prevUsername) { // Set previous user's groups if(prevUsername != "|||") { prevUser.Groups = groups.ToArray(); groups.Clear(); } // Read new data displayName = GetNullableColumn(reader, "User_DisplayName", null); email = reader["User_Email"] as string; active = (bool)reader["User_Active"]; dateTime = (DateTime)reader["User_DateTime"]; data = reader["UserData_Data"] as string; // Append new user prevUser = new UserInfo(username, displayName, email, active, dateTime, this); result.Add(prevUser, data); } // Keep reading groups prevUsername = username; if(!IsDBNull(reader, "UserGroupMembership_UserGroup")) { groups.Add(reader["UserGroupMembership_UserGroup"] as string); } } if(prevUser != null) { prevUser.Groups = groups.ToArray(); } CloseReader(command, reader); return result; } else return null; } #endregion /// /// Gets a value indicating whether user accounts are read-only. /// public bool UserAccountsReadOnly { get { return false; } } /// /// Gets a value indicating whether user groups are read-only. If so, the provider /// should support default user groups as defined in the wiki configuration. /// public bool UserGroupsReadOnly { get { return false; } } /// /// Gets a value indicating whether group membership is read-only (if /// is false, then this property must be false). If this property is true, the provider /// should return membership data compatible with default user groups. /// public bool GroupMembershipReadOnly { get { return false; } } /// /// Gets a value indicating whether users' data is read-only. /// public bool UsersDataReadOnly { get { return false; } } } }