
This update applies the maxlength attribute fix to all input and textarea elements. The maxlength attribute will only be added if p.MaxLength is greater than 0, allowing unlimited characters when it's 0 or less.
223 lines
10 KiB
Plaintext
223 lines
10 KiB
Plaintext
@namespace Oqtane.Modules.Admin.Users
|
|
@using System.Text.RegularExpressions;
|
|
@inherits ModuleBase
|
|
@inject NavigationManager NavigationManager
|
|
@inject IUserService UserService
|
|
@inject IProfileService ProfileService
|
|
@inject ISettingService SettingService
|
|
@inject IStringLocalizer<Add> Localizer
|
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
|
|
|
@if (_initialized)
|
|
{
|
|
<TabStrip>
|
|
<TabPanel Name="Identity" ResourceKey="Identity">
|
|
@if (profiles != null)
|
|
{
|
|
<div class="container">
|
|
<div class="row mb-1 align-items-center">
|
|
<Label Class="col-sm-3" For="username" HelpText="A unique username for a user. Note that this field can not be modified once it is saved." ResourceKey="Username"></Label>
|
|
<div class="col-sm-9">
|
|
<input id="username" class="form-control" @bind="@_username" />
|
|
</div>
|
|
</div>
|
|
<div class="row mb-1 align-items-center">
|
|
<Label Class="col-sm-3" For="email" HelpText="The email address where the user will receive notifications" ResourceKey="Email"></Label>
|
|
<div class="col-sm-9">
|
|
<input id="email" class="form-control" @bind="@_email" />
|
|
</div>
|
|
</div>
|
|
<div class="row mb-1 align-items-center">
|
|
<Label Class="col-sm-3" For="displayname" HelpText="The full name of the user" ResourceKey="DisplayName"></Label>
|
|
<div class="col-sm-9">
|
|
<input id="displayname" class="form-control" @bind="@_displayname" />
|
|
</div>
|
|
</div>
|
|
<div class="row mb-1 align-items-center">
|
|
<Label Class="col-sm-3" For="notify" HelpText="Indicate if new users should receive an email notification" ResourceKey="Notify">Notify? </Label>
|
|
<div class="col-sm-9">
|
|
<select id="notify" class="form-select" @bind="@_notify" required>
|
|
<option value="True">@SharedLocalizer["Yes"]</option>
|
|
<option value="False">@SharedLocalizer["No"]</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
}
|
|
</TabPanel>
|
|
<TabPanel Name="Profile" ResourceKey="Profile">
|
|
<div class="container">
|
|
<div class="row mb-1 align-items-center">
|
|
@foreach (Profile profile in profiles)
|
|
{
|
|
var p = profile;
|
|
if (p.Category != category)
|
|
{
|
|
<div class="col text-center pb-2">
|
|
<strong>@p.Category</strong>
|
|
</div>
|
|
category = p.Category;
|
|
}
|
|
<div class="row mb-1 align-items-center">
|
|
<Label Class="col-sm-3" For="@p.Name" HelpText="@p.Description">@p.Title</Label>
|
|
<div class="col-sm-9">
|
|
@if (!string.IsNullOrEmpty(p.Options))
|
|
{
|
|
<select id="@p.Name" class="form-select" @onchange="@(e => ProfileChanged(e, p.Name))">
|
|
@foreach (var option in p.Options.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
|
|
{
|
|
@if (GetProfileValue(p.Name, "") == option || (GetProfileValue(p.Name, "") == "" && p.DefaultValue == option))
|
|
{
|
|
<option value="@option" selected>@option</option>
|
|
}
|
|
else
|
|
{
|
|
<option value="@option">@option</option>
|
|
}
|
|
}
|
|
</select>
|
|
}
|
|
else
|
|
{
|
|
@if (p.Rows == 1)
|
|
{
|
|
<input id="@p.Name" class="form-control" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)" />
|
|
}
|
|
else
|
|
{
|
|
<textarea id="@p.Name" class="form-control" rows="@p.Rows" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" @attributes="@(p.MaxLength > 0 ? new Dictionary<string, object> {{"maxlength", p.MaxLength }} : null)"></textarea>
|
|
}
|
|
}
|
|
</div>
|
|
</div>
|
|
}
|
|
</div>
|
|
</div>
|
|
</TabPanel>
|
|
</TabStrip>
|
|
<br />
|
|
<br />
|
|
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
|
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
|
}
|
|
|
|
|
|
@code {
|
|
private bool _initialized = false;
|
|
private string _username = string.Empty;
|
|
private string _email = string.Empty;
|
|
private string _displayname = string.Empty;
|
|
private string _notify = "True";
|
|
private List<Profile> profiles;
|
|
private Dictionary<string, string> settings;
|
|
private string category = string.Empty;
|
|
|
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
|
|
|
protected override async Task OnInitializedAsync()
|
|
{
|
|
try
|
|
{
|
|
profiles = await ProfileService.GetProfilesAsync(ModuleState.SiteId);
|
|
settings = new Dictionary<string, string>();
|
|
_initialized = true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await logger.LogError(ex, "Error Loading User Profile {Error}", ex.Message);
|
|
AddModuleMessage(Localizer["Error.Profile.Load"], MessageType.Error);
|
|
}
|
|
}
|
|
|
|
private string GetProfileValue(string SettingName, string DefaultValue)
|
|
{
|
|
string value = SettingService.GetSetting(settings, SettingName, DefaultValue);
|
|
if (value.Contains("]"))
|
|
{
|
|
value = value.Substring(value.IndexOf("]") + 1);
|
|
}
|
|
return value;
|
|
}
|
|
|
|
private async Task SaveUser()
|
|
{
|
|
try
|
|
{
|
|
if (_username != string.Empty && _email != string.Empty)
|
|
{
|
|
if (ValidateProfiles())
|
|
{
|
|
var user = new User();
|
|
user.SiteId = PageState.Site.SiteId;
|
|
user.Username = _username;
|
|
user.Password = ""; // will be auto generated
|
|
user.Email = _email;
|
|
user.DisplayName = string.IsNullOrWhiteSpace(_displayname) ? _username : _displayname;
|
|
user.PhotoFileId = null;
|
|
user.SuppressNotification = !bool.Parse(_notify);
|
|
|
|
user = await UserService.AddUserAsync(user);
|
|
|
|
if (user != null)
|
|
{
|
|
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
|
|
await logger.LogInformation("User Created {User}", user);
|
|
NavigationManager.NavigateTo(NavigateUrl());
|
|
}
|
|
else
|
|
{
|
|
await logger.LogError("Error Adding User {Username} {Email}", _username, _email);
|
|
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", _username, _email, ex.Message);
|
|
AddModuleMessage(Localizer["Error.User.Add"], MessageType.Error);
|
|
}
|
|
}
|
|
|
|
private bool ValidateProfiles()
|
|
{
|
|
foreach (Profile profile in profiles)
|
|
{
|
|
var value = GetProfileValue(profile.Name, string.Empty);
|
|
if (string.IsNullOrEmpty(value) && !string.IsNullOrEmpty(profile.DefaultValue))
|
|
{
|
|
settings = SettingService.SetSetting(settings, profile.Name, profile.DefaultValue);
|
|
}
|
|
if (!profile.IsPrivate || UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
|
|
{
|
|
if (profile.IsRequired && string.IsNullOrEmpty(value))
|
|
{
|
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileRequired"], profile.Title), MessageType.Warning);
|
|
return false;
|
|
}
|
|
if (!string.IsNullOrEmpty(profile.Validation))
|
|
{
|
|
Regex regex = new Regex(profile.Validation);
|
|
bool valid = regex.Match(value).Success;
|
|
if (!valid)
|
|
{
|
|
AddModuleMessage(string.Format(SharedLocalizer["ProfileInvalid"], profile.Title), MessageType.Warning);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void ProfileChanged(ChangeEventArgs e, string SettingName)
|
|
{
|
|
var value = (string)e.Value;
|
|
settings = SettingService.SetSetting(settings, SettingName, value);
|
|
}
|
|
}
|