using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ScrewTurn.Wiki.PluginFramework;
using System.Text;
namespace ScrewTurn.Wiki {
public partial class AdminUsers : BasePage {
///
/// The numer of items in a page.
///
public const int PageSize = 50;
private IList currentUsers = null;
private int rangeBegin = 0;
private int rangeEnd = PageSize - 1;
private int selectedPage = 0;
protected void Page_Load(object sender, EventArgs e) {
AdminMaster.RedirectToLoginIfNeeded();
if(!AdminMaster.CanManageUsers(SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames())) UrlTools.Redirect("AccessDenied.aspx");
aclActionsSelector.Visible = AdminMaster.CanManagePermissions(SessionFacade.GetCurrentUsername(), SessionFacade.GetCurrentGroupNames());
revUsername.ValidationExpression = Settings.UsernameRegex;
revDisplayName.ValidationExpression = Settings.DisplayNameRegex;
revPassword1.ValidationExpression = Settings.UsernameRegex;
revEmail.ValidationExpression = Settings.EmailRegex;
if(!Page.IsPostBack) {
ResetUserList();
RefreshList();
providerSelector.Reload();
btnNewUser.Enabled = providerSelector.HasProviders;
}
if(Page.IsPostBack) {
// Preserve password value (a bit insecure but much more usable)
txtPassword1.Attributes.Add("value", txtPassword1.Text);
txtPassword2.Attributes.Add("value", txtPassword2.Text);
}
}
///
/// Resets the user list.
///
private void ResetUserList() {
currentUsers = GetUsers();
pageSelector.ItemCount = currentUsers.Count;
pageSelector.SelectPage(0);
}
protected void chkFilter_CheckedChanged(object sender, EventArgs e) {
currentUsers = GetUsers();
pageSelector.ItemCount = currentUsers.Count;
pageSelector.SelectPage(0);
RefreshList();
}
protected void btnFilter_Click(object sender, EventArgs e) {
currentUsers = GetUsers();
pageSelector.ItemCount = currentUsers.Count;
pageSelector.SelectPage(0);
RefreshList();
}
protected void pageSelector_SelectedPageChanged(object sender, SelectedPageChangedEventArgs e) {
rangeBegin = e.SelectedPage * PageSize;
rangeEnd = rangeBegin + e.ItemCount - 1;
selectedPage = e.SelectedPage;
RefreshList();
}
///
/// Gets the users.
///
/// The users.
private IList GetUsers() {
List allUsers = Users.GetUsers();
// Apply filter
List result = new List(allUsers.Count);
foreach(UserInfo user in allUsers) {
if(user.Active && chkActive.Checked) {
if(FilterUsername(user)) result.Add(user);
}
else if(!user.Active && chkInactive.Checked) {
if(FilterUsername(user)) result.Add(user);
}
}
return result;
}
///
/// Refreshes the users list.
///
private void RefreshList() {
rangeBegin = pageSelector.SelectedPage * PageSize;
rangeEnd = rangeBegin + pageSelector.SelectedPageSize - 1;
selectedPage = pageSelector.SelectedPage;
txtCurrentUsername.Value = "";
ResetEditor();
rptAccounts.DataBind();
}
private bool FilterUsername(UserInfo user) {
if(txtFilter.Text.Length == 0) return true;
else return user.Username.ToLower(System.Globalization.CultureInfo.CurrentCulture).Contains(txtFilter.Text.ToLower(System.Globalization.CultureInfo.CurrentCulture));
}
protected void rptAccounts_DataBinding(object sender, EventArgs e) {
if(currentUsers == null) currentUsers = GetUsers();
List selectedRows = new List(PageSize);
for(int i = rangeBegin; i <= rangeEnd; i++) {
selectedRows.Add(new UserRow(currentUsers[i], Users.GetUserGroupsForUser(currentUsers[i]),
currentUsers[i].Username == txtCurrentUsername.Value));
}
rptAccounts.DataSource = selectedRows;
}
protected void rptAccounts_ItemCommand(object sender, RepeaterCommandEventArgs e) {
if(e.CommandName == "Select") {
txtCurrentUsername.Value = e.CommandArgument as string;
//rptAccounts.DataBind(); Not needed because the list is hidden on select
UserInfo user = Users.FindUser(txtCurrentUsername.Value);
txtUsername.Text = user.Username;
txtUsername.Enabled = false;
txtDisplayName.Text = user.DisplayName;
txtEmail.Text = user.Email;
chkSetActive.Checked = user.Active;
providerSelector.SelectedProvider = user.Provider.GetType().FullName;
providerSelector.Enabled = false;
btnCreate.Visible = false;
btnSave.Visible = true;
btnDelete.Visible = true;
rfvPassword1.Enabled = false;
cvUsername.Enabled = false;
lblPasswordInfo.Visible = true;
pnlEditAccount.Visible = true;
pnlList.Visible = false;
PopulateGroups();
// Select user's groups
List groups = Users.GetUserGroupsForUser(user);
foreach(ListItem item in lstGroups.Items) {
if(groups.Find(delegate(UserGroup g) { return g.Name == item.Value; }) != null) {
item.Selected = true;
}
}
// Select user's global permissions
aclActionsSelector.GrantedActions =
AuthReader.RetrieveGrantsForGlobals(user);
aclActionsSelector.DeniedActions =
AuthReader.RetrieveDenialsForGlobals(user);
// Enable/disable interface sections based on provider read-only settings
lstGroups.Enabled = !user.Provider.GroupMembershipReadOnly;
pnlAccountDetails.Enabled = !user.Provider.UserAccountsReadOnly;
btnDelete.Enabled = !user.Provider.UserAccountsReadOnly;
lblResult.CssClass = "";
lblResult.Text = "";
}
}
///
/// Resets the account editor.
///
private void ResetEditor() {
txtUsername.Text = "";
txtUsername.Enabled = true;
txtEmail.Text = "";
chkSetActive.Checked = true;
providerSelector.Enabled = true;
providerSelector.Reload();
lstGroups.Enabled = true;
pnlAccountDetails.Enabled = true;
aclActionsSelector.GrantedActions = new string[0];
aclActionsSelector.DeniedActions = new string[0];
foreach(ListItem item in lstGroups.Items) {
item.Selected = false;
}
btnCreate.Visible = true;
btnSave.Visible = false;
btnDelete.Visible = false;
rfvPassword1.Enabled = true;
cvUsername.Enabled = true;
lblPasswordInfo.Visible = false;
lblResult.Text = "";
}
protected void providerSelector_SelectedProviderChanged(object sender, EventArgs e) {
PopulateGroups();
}
///
/// Populates the groups list according to the currently selected provider.
///
private void PopulateGroups() {
List groups = Users.GetUserGroups(Collectors.UsersProviderCollector.GetProvider(providerSelector.SelectedProvider));
lstGroups.Items.Clear();
foreach(UserGroup group in groups) {
ListItem item = new ListItem(group.Name, group.Name);
lstGroups.Items.Add(item);
}
}
protected void cvUsername_ServerValidate(object sender, ServerValidateEventArgs e) {
e.IsValid = Users.FindUser(txtUsername.Text) == null;
}
protected void cvPassword2_ServerValidate(object sender, ServerValidateEventArgs e) {
e.IsValid = txtPassword1.Text == txtPassword2.Text;
}
protected void btnBulkDelete_Click(object sender, EventArgs e) {
Log.LogEntry("Bulk account deletion requested", EntryType.General, SessionFacade.CurrentUsername);
DateTime now = DateTime.Now;
List allUsers = Users.GetUsers();
int count = 0;
for(int i = 0; i < allUsers.Count; i++) {
if(!allUsers[i].Active && !allUsers[i].Provider.UserAccountsReadOnly && (now - allUsers[i].DateTime).TotalDays >= 31) {
RemoveAllAclEntries(allUsers[i]);
RemoveGroupMembership(allUsers[i]);
Users.RemoveUser(allUsers[i]);
count++;
}
}
Log.LogEntry("Bulk account deletion completed - " + count.ToString() + " accounts deleted", EntryType.General, SessionFacade.CurrentUsername);
ResetUserList();
RefreshList();
lblBulkDeleteResult.CssClass = "resultok";
lblBulkDeleteResult.Text = Properties.Messages.NAccountsDeleted.Replace("$", count.ToString());
}
protected void btnCreate_Click(object sender, EventArgs e) {
if(!Page.IsValid) return;
lblResult.CssClass = "";
lblResult.Text = "";
Log.LogEntry("User creation requested for " + txtUsername.Text, EntryType.General, SessionFacade.CurrentUsername);
// Add the new user, set its global permissions, set its membership
bool done = Users.AddUser(txtUsername.Text, txtDisplayName.Text, txtPassword1.Text, txtEmail.Text,
chkSetActive.Checked,
Collectors.UsersProviderCollector.GetProvider(providerSelector.SelectedProvider));
UserInfo currentUser = null;
if(done) {
currentUser = Users.FindUser(txtUsername.Text);
// Wipe old data, if any
RemoveAllAclEntries(currentUser);
done = AddAclEntries(currentUser, aclActionsSelector.GrantedActions, aclActionsSelector.DeniedActions);
if(done) {
done = SetGroupMembership(currentUser, GetSelectedGroups());
if(done) {
ResetUserList();
RefreshList();
lblResult.CssClass = "resultok";
lblResult.Text = Properties.Messages.UserCreated;
ReturnToList();
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.UserCreatedCouldNotStoreGroupMembership;
}
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.UserCreatedCouldNotStorePermissions;
}
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.CouldNotCreateUser;
}
}
protected void btnSave_Click(object sender, EventArgs e) {
if(!Page.IsValid) return;
// Perform proper actions based on provider read-only settings
// 1. If possible, modify user
// 2. Update ACLs
// 3. If possible, update group membership
lblResult.CssClass = "";
lblResult.Text = "";
Log.LogEntry("User update requested for " + txtCurrentUsername.Value, EntryType.General, SessionFacade.CurrentUsername);
UserInfo currentUser = Users.FindUser(txtCurrentUsername.Value);
bool done = true;
if(!currentUser.Provider.UserAccountsReadOnly) {
done = Users.ModifyUser(currentUser, txtDisplayName.Text, txtPassword1.Text, txtEmail.Text, chkSetActive.Checked);
}
if(!done) {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.CouldNotUpdateUser;
return;
}
done = RemoveAllAclEntries(currentUser);
if(done) {
done = AddAclEntries(currentUser, aclActionsSelector.GrantedActions, aclActionsSelector.DeniedActions);
if(!done) {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.UserUpdatedCouldNotStoreNewPermissions;
}
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.UserUpdatedCouldNotDeleteOldPermissions;
return;
}
if(!currentUser.Provider.GroupMembershipReadOnly) {
// This overwrites old membership data
done = SetGroupMembership(currentUser, GetSelectedGroups());
if(done) {
RefreshList();
lblResult.CssClass = "resultok";
lblResult.Text = Properties.Messages.UserUpdated;
ReturnToList();
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.UserUpdatedCouldNotStoreGroupMembership;
}
}
}
protected void btnDelete_Click(object sender, EventArgs e) {
lblResult.Text = "";
lblResult.CssClass = "";
Log.LogEntry("User deletion requested for " + txtCurrentUsername.Value, EntryType.General, SessionFacade.CurrentUsername);
UserInfo currentUser = Users.FindUser(txtCurrentUsername.Value);
if(currentUser.Provider.UserAccountsReadOnly) return;
// Remove global permissions, remove group membership, remove user
bool done = RemoveAllAclEntries(currentUser);
if(done) {
done = RemoveGroupMembership(currentUser);
if(done) {
done = Users.RemoveUser(currentUser);
if(done) {
ResetUserList();
RefreshList();
lblResult.Text = Properties.Messages.UserDeleted;
lblResult.CssClass = "resultok";
ReturnToList();
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.PermissionsAndGroupMembershipDeletedCouldNotDeleteUser;
}
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.PermissionsDeletedCouldNotDeleteUser;
}
}
else {
lblResult.CssClass = "resulterror";
lblResult.Text = Properties.Messages.CouldNotDeletePermissions;
}
}
protected void btnCancel_Click(object sender, EventArgs e) {
rangeBegin = pageSelector.SelectedPage * PageSize;
rangeEnd = rangeBegin + pageSelector.SelectedPageSize - 1;
selectedPage = pageSelector.SelectedPage;
RefreshList();
ReturnToList();
}
protected void btnNewUser_Click(object sender, EventArgs e) {
pnlList.Visible = false;
pnlEditAccount.Visible = true;
PopulateGroups();
lblResult.Text = "";
lblResult.CssClass = "";
}
///
/// Gets the currently selected groups.
///
///
private string[] GetSelectedGroups() {
List selectedGroups = new List(5);
foreach(ListItem item in lstGroups.Items) {
if(item.Selected) selectedGroups.Add(item.Value);
}
return selectedGroups.ToArray();
}
///
/// Removes all the ACL entries for a user.
///
/// The user.
/// true if the operation succeeded, false otherwise.
private bool RemoveAllAclEntries(UserInfo user) {
return AuthWriter.RemoveEntriesForGlobals(user);
}
///
/// Adds some ACL entries for a user.
///
/// The user.
/// The granted actions.
/// The denied actions.
/// true if the operation succeeded, false otherwise.
private bool AddAclEntries(UserInfo user, string[] grants, string[] denials) {
foreach(string action in grants) {
bool done = AuthWriter.SetPermissionForGlobals(AuthStatus.Grant, action, user);
if(!done) return false;
}
foreach(string action in denials) {
bool done = AuthWriter.SetPermissionForGlobals(AuthStatus.Deny, action, user);
if(!done) return false;
}
return true;
}
///
/// Removes all the group membership data for a user.
///
/// The user.
/// true if the operation succeeded, false otherwise.
private bool RemoveGroupMembership(UserInfo user) {
return Users.SetUserMembership(user, new string[0]);
}
///
/// Sets the group membership data for a user, overwriting previous membership.
///
/// The user.
/// The groups the user should be member of.
/// true if the operation succeded, false otherwise.
private bool SetGroupMembership(UserInfo user, string[] groups) {
return Users.SetUserMembership(user, groups);
}
///
/// Returns to the accounts list.
///
private void ReturnToList() {
pnlEditAccount.Visible = false;
pnlList.Visible = true;
}
}
///
/// Represents a User for display purposes.
///
public class UserRow {
private string username, displayName, email, memberOf, regDateTime, provider, additionalClass;
///
/// Initializes a new instance of the class.
///
/// The original user.
/// The groups the user is member of.
/// A value indicating whether the user is selected.
public UserRow(UserInfo user, List groups, bool selected) {
username = user.Username;
displayName = Users.GetDisplayName(user);
email = user.Email;
StringBuilder sb = new StringBuilder(50);
for(int i = 0; i < groups.Count; i++) {
sb.Append(groups[i].Name);
if(i != groups.Count - 1) sb.Append(", ");
}
memberOf = sb.ToString();
regDateTime = user.DateTime.ToString(Settings.DateTimeFormat);
provider = user.Provider.Information.Name;
additionalClass = (selected ? " selected" : "") + (!user.Active ? " inactive" : "");
}
///
/// Gets the username.
///
public string Username {
get { return username; }
}
///
/// Gets the display name.
///
public string DisplayName {
get { return displayName; }
}
///
/// Gets the email.
///
public string Email {
get { return email; }
}
///
/// Gets the user membership.
///
public string MemberOf {
get { return memberOf; }
}
///
/// Gets the registration date/time, formatted.
///
public string RegDateTime {
get { return regDateTime; }
}
///
/// Gets the provider name.
///
public string Provider {
get { return provider; }
}
///
/// Gets the additional CSS classes to apply.
///
public string AdditionalClass {
get { return additionalClass; }
}
}
}