using System; using System.Collections; using System.Configuration.Provider; using System.Globalization; using System.IO; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Xml; using Umbraco.Core.Logging; using Umbraco.Core.Security; using Umbraco.Web; using Umbraco.Web.Models; using Umbraco.Web.Security; using umbraco.BasePages; using umbraco.BusinessLogic; using umbraco.businesslogic.Exceptions; using umbraco.cms.businesslogic.media; using umbraco.cms.businesslogic.propertytype; using umbraco.cms.businesslogic.web; using umbraco.controls; using umbraco.presentation.channels.businesslogic; using umbraco.uicontrols; using umbraco.providers; using umbraco.cms.presentation.Trees; using Umbraco.Core.IO; using Umbraco.Core; namespace umbraco.cms.presentation.user { /// /// Summary description for EditUser. /// public partial class EditUser : UmbracoEnsuredPage { public EditUser() { CurrentApp = DefaultApps.users.ToString(); } protected HtmlTable macroProperties; protected TextBox uname = new TextBox(); protected TextBox lname = new TextBox(); protected PlaceHolder passw = new PlaceHolder(); protected CheckBoxList lapps = new CheckBoxList(); protected TextBox email = new TextBox(); protected DropDownList userType = new DropDownList(); protected DropDownList userLanguage = new DropDownList(); protected CheckBox NoConsole = new CheckBox(); protected CheckBox Disabled = new CheckBox(); protected CheckBox DefaultToLiveEditing = new CheckBox(); protected ContentPicker mediaPicker = new ContentPicker(); protected ContentPicker contentPicker = new ContentPicker(); protected TextBox cName = new TextBox(); protected CheckBox cFulltree = new CheckBox(); protected DropDownList cDocumentType = new DropDownList(); protected DropDownList cDescription = new DropDownList(); protected DropDownList cCategories = new DropDownList(); protected DropDownList cExcerpt = new DropDownList(); protected ContentPicker cMediaPicker = new ContentPicker(); protected ContentPicker cContentPicker = new ContentPicker(); protected CustomValidator sectionValidator = new CustomValidator(); protected Pane pp = new Pane(); private User u; private MembershipHelper _membershipHelper; private MembershipProvider BackOfficeProvider { get { var provider = Membership.Providers[UmbracoSettings.DefaultBackofficeProvider]; if (provider == null) { throw new ProviderException("The membership provider " + UmbracoSettings.DefaultBackofficeProvider + " was not found"); } return provider; } } protected void Page_Load(object sender, EventArgs e) { _membershipHelper = new MembershipHelper(UmbracoContext.Current); int UID = int.Parse(Request.QueryString["id"]); u = BusinessLogic.User.GetUser(UID); //the true admin can only edit the true admin if (u.Id == 0 && CurrentUser.Id != 0) { throw new Exception("Only the root user can edit the 'root' user (id:0)"); } //only another admin can edit another admin (who is not the true admin) if (u.IsAdmin() && CurrentUser.IsAdmin() == false) { throw new Exception("Admin users can only be edited by admins"); } // check if canvas editing is enabled DefaultToLiveEditing.Visible = UmbracoSettings.EnableCanvasEditing; // Populate usertype list foreach (UserType ut in UserType.getAll) { if (CurrentUser.IsAdmin() || ut.Alias != "admin") { ListItem li = new ListItem(ui.Text("user", ut.Name.ToLower(), UmbracoUser), ut.Id.ToString()); if (ut.Id == u.UserType.Id) li.Selected = true; userType.Items.Add(li); } } // Populate ui language lsit foreach ( string f in Directory.GetFiles(IOHelper.MapPath(SystemDirectories.Umbraco + "/config/lang"), "*.xml") ) { XmlDocument x = new XmlDocument(); x.Load(f); ListItem li = new ListItem(x.DocumentElement.Attributes.GetNamedItem("intName").Value, x.DocumentElement.Attributes.GetNamedItem("alias").Value); if (x.DocumentElement.Attributes.GetNamedItem("alias").Value == u.Language) li.Selected = true; userLanguage.Items.Add(li); } // Console access and disabling NoConsole.Checked = u.NoConsole; Disabled.Checked = u.Disabled; DefaultToLiveEditing.Checked = u.DefaultToLiveEditing; PlaceHolder medias = new PlaceHolder(); mediaPicker.AppAlias = Constants.Applications.Media; mediaPicker.TreeAlias = "media"; if (u.StartMediaId > 0) mediaPicker.Value = u.StartMediaId.ToString(); else mediaPicker.Value = "-1"; medias.Controls.Add(mediaPicker); PlaceHolder content = new PlaceHolder(); contentPicker.AppAlias = Constants.Applications.Content; contentPicker.TreeAlias = "content"; if (u.StartNodeId > 0) contentPicker.Value = u.StartNodeId.ToString(); else contentPicker.Value = "-1"; content.Controls.Add(contentPicker); // Add password changer var passwordChanger = (passwordChanger) LoadControl(SystemDirectories.Umbraco + "/controls/passwordChanger.ascx"); passwordChanger.MembershipProviderName = UmbracoSettings.DefaultBackofficeProvider; //This is a hack to allow the admin to change a user's password to whatever they want - this will only work if we are using the // default umbraco membership provider. // See the notes below in the ChangePassword method. if (BackOfficeProvider.IsUmbracoUsersProvider()) { passwordChanger.ShowOldPassword = false; } //Add a custom validation message for the password changer var passwordValidation = new CustomValidator { ID = "PasswordChangerValidator" }; var validatorContainer = new HtmlGenericControl("div") { Visible = false, EnableViewState = false }; validatorContainer.Attributes["class"] = "error"; validatorContainer.Style.Add(HtmlTextWriterStyle.MarginTop, "10px"); validatorContainer.Style.Add(HtmlTextWriterStyle.Width, "300px"); var validatorContainer2 = new HtmlGenericControl("p"); validatorContainer.Controls.Add(validatorContainer2); validatorContainer2.Controls.Add(passwordValidation); passw.Controls.Add(passwordChanger); passw.Controls.Add(validatorContainer); pp.addProperty(ui.Text("user", "username", UmbracoUser), uname); pp.addProperty(ui.Text("user", "loginname", UmbracoUser), lname); pp.addProperty(ui.Text("user", "password", UmbracoUser), passw); pp.addProperty(ui.Text("email", UmbracoUser), email); pp.addProperty(ui.Text("user", "usertype", UmbracoUser), userType); pp.addProperty(ui.Text("user", "language", UmbracoUser), userLanguage); //Media / content root nodes Pane ppNodes = new Pane(); ppNodes.addProperty(ui.Text("user", "startnode", UmbracoUser), content); ppNodes.addProperty(ui.Text("user", "mediastartnode", UmbracoUser), medias); //Generel umrbaco access Pane ppAccess = new Pane(); if (UmbracoSettings.EnableCanvasEditing) { ppAccess.addProperty(ui.Text("user", "defaultToLiveEditing", UmbracoUser), DefaultToLiveEditing); } ppAccess.addProperty(ui.Text("user", "noConsole", UmbracoUser), NoConsole); ppAccess.addProperty(ui.Text("user", "disabled", UmbracoUser), Disabled); //access to which modules... Pane ppModules = new Pane(); ppModules.addProperty(ui.Text("user", "modules", UmbracoUser), lapps); ppModules.addProperty(" ", sectionValidator); TabPage userInfo = UserTabs.NewTabPage(u.Name); userInfo.Controls.Add(pp); userInfo.Controls.Add(ppNodes); userInfo.Controls.Add(ppAccess); userInfo.Controls.Add(ppModules); userInfo.Style.Add("text-align", "center"); userInfo.HasMenu = true; ImageButton save = userInfo.Menu.NewImageButton(); save.ImageUrl = SystemDirectories.Umbraco + "/images/editor/save.gif"; save.Click += new ImageClickEventHandler(SaveUser_Click); sectionValidator.ServerValidate += new ServerValidateEventHandler(sectionValidator_ServerValidate); sectionValidator.ControlToValidate = lapps.ID; sectionValidator.ErrorMessage = ui.Text("errorHandling", "errorMandatoryWithoutTab", ui.Text("user", "modules", UmbracoUser), UmbracoUser); sectionValidator.CssClass = "error"; SetupForm(); SetupChannel(); ClientTools .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) .SyncTree(UID.ToString(), IsPostBack); } void sectionValidator_ServerValidate(object source, ServerValidateEventArgs args) { args.IsValid = false; if (lapps.SelectedIndex >= 0) args.IsValid = true; } private void SetupChannel() { Channel userChannel; try { userChannel = new Channel(u.Id); } catch { userChannel = new Channel(); } // Populate dropdowns foreach (DocumentType dt in DocumentType.GetAllAsList()) cDocumentType.Items.Add( new ListItem(dt.Text, dt.Alias) ); // populate fields ArrayList fields = new ArrayList(); cDescription.ID = "cDescription"; cCategories.ID = "cCategories"; cExcerpt.ID = "cExcerpt"; cDescription.Items.Add(new ListItem(ui.Text("choose"), "")); cCategories.Items.Add(new ListItem(ui.Text("choose"), "")); cExcerpt.Items.Add(new ListItem(ui.Text("choose"), "")); foreach (PropertyType pt in PropertyType.GetAll()) { if (!fields.Contains(pt.Alias)) { cDescription.Items.Add(new ListItem(string.Format("{0} ({1})", pt.Name, pt.Alias), pt.Alias)); cCategories.Items.Add(new ListItem(string.Format("{0} ({1})", pt.Name, pt.Alias), pt.Alias)); cExcerpt.Items.Add(new ListItem(string.Format("{0} ({1})", pt.Name, pt.Alias), pt.Alias)); fields.Add(pt.Alias); } } // Handle content and media pickers PlaceHolder medias = new PlaceHolder(); cMediaPicker.AppAlias = Constants.Applications.Media; cMediaPicker.TreeAlias = "media"; if (userChannel.MediaFolder > 0) cMediaPicker.Value = userChannel.MediaFolder.ToString(); else cMediaPicker.Value = "-1"; medias.Controls.Add(cMediaPicker); PlaceHolder content = new PlaceHolder(); cContentPicker.AppAlias = Constants.Applications.Content; cContentPicker.TreeAlias = "content"; if (userChannel.StartNode > 0) cContentPicker.Value = userChannel.StartNode.ToString(); else cContentPicker.Value = "-1"; content.Controls.Add(cContentPicker); // Setup the panes Pane ppInfo = new Pane(); ppInfo.addProperty(ui.Text("name", UmbracoUser), cName); ppInfo.addProperty(ui.Text("user", "startnode", UmbracoUser), content); ppInfo.addProperty(ui.Text("user", "searchAllChildren", UmbracoUser), cFulltree); ppInfo.addProperty(ui.Text("user", "mediastartnode", UmbracoUser), medias); Pane ppFields = new Pane(); ppFields.addProperty(ui.Text("user", "documentType", UmbracoUser), cDocumentType); ppFields.addProperty(ui.Text("user", "descriptionField", UmbracoUser), cDescription); ppFields.addProperty(ui.Text("user", "categoryField", UmbracoUser), cCategories); ppFields.addProperty(ui.Text("user", "excerptField", UmbracoUser), cExcerpt); TabPage channelInfo = UserTabs.NewTabPage(ui.Text("user", "contentChannel", UmbracoUser)); channelInfo.Controls.Add(ppInfo); channelInfo.Controls.Add(ppFields); channelInfo.HasMenu = true; ImageButton save = channelInfo.Menu.NewImageButton(); save.ImageUrl = SystemDirectories.Umbraco + "/images/editor/save.gif"; save.Click += SaveUser_Click; save.ID = "save"; if (!IsPostBack) { cName.Text = userChannel.Name; cDescription.SelectedValue = userChannel.FieldDescriptionAlias; cCategories.SelectedValue = userChannel.FieldCategoriesAlias; cExcerpt.SelectedValue = userChannel.FieldExcerptAlias; cDocumentType.SelectedValue = userChannel.DocumentTypeAlias; cFulltree.Checked = userChannel.FullTree; } } /// /// Setups the form. /// private void SetupForm() { if (!IsPostBack) { MembershipUser user = BackOfficeProvider.GetUser(u.LoginName, false); uname.Text = u.Name; lname.Text = (user == null) ? u.LoginName : user.UserName; email.Text = (user == null) ? u.Email : user.Email; //// Prevent users from changing information if logged in through a custom provider //// custom provider mapped accounts have empty passwords by default... so set update user fields to read only //// this will not be a security issue because empty passwords are not allowed in membership provider. //// This might change in version 4.0 //if (string.IsNullOrEmpty(u.GetPassword())) //{ // uname.ReadOnly = true; // lname.ReadOnly = true; // email.ReadOnly = true; // passw.Visible = false; //} contentPicker.Value = u.StartNodeId.ToString(CultureInfo.InvariantCulture); mediaPicker.Value = u.StartMediaId.ToString(CultureInfo.InvariantCulture); // get the current users applications string currentUserApps = ";"; foreach (Application a in CurrentUser.Applications) currentUserApps += a.alias + ";"; Application[] uapps = u.Applications; foreach (Application app in BusinessLogic.Application.getAll()) { if (CurrentUser.IsRoot() || currentUserApps.Contains(";" + app.alias + ";")) { ListItem li = new ListItem(ui.Text("sections", app.alias), app.alias); if (!IsPostBack) foreach (Application tmp in uapps) if (app.alias == tmp.alias) li.Selected = true; lapps.Items.Add(li); } } } } protected override void OnInit(EventArgs e) { base.OnInit(e); //lapps.SelectionMode = ListSelectionMode.Multiple; lapps.RepeatLayout = RepeatLayout.Flow; lapps.RepeatDirection = RepeatDirection.Vertical; } protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference("../webservices/CMSNode.asmx")); // ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference("../webservices/legacyAjaxCalls.asmx")); } /// /// This handles changing the password /// /// /// /// private void ChangePassword(passwordChanger passwordChangerControl, MembershipUser membershipUser, CustomValidator passwordChangerValidator) { if (passwordChangerControl.IsChangingPassword) { //SD: not sure why this check is here but must have been for some reason at some point? if (string.IsNullOrEmpty(passwordChangerControl.ChangingPasswordModel.NewPassword) == false) { // make sure password is not empty if (string.IsNullOrEmpty(u.Password)) u.Password = "default"; } var changePasswordModel = passwordChangerControl.ChangingPasswordModel; // Is it using the default membership provider if (BackOfficeProvider.IsUmbracoUsersProvider()) { //This is a total hack so that an admin can change the password without knowing the previous one // we do this by simply passing in the already stored hashed/encrypted password in the database - // this shouldn't be allowed but to maintain backwards compatibility we need to do this because // this logic was previously allowed. //For this editor, we set the passwordChanger.ShowOldPassword = false so that the old password // field doesn't appear because we know we are going to manually set it here. // We'll change the model to have the already encrypted password stored in the db and that will continue to validate. changePasswordModel.OldPassword = u.Password; } //now do the actual change var changePassResult = _membershipHelper.ChangePassword( membershipUser.UserName, changePasswordModel, BackOfficeProvider); if (changePassResult.Success) { //if it is successful, we need to show the generated password if there was one, so set //that back on the control passwordChangerControl.ChangingPasswordModel.GeneratedPassword = changePassResult.Result.ResetPassword; } else { passwordChangerValidator.IsValid = false; passwordChangerValidator.ErrorMessage = changePassResult.Result.ChangeError.ErrorMessage; passw.Controls[1].Visible = true; } } } /// /// Handles the Click event of the saveUser control. /// /// The source of the event. /// The instance containing the event data. private void SaveUser_Click(object sender, ImageClickEventArgs e) { if (base.IsValid) { try { var membershipUser = BackOfficeProvider.GetUser(u.LoginName, false); if (membershipUser == null) { throw new ProviderException("Could not find user in the membership provider with login name " + u.LoginName); } var passwordChangerControl = (passwordChanger) passw.Controls[0]; var passwordChangerValidator = (CustomValidator) passw.Controls[1].Controls[0].Controls[0]; //perform the changing password logic ChangePassword(passwordChangerControl, membershipUser, passwordChangerValidator); //update the membership provider UpdateMembershipProvider(membershipUser); //update the Umbraco user properties - even though we are updating some of these properties in the membership provider that is // ok since the membership provider might be storing these details someplace totally different! But we want to keep our UI in sync. u.Name = uname.Text.Trim(); u.Language = userLanguage.SelectedValue; u.UserType = UserType.GetUserType(int.Parse(userType.SelectedValue)); u.Email = email.Text.Trim(); u.LoginName = lname.Text; u.Disabled = Disabled.Checked; u.DefaultToLiveEditing = DefaultToLiveEditing.Checked; u.NoConsole = NoConsole.Checked; int startNode; if (int.TryParse(contentPicker.Value, out startNode) == false) { //set to default if nothing is choosen if (u.StartNodeId > 0) startNode = u.StartNodeId; else startNode = -1; } u.StartNodeId = startNode; int mstartNode; if (int.TryParse(mediaPicker.Value, out mstartNode) == false) { //set to default if nothing is choosen if (u.StartMediaId > 0) mstartNode = u.StartMediaId; else mstartNode = -1; } u.StartMediaId = mstartNode; u.clearApplications(); foreach (ListItem li in lapps.Items) { if (li.Selected) u.addApplication(li.Value); } u.Save(); // save data if (cName.Text != "") { Channel c; try { c = new Channel(u.Id); } catch { c = new Channel(); c.User = u; } c.Name = cName.Text; c.FullTree = cFulltree.Checked; c.StartNode = int.Parse(cContentPicker.Value); c.MediaFolder = int.Parse(cMediaPicker.Value); c.FieldCategoriesAlias = cCategories.SelectedValue; c.FieldDescriptionAlias = cDescription.SelectedValue; c.FieldExcerptAlias = cExcerpt.SelectedValue; c.DocumentTypeAlias = cDocumentType.SelectedValue; // c.MediaTypeAlias = Constants.Conventions.MediaTypes.Image; // [LK:2013-03-22] This was previously lowercase; unsure if using const will cause an issue. c.MediaTypeFileProperty = Constants.Conventions.Media.File; c.ImageSupport = true; c.Save(); } ClientTools.ShowSpeechBubble(speechBubbleIcon.save, ui.Text("speechBubbles", "editUserSaved", UmbracoUser), ""); } catch (Exception ex) { ClientTools.ShowSpeechBubble(speechBubbleIcon.error, ui.Text("speechBubbles", "editUserError", UmbracoUser), ""); LogHelper.Error("Exception", ex); } } else { ClientTools.ShowSpeechBubble(speechBubbleIcon.error, ui.Text("speechBubbles", "editUserError", UmbracoUser), ""); } } private void UpdateMembershipProvider(MembershipUser membershipUser) { //SD: This check must be here for some reason but apparently we don't want to try to // update when the AD provider is active. if ((BackOfficeProvider is ActiveDirectoryMembershipProvider) == false) { var membershipHelper = new MembershipHelper(ApplicationContext, new HttpContextWrapper(Context)); //set the writable properties that we are editing membershipHelper.UpdateMember(membershipUser, BackOfficeProvider, email.Text.Trim(), Disabled.Checked == false, NoConsole.Checked); } } /// /// UserTabs control. /// /// /// Auto-generated field. /// To modify move field declaration from designer file to code-behind file. /// protected TabView UserTabs; } }