using System; using System.Collections.Generic; using System.Text; using ScrewTurn.Wiki.PluginFramework; using System.Web; namespace ScrewTurn.Wiki { /// /// Manages all the User Accounts data. /// public static class Users { private static UserInfo adminAccount = null; private static UserInfo anonAccount = null; /// /// Gets the built-in administrator account. /// /// The account. public static UserInfo GetAdministratorAccount() { if(adminAccount == null) { adminAccount = new UserInfo("admin", "Administrator", Settings.ContactEmail, true, DateTime.MinValue, null); adminAccount.Groups = new[] { Settings.AdministratorsGroup }; } return adminAccount; } /// /// Gets the fake anonymous account. /// /// The account. public static UserInfo GetAnonymousAccount() { if(anonAccount == null) { anonAccount = new UserInfo(SessionFacade.AnonymousUsername, null, null, false, DateTime.MinValue, null); anonAccount.Groups = new[] { Settings.AnonymousGroup }; } return anonAccount; } /// /// The user data key pointing to page changes notification entries. /// private const string PageChangesKey = "PageChanges"; /// /// The user data key pointing to discussion messages notification entries. /// private const string DiscussionMessagesKey = "DiscussionMessages"; /// /// The user data key pointing to page changes notification entries for whole namespace. /// private const string NamespacePageChangesKey = "NamespacePageChanges"; /// /// The user data key pointing to discussion messages notification entries for whole namespaces. /// private const string NamespaceDiscussionMessagesKey = "NamespaceDiscussionMessages"; /// /// Gets all the Users that the providers declare to manage. /// /// The users, sorted by username. public static List GetUsers() { List allUsers = new List(1000); // Retrieve all the users from the Users Providers int count = 0; foreach(IUsersStorageProviderV30 provider in Collectors.UsersProviderCollector.AllProviders) { count++; allUsers.AddRange(provider.GetUsers()); } if(count > 1) { allUsers.Sort(new UsernameComparer()); } return allUsers; } /// /// Finds a user. /// /// The username. /// The user, or null. public static UserInfo FindUser(string username) { if(username == "admin") return GetAdministratorAccount(); // Try default provider first IUsersStorageProviderV30 defaultProvider = Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider); UserInfo temp = defaultProvider.GetUser(username); if(temp != null) return temp; // The try other providers temp = null; IUsersStorageProviderV30[] providers = Collectors.UsersProviderCollector.AllProviders; foreach(IUsersStorageProviderV30 p in providers) { IUsersStorageProviderV30 extProv = p as IUsersStorageProviderV30; if(extProv != null && extProv != defaultProvider) { temp = extProv.GetUser(username); if(temp != null) return temp; } } return null; } /// /// Finds a user by email. /// /// The email address. /// The user, or null. public static UserInfo FindUserByEmail(string email) { // Try default provider first IUsersStorageProviderV30 defaultProvider = Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider); UserInfo temp = defaultProvider.GetUserByEmail(email); if(temp != null) return temp; // The try other providers temp = null; IUsersStorageProviderV30[] providers = Collectors.UsersProviderCollector.AllProviders; foreach(IUsersStorageProviderV30 p in providers) { IUsersStorageProviderV30 extProv = p as IUsersStorageProviderV30; if(extProv != null && extProv != defaultProvider) { temp = extProv.GetUserByEmail(email); if(temp != null) return temp; } } return null; } /// /// Gets user data. /// /// The user. /// The data key. /// The data, or null if either the user or the key is not found. public static string GetUserData(UserInfo user, string key) { if(user == null) return null; if(string.IsNullOrEmpty(key)) return null; if(user.Username == "admin") return null; return user.Provider.RetrieveUserData(user, key); } /// /// Sets user data. /// /// The user. /// The data key. /// The data value. /// true if the data is stored, false otherwise. public static bool SetUserData(UserInfo user, string key, string data) { if(user == null) return false; if(string.IsNullOrEmpty(key)) return false; if(user.Username == "admin") return false; if(user.Provider.UsersDataReadOnly) return false; bool done = user.Provider.StoreUserData(user, key, data); if(done) Log.LogEntry("User data stored for " + user.Username, EntryType.General, Log.SystemUsername); else Log.LogEntry("Could not store user data for " + user.Username, EntryType.Error, Log.SystemUsername); return done; } /// /// Adds a new User. /// /// The Username. /// The display name. /// The Password (plain text). /// The Email address. /// A value specifying whether or not the account is active. /// The Provider. If null, the default provider is used. /// True if the User has been created successfully. public static bool AddUser(string username, string displayName, string password, string email, bool active, IUsersStorageProviderV30 provider) { if(FindUser(username) != null) return false; if(provider == null) provider = Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider); if(provider.UserAccountsReadOnly) return false; UserInfo u = provider.AddUser(username, displayName, password, email, active, DateTime.Now); if(u == null) { Log.LogEntry("User creation failed for " + username, EntryType.Error, Log.SystemUsername); return false; } else { Log.LogEntry("User " + username + " created", EntryType.General, Log.SystemUsername); Host.Instance.OnUserAccountActivity(u, UserAccountActivity.AccountAdded); return true; } } /// /// Updates a new User. /// /// The user to modify. /// The display name. /// The Password (plain text, null or empty for no change). /// The Email address. /// A value specifying whether or not the account is active. /// True if the User has been created successfully. public static bool ModifyUser(UserInfo user, string displayName, string password, string email, bool active) { if(user.Provider.UserAccountsReadOnly) return false; bool done = user.Provider.ModifyUser(user, displayName, password, email, active) != null; if(done) { Log.LogEntry("User " + user.Username + " updated", EntryType.General, Log.SystemUsername); Host.Instance.OnUserAccountActivity(user, UserAccountActivity.AccountModified); return true; } else { Log.LogEntry("User update failed for " + user.Username, EntryType.Error, Log.SystemUsername); return false; } } /// /// Removes a User. /// /// The User to remove. /// True if the User has been removed successfully. public static bool RemoveUser(UserInfo user) { if(user.Provider.UserAccountsReadOnly) return false; bool done = user.Provider.RemoveUser(user); if(done) { Log.LogEntry("User " + user.Username + " removed", EntryType.General, Log.SystemUsername); Host.Instance.OnUserAccountActivity(user, UserAccountActivity.AccountRemoved); return true; } else { Log.LogEntry("User deletion failed for " + user.Username, EntryType.Error, Log.SystemUsername); return false; } } /// /// Changes the Password of a User. /// /// The User to change the password of. /// The new Password (plain text). /// true if the Password has been changed successfully, false otherwise. public static bool ChangePassword(UserInfo user, string newPassword) { return ModifyUser(user, user.DisplayName, newPassword, user.Email, user.Active); } /// /// Sends the password reset message to a user. /// /// The username. /// The email. /// The user registration date/time. public static void SendPasswordResetMessage(string username, string email, DateTime dateTime) { string mainLink = Settings.MainUrl + "Login.aspx?ResetCode=" + Tools.ComputeSecurityHash(username, email, dateTime) + "&Username=" + Tools.UrlEncode(username); string body = Settings.Provider.GetMetaDataItem(MetaDataItem.PasswordResetProcedureMessage, null).Replace("##USERNAME##", username).Replace("##LINK##", mainLink).Replace("##WIKITITLE##", Settings.WikiTitle).Replace("##EMAILADDRESS##", Settings.ContactEmail); EmailTools.AsyncSendEmail(email, Settings.SenderEmail, Settings.WikiTitle + " - " + Exchanger.ResourceExchanger.GetResource("ResetPassword"), body, false); } /// /// Changes the Email address of a User. /// /// The User to change the Email address of. /// The new Email address. /// true if the Email address has been changed successfully, false otherwise. public static bool ChangeEmail(UserInfo user, string newEmail) { return ModifyUser(user, user.DisplayName, null, newEmail, user.Active); } /// /// Sets the Active/Inactive status of a User. /// /// The User. /// The status. /// True if the User's status has been changed successfully. public static bool SetActivationStatus(UserInfo user, bool active) { return ModifyUser(user, user.DisplayName, null, user.Email, active); } /// /// Gets all the user groups. /// /// All the user groups, sorted by name. public static List GetUserGroups() { List result = new List(50); int count = 0; foreach(IUsersStorageProviderV30 prov in Collectors.UsersProviderCollector.AllProviders) { count++; result.AddRange(prov.GetUserGroups()); } if(count > 1) { result.Sort(new UserGroupComparer()); } return result; } /// /// Gets all the user groups in a provider. /// /// The provider. /// The user groups, sorted by name. public static List GetUserGroups(IUsersStorageProviderV30 provider) { return new List(provider.GetUserGroups()); } /// /// Gets all the user groups a user is member of. /// /// The user. /// All the user groups the user is member of, sorted by name. public static List GetUserGroupsForUser(UserInfo user) { UserGroup[] allGroups = user.Provider.GetUserGroups(); List result = new List(allGroups.Length); StringComparer comp = StringComparer.OrdinalIgnoreCase; foreach(UserGroup group in allGroups) { if(Array.Find(user.Groups, delegate(string g) { return comp.Compare(g, group.Name) == 0; }) != null) { result.Add(group); } } return result; } /// /// Finds a user group. /// /// The name of the user group to find. /// The object or null if no data is found. public static UserGroup FindUserGroup(string name) { List allGroups = GetUserGroups(); int index = allGroups.BinarySearch(new UserGroup(name, "", null), new UserGroupComparer()); if(index < 0) return null; else return allGroups[index]; } /// /// Adds a new user group to a specific provider. /// /// The name of the group. /// The description of the group. /// The target provider. /// true if the groups is added, false otherwise. public static bool AddUserGroup(string name, string description, IUsersStorageProviderV30 provider) { if(provider == null) provider = Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider); if(provider.UserGroupsReadOnly) return false; if(FindUserGroup(name) != null) return false; UserGroup result = provider.AddUserGroup(name, description); if(result != null) { Host.Instance.OnUserGroupActivity(result, UserGroupActivity.GroupAdded); Log.LogEntry("User Group " + name + " created", EntryType.General, Log.SystemUsername); } else Log.LogEntry("Creation failed for User Group " + name, EntryType.Error, Log.SystemUsername); return result != null; } /// /// Adds a new user group to the default provider. /// /// The name of the group. /// The description of the group. /// true if the groups is added, false otherwise. public static bool AddUserGroup(string name, string description) { return AddUserGroup(name, description, Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider)); } /// /// Modifies a user group. /// /// The user group to modify. /// The new description. /// true if the user group is modified, false otherwise. public static bool ModifyUserGroup(UserGroup group, string description) { if(group.Provider.UserGroupsReadOnly) return false; UserGroup result = group.Provider.ModifyUserGroup(group, description); if(result != null) { Host.Instance.OnUserGroupActivity(result, UserGroupActivity.GroupModified); Log.LogEntry("User Group " + group.Name + " updated", EntryType.General, Log.SystemUsername); } else Log.LogEntry("Update failed for User Group " + result.Name, EntryType.Error, Log.SystemUsername); return result != null; } /// /// Removes a user group. /// /// The user group to remove. /// true if the user group is removed, false otherwise. public static bool RemoveUserGroup(UserGroup group) { if(group.Provider.UserGroupsReadOnly) return false; bool done = group.Provider.RemoveUserGroup(group); if(done) { Host.Instance.OnUserGroupActivity(group, UserGroupActivity.GroupRemoved); Log.LogEntry("User Group " + group.Name + " deleted", EntryType.General, Log.SystemUsername); } else Log.LogEntry("Deletion failed for User Group " + group.Name, EntryType.Error, Log.SystemUsername); return done; } /// /// Sets the group memberships of a user account. /// /// The user account. /// The groups the user account is member of. /// true if the membership is set, false otherwise. public static bool SetUserMembership(UserInfo user, string[] groups) { if(user.Provider.GroupMembershipReadOnly) return false; UserInfo result = user.Provider.SetUserMembership(user, groups); if(result != null) { Host.Instance.OnUserAccountActivity(result, UserAccountActivity.AccountMembershipChanged); Log.LogEntry("Group membership set for User " + user.Username, EntryType.General, Log.SystemUsername); } else Log.LogEntry("Could not set group membership for User " + user.Username, EntryType.Error, Log.SystemUsername); return result != null; } /// /// Creates the correct link of a User. /// /// The Username. /// The User link. public static string UserLink(string username) { return UserLink(username, false); } /// /// Creates the correct link of a User. /// /// The Username. /// A value indicating whether to open the link in a new window. /// The User link. public static string UserLink(string username, bool newWindow) { if(username != null && (username.EndsWith("+" + Log.SystemUsername) || username == Log.SystemUsername)) return username; UserInfo u = FindUser(username); if(u == null && username.Equals("admin")) u = new UserInfo("admin", null, Settings.ContactEmail, true, DateTime.Now, null); if(u != null) { return @"" + GetDisplayName(u) + ""; } else return username; } /// /// Gets the display name of a user. /// /// The user. /// The display name. public static string GetDisplayName(UserInfo user) { if(string.IsNullOrEmpty(user.DisplayName)) return user.Username; else return user.DisplayName; } /// /// Tries to automatically login a user using the current HttpContext, /// through any provider that supports the operation. /// /// The current HttpContext. /// The correct UserInfo, or null. public static UserInfo TryAutoLogin(HttpContext context) { // Try default provider first IUsersStorageProviderV30 defaultProvider = Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider) as IUsersStorageProviderV30; if(defaultProvider != null) { UserInfo temp = defaultProvider.TryAutoLogin(context); if(temp != null) return temp; } // Then try all other providers IUsersStorageProviderV30[] providers = Collectors.UsersProviderCollector.AllProviders; foreach(IUsersStorageProviderV30 p in providers) { IUsersStorageProviderV30 extProv = p as IUsersStorageProviderV30; if(extProv != null && extProv != defaultProvider) { UserInfo temp = extProv.TryAutoLogin(context); if(temp != null) return temp; } } return null; } /// /// Tries to manually login a user using all the available methods. /// /// The username. /// The password. /// The correct UserInfo, or null. public static UserInfo TryLogin(string username, string password) { if(username == "admin" && password == Settings.MasterPassword) { return GetAdministratorAccount(); } // Try default provider first IUsersStorageProviderV30 defaultProvider = Collectors.UsersProviderCollector.GetProvider(Settings.DefaultUsersProvider) as IUsersStorageProviderV30; if(defaultProvider != null) { UserInfo temp = defaultProvider.TryManualLogin(username, password); if(temp != null) return temp; } // Then try all other providers IUsersStorageProviderV30[] providers = Collectors.UsersProviderCollector.AllProviders; foreach(IUsersStorageProviderV30 p in providers) { IUsersStorageProviderV30 extProv = p as IUsersStorageProviderV30; if(extProv != null && extProv != defaultProvider) { UserInfo temp = extProv.TryManualLogin(username, password); if(temp != null) return temp; } } return null; } /// /// Tries to login a user through the cookie-stored authentication data. /// /// The username. /// The login key. /// The correct UserInfo object, or null. public static UserInfo TryCookieLogin(string username, string loginKey) { if(username == "admin" && loginKey == ComputeLoginKey(username, Settings.ContactEmail, DateTime.MinValue)) { // Just return, no notification to providers because the "admin" account is fictitious return GetAdministratorAccount(); } UserInfo user = FindUser(username); if(user != null && user.Active) { if(loginKey == ComputeLoginKey(user.Username, user.Email, user.DateTime)) { // Notify provider user.Provider.NotifyCookieLogin(user); return user; } } return null; } /// /// Notifies to the proper provider that a user has logged out. /// /// The username. public static void NotifyLogout(string username) { UserInfo user = FindUser(username); if(user != null) { IUsersStorageProviderV30 prov = user.Provider as IUsersStorageProviderV30; if(prov != null) prov.NotifyLogout(user); } } /// /// Copmputes the login key. /// /// The username. /// The email. /// The registration date/time. /// The login key. public static string ComputeLoginKey(string username, string email, DateTime dateTime) { if(username == null) throw new ArgumentNullException("username"); if(email == null) throw new ArgumentNullException("email"); return Tools.ComputeSecurityHash(username, email, dateTime); } /// /// Sets the email notification status for a page. /// /// The user for which to set the notification status. /// The page subject of the notification. /// A value indicating whether page changes should be notified. /// A value indicating whether discussion messages should be notified. /// true if the notification is set, false otherwise. public static bool SetEmailNotification(UserInfo user, PageInfo page, bool pageChanges, bool discussionMessages) { if(user == null || page == null) return false; // Get user's data // Depending on the status of pageChanges and discussionMessages, // either remove existing entries (if any) or add new entries // In the process, remove entries that refer to inexistent pages // Format // Page1:Page2:Page3 string pageChangeData = user.Provider.RetrieveUserData(user, PageChangesKey); string discussionMessagesData = user.Provider.RetrieveUserData(user, DiscussionMessagesKey); if(pageChangeData == null) pageChangeData = ""; if(discussionMessagesData == null) discussionMessagesData = ""; string[] pageChangesEntries = pageChangeData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); string[] discussionMessagesEntries = discussionMessagesData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); List pageChangesResult = new List(pageChangesEntries.Length + 1); List discussionMessagesResult = new List(discussionMessagesEntries.Length + 1); string lowercasePage = page.FullName.ToLowerInvariant(); bool added = false; foreach(string entry in pageChangesEntries) { if(entry.ToLowerInvariant() == lowercasePage) { if(pageChanges) { pageChangesResult.Add(entry); added = true; } } else if(Pages.FindPage(entry) != null) pageChangesResult.Add(entry); } if(!added && pageChanges) pageChangesResult.Add(page.FullName); added = false; foreach(string entry in discussionMessagesEntries) { if(entry.ToLowerInvariant() == lowercasePage) { if(discussionMessages) { discussionMessagesResult.Add(entry); added = true; } } else if(Pages.FindPage(entry) != null) discussionMessagesResult.Add(entry); } if(!added && discussionMessages) discussionMessagesResult.Add(page.FullName); string newPageChangesData = string.Join(":", pageChangesResult.ToArray()); string newDiscussionMessagesData = string.Join(":", discussionMessagesResult.ToArray()); bool done = user.Provider.StoreUserData(user, PageChangesKey, newPageChangesData) & user.Provider.StoreUserData(user, DiscussionMessagesKey, newDiscussionMessagesData); return done; } /// /// Sets the email notification status for a namespace. /// /// The user for which to set the notification status. /// The namespace subject of the notification. /// A value indicating whether page changes should be notified. /// A value indicating whether discussion messages should be notified. /// true if the notification is set, false otherwise. public static bool SetEmailNotification(UserInfo user, NamespaceInfo nspace, bool pageChanges, bool discussionMessages) { if(user == null) return false; // Get user's data // Depending on the status of pageChanges and discussionMessages, // either remove existing entries (if any) or add new entries // In the process, remove entries that refer to inexistent pages // Format // Namespace1:Namespace2:Namespace3 string pageChangeData = user.Provider.RetrieveUserData(user, NamespacePageChangesKey); string discussionMessagesData = user.Provider.RetrieveUserData(user, NamespaceDiscussionMessagesKey); if(pageChangeData == null) pageChangeData = ""; if(discussionMessagesData == null) discussionMessagesData = ""; string[] pageChangesEntries = pageChangeData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); string[] discussionMessagesEntries = discussionMessagesData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); List pageChangesResult = new List(pageChangesEntries.Length + 1); List discussionMessagesResult = new List(discussionMessagesEntries.Length + 1); string namespaceName = nspace != null ? nspace.Name : ""; string lowercaseNamespace = nspace != null ? nspace.Name.ToLowerInvariant() : ""; bool added = false; foreach(string entry in pageChangesEntries) { if(entry.ToLowerInvariant() == lowercaseNamespace) { if(pageChanges) { pageChangesResult.Add(entry); added = true; } } else { if(entry == "") pageChangesResult.Add(""); else if(Pages.FindNamespace(entry) != null) pageChangesResult.Add(entry); } } if(!added && pageChanges) pageChangesResult.Add(namespaceName); added = false; foreach(string entry in discussionMessagesEntries) { if(entry.ToLowerInvariant() == lowercaseNamespace) { if(discussionMessages) { discussionMessagesResult.Add(entry); added = true; } } else { if(entry == "") discussionMessagesResult.Add(""); else if(Pages.FindNamespace(entry) != null) discussionMessagesResult.Add(entry); } } if(!added && discussionMessages) discussionMessagesResult.Add(namespaceName); string newPageChangesData = string.Join(":", pageChangesResult.ToArray()); string newDiscussionMessagesData = string.Join(":", discussionMessagesResult.ToArray()); bool done = user.Provider.StoreUserData(user, NamespacePageChangesKey, newPageChangesData) & user.Provider.StoreUserData(user, NamespaceDiscussionMessagesKey, newDiscussionMessagesData); return done; } /// /// Gets the email notification status for a page. /// /// The user for which to get the notification status. /// The page subject of the notification. /// A value indicating whether page changes should be notified. /// A value indicating whether discussion messages should be notified. public static void GetEmailNotification(UserInfo user, PageInfo page, out bool pageChanges, out bool discussionMessages) { pageChanges = false; discussionMessages = false; if(user == null || page == null) return; string pageChangeData = user.Provider.RetrieveUserData(user, PageChangesKey); string discussionMessagesData = user.Provider.RetrieveUserData(user, DiscussionMessagesKey); if(pageChangeData == null) pageChangeData = ""; if(discussionMessagesData == null) discussionMessagesData = ""; pageChangeData = pageChangeData.ToLowerInvariant(); discussionMessagesData = discussionMessagesData.ToLowerInvariant(); string[] pageChangeEntries = pageChangeData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); string[] discussionMessagesEntries = discussionMessagesData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); string lowercasePage = page.FullName.ToLowerInvariant(); // Elements in the array are already lowercase pageChanges = Array.Find(pageChangeEntries, delegate(string elem) { return elem == lowercasePage; }) != null; discussionMessages = Array.Find(discussionMessagesEntries, delegate(string elem) { return elem == lowercasePage; }) != null; } /// /// Gets the email notification status for a namespace. /// /// The user for which to get the notification status. /// The namespace subject of the notification (null for the root). /// A value indicating whether page changes should be notified. /// A value indicating whether discussion messages should be notified. public static void GetEmailNotification(UserInfo user, NamespaceInfo nspace, out bool pageChanges, out bool discussionMessages) { pageChanges = false; discussionMessages = false; if(user == null) return; string lowercaseNamespaces = nspace != null ? nspace.Name.ToLowerInvariant() : ""; string pageChangesData = user.Provider.RetrieveUserData(user, NamespacePageChangesKey); string discussionMessagesData = user.Provider.RetrieveUserData(user, NamespaceDiscussionMessagesKey); if(pageChangesData == null) pageChangesData = ""; if(discussionMessagesData == null) discussionMessagesData = ""; pageChangesData = pageChangesData.ToLowerInvariant(); discussionMessagesData = discussionMessagesData.ToLowerInvariant(); string[] pageChangeEntries = pageChangesData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); string[] discussionMessagesEntries = discussionMessagesData.Split(new char[] { ':' }, StringSplitOptions.RemoveEmptyEntries); // Elements in the array are already lowercase pageChanges = Array.Find(pageChangeEntries, delegate(string elem) { return elem == lowercaseNamespaces; }) != null; discussionMessages = Array.Find(discussionMessagesEntries, delegate(string elem) { return elem == lowercaseNamespaces; }) != null; } /// /// Gets all the users that must be notified of a page change. /// /// The page. /// The users to be notified. public static UserInfo[] GetUsersToNotifyForPageChange(PageInfo page) { if(page == null) return new UserInfo[0]; UserInfo[] specific = GetUsersToNotify(page, PageChangesKey); UserInfo[] nspace = GetUsersToNotify(Pages.FindNamespace(NameTools.GetNamespace(page.FullName)), NamespacePageChangesKey); UserInfo[] temp = MergeArrays(specific, nspace); List result = new List(temp.Length); // Verify read permissions foreach(UserInfo user in temp) { if(AuthChecker.CheckActionForPage(page, Actions.ForPages.ReadPage, user.Username, user.Groups)) { result.Add(user); } } return result.ToArray(); } /// /// Gets all the users that must be notified of a discussion message. /// /// The page. /// The users to be notified. public static UserInfo[] GetUsersToNotifyForDiscussionMessages(PageInfo page) { if(page == null) return new UserInfo[0]; UserInfo[] specific = GetUsersToNotify(page, DiscussionMessagesKey); UserInfo[] nspace = GetUsersToNotify(Pages.FindNamespace(NameTools.GetNamespace(page.FullName)), NamespaceDiscussionMessagesKey); UserInfo[] temp = MergeArrays(specific, nspace); List result = new List(temp.Length); // Verify read permissions foreach(UserInfo user in temp) { if(AuthChecker.CheckActionForPage(page, Actions.ForPages.ReadDiscussion, user.Username, user.Groups)) { result.Add(user); } } return result.ToArray(); } /// /// Merges two arrays of users, removing duplicates. /// /// The first array. /// The second array. /// The merged users. private static UserInfo[] MergeArrays(UserInfo[] array1, UserInfo[] array2) { List result = new List(array1.Length + array2.Length); result.AddRange(array1); UsernameComparer comp = new UsernameComparer(); foreach(UserInfo user in array2) { bool found = false; foreach(UserInfo present in result) { if(comp.Compare(present, user) == 0) { found = true; break; } } if(!found) { result.Add(user); } } return result.ToArray(); } /// /// Gets the users to notify for either a page change or a discussion message. /// /// The page. /// The key to look for in the user's data. /// The users to be notified. private static UserInfo[] GetUsersToNotify(PageInfo page, string key) { List result = new List(200); string lowercasePage = page.FullName.ToLowerInvariant(); foreach(IUsersStorageProviderV30 prov in Collectors.UsersProviderCollector.AllProviders) { IDictionary users = prov.GetUsersWithData(key); string[] fields; foreach(KeyValuePair pair in users) { fields = pair.Value.ToLowerInvariant().Split(':'); if(Array.Find(fields, delegate(string elem) { return elem == lowercasePage; }) != null) { result.Add(pair.Key); } } } return result.ToArray(); } /// /// Gets the users to notify for either a page change or a discussion message in a namespace. /// /// The namespace (null for the root). /// The key to look for in the user's data. /// The users to be notified. private static UserInfo[] GetUsersToNotify(NamespaceInfo nspace, string key) { List result = new List(200); string lowercaseNamespace = nspace != null ? nspace.Name.ToLowerInvariant() : ""; foreach(IUsersStorageProviderV30 prov in Collectors.UsersProviderCollector.AllProviders) { IDictionary users = prov.GetUsersWithData(key); string[] fields; foreach(KeyValuePair pair in users) { fields = pair.Value.ToLowerInvariant().Split(':'); if(Array.Find(fields, delegate(string elem) { return elem == lowercaseNamespace; }) != null) { result.Add(pair.Key); } } } return result.ToArray(); } } }