themes - users validation changes

This commit is contained in:
Grayson Walker 2021-07-29 16:54:32 -04:00
parent 46fcfcc321
commit 9af8ab92c9
6 changed files with 567 additions and 487 deletions

View File

@ -11,61 +11,66 @@
@if (_templates != null) @if (_templates != null)
{ {
<div class="container"> <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="row mb-1 align-items-center"> <div class="container">
<Label Class="col-sm-3" For="owner" HelpText="Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label> <div class="row mb-1 align-items-center">
<div class="col-sm-9"> <Label Class="col-sm-3" For="owner" HelpText="Enter the name of the organization who is developing this theme. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
<input id="owner" class="form-control" @bind="@_owner" /> <div class="col-sm-9">
</div> <input id="owner" class="form-control" @bind="@_owner" maxlength="256" required />
</div> </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="module" HelpText="Enter a name for this theme. It should not contain spaces or punctuation." ResourceKey="ThemeName">Theme Name: </Label>
<div class="col-sm-9">
<input id="module" class="form-control" @bind="@_theme" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="template" HelpText="Select a theme template. Templates are located in the wwwroot/Themes/Templates folder on the server." ResourceKey="Template">Template: </Label>
<div class="col-sm-9">
<select id="template" class="form-select" @onchange="(e => TemplateChanged(e))">
<option value="-">&lt;@Localizer["Template.Select"]&gt;</option>
@foreach (Template template in _templates)
{
<option value="@template.Name">@template.Title</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
<div class="col-sm-9">
<select id="reference" class="form-select" @bind="@_reference">
@foreach (string version in _versions)
{
if (Version.Parse(version).CompareTo(Version.Parse(_minversion)) >= 0)
{
<option value="@(version)">@(version)</option>
}
}
<option value="local">@SharedLocalizer["LocalVersion"]</option>
</select>
</div>
</div>
@if (!string.IsNullOrEmpty(_location)) {
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="location" HelpText="Location where the theme will be created" ResourceKey="Location">Location: </Label>
<div class="col-sm-9">
<input id="module" class="form-control" @bind="@_location" readonly />
</div> </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="module" HelpText="Enter a name for this theme. It should not contain spaces or punctuation." ResourceKey="ThemeName">Theme Name: </Label>
<div class="col-sm-9">
<input id="module" class="form-control" @bind="@_theme" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="template" HelpText="Select a theme template. Templates are located in the wwwroot/Themes/Templates folder on the server." ResourceKey="Template">Template: </Label>
<div class="col-sm-9">
<select id="template" class="form-select" @onchange="(e => TemplateChanged(e))" required>
<option value="-">&lt;@Localizer["Template.Select"]&gt;</option>
@foreach (Template template in _templates)
{
<option value="@template.Name">@template.Title</option>
}
</select>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
<div class="col-sm-9">
<select id="reference" class="form-select" @bind="@_reference" required>
@foreach (string version in _versions)
{
if (Version.Parse(version).CompareTo(Version.Parse(_minversion)) >= 0)
{
<option value="@(version)">@(version)</option>
}
}
<option value="local">@SharedLocalizer["LocalVersion"]</option>
</select>
</div>
</div>
@if (!string.IsNullOrEmpty(_location))
{
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="location" HelpText="Location where the theme will be created" ResourceKey="Location">Location: </Label>
<div class="col-sm-9">
<input id="module" class="form-control" @bind="@_location" readonly />
</div>
</div>
}
</div> </div>
} <br />
</div> <button type="button" class="btn btn-success" @onclick="CreateTheme">@Localizer["Theme.Create"]</button>
<br /> <NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<button type="button" class="btn btn-success" @onclick="CreateTheme">@Localizer["Theme.Create"]</button> </form>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
} }
@code { @code {
private ElementReference form;
private bool validated = false;
private string _owner = string.Empty; private string _owner = string.Empty;
private string _theme = string.Empty; private string _theme = string.Empty;
private List<Template> _templates; private List<Template> _templates;
@ -93,23 +98,32 @@
private async Task CreateTheme() private async Task CreateTheme()
{ {
try validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-") try
{ {
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference }; if (IsValid(_owner) && IsValid(_theme) && _owner != _theme && _template != "-")
theme = await ThemeService.CreateThemeAsync(theme); {
GetLocation(); var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference };
AddModuleMessage(string.Format(Localizer["Success.Theme.Create"], NavigateUrl("admin/system")), MessageType.Success); theme = await ThemeService.CreateThemeAsync(theme);
GetLocation();
AddModuleMessage(string.Format(Localizer["Success.Theme.Create"], NavigateUrl("admin/system")), MessageType.Success);
}
else
{
AddModuleMessage(Localizer["Message.Required.ValidName"], MessageType.Warning);
}
} }
else catch (Exception ex)
{ {
AddModuleMessage(Localizer["Message.Required.ValidName"], MessageType.Warning); await logger.LogError(ex, "Error Creating Theme");
} }
} }
catch (Exception ex) else
{ {
await logger.LogError(ex, "Error Creating Theme"); AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
} }
} }

View File

@ -8,32 +8,36 @@
@if (PageState.User != null) @if (PageState.User != null)
{ {
<div class="container"> <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="row mb-1 align-items-center"> <div class="container">
<Label Class="col-sm-3" For="to" HelpText="Enter the username you wish to send a message to" ResourceKey="To">To: </Label> <div class="row mb-1 align-items-center">
<div class="col-sm-9"> <Label Class="col-sm-3" For="to" HelpText="Enter the username you wish to send a message to" ResourceKey="To">To: </Label>
<input id="to" class="form-control" @bind="@username" /> <div class="col-sm-9">
</div> > <input id="to" class="form-control" @bind="@username" maxlength="256" required />
</div> </div> >
<div class="row mb-1 align-items-center"> </div>
<Label Class="col-sm-3" For="subject" HelpText="Enter the subject of the message" ResourceKey="Subject">Subject: </Label> <div class="row mb-1 align-items-center">
<div class="col-sm-9"> <Label Class="col-sm-3" For="subject" HelpText="Enter the subject of the message" ResourceKey="Subject">Subject: </Label>
<input id="subject" class="form-control" @bind="@subject" /> <div class="col-sm-9">
<input id="subject" class="form-control" @bind="@subject" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="message" HelpText="Enter the message" ResourceKey="Message">Message: </Label>
<div class="col-sm-9">
<textarea id="message" class="form-control" @bind="@body" rows="5" required />
</div>
</div>
</div> </div>
</div> <br />
<div class="row mb-1 align-items-center"> <button type="button" class="btn btn-primary" @onclick="Send">@SharedLocalizer["Send"]</button>
<Label Class="col-sm-3" For="message" HelpText="Enter the message" ResourceKey="Message">Message: </Label> <NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<div class="col-sm-9"> </form>
<textarea id="message" class="form-control" @bind="@body" rows="5" />
</div>
</div>
</div>
<br/>
<button type="button" class="btn btn-primary" @onclick="Send">@SharedLocalizer["Send"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
} }
@code { @code {
private ElementReference form;
private bool validated = false;
private string username = ""; private string username = "";
private string subject = ""; private string subject = "";
private string body = ""; private string body = "";
@ -44,25 +48,34 @@
private async Task Send() private async Task Send()
{ {
try validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); try
if (user != null)
{ {
var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null); var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
notification = await NotificationService.AddNotificationAsync(notification); if (user != null)
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId); {
NavigationManager.NavigateTo(NavigateUrl()); var notification = new Notification(PageState.Site.SiteId, PageState.User, user, subject, body, null);
notification = await NotificationService.AddNotificationAsync(notification);
await logger.LogInformation("Notification Created {NotificationId}", notification.NotificationId);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["Message.User.Invalid"], MessageType.Warning);
}
} }
else catch (Exception ex)
{ {
AddModuleMessage(Localizer["Message.User.Invalid"], MessageType.Warning); await logger.LogError(ex, "Error Adding Notification {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Notification.Add"], MessageType.Error);
} }
} }
catch (Exception ex) else
{ {
await logger.LogError(ex, "Error Adding Notification {Error}", ex.Message); AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
AddModuleMessage(Localizer["Error.Notification.Add"], MessageType.Error);
} }
} }

View File

@ -21,47 +21,49 @@ else
<TabPanel Name="Identity" ResourceKey="Identity"> <TabPanel Name="Identity" ResourceKey="Identity">
@if (PageState.User != null) @if (PageState.User != null)
{ {
<div class="container"> <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="row mb-1 align-items-center"> <div class="container">
<Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified." ResourceKey="Username"></Label> <div class="row mb-1 align-items-center">
<div class="col-sm-9"> <Label Class="col-sm-3" For="username" HelpText="Your username. Note that this field can not be modified." ResourceKey="Username"></Label>
<input id="username" class="form-control" @bind="@username" readonly /> <div class="col-sm-9">
<input id="username" class="form-control" @bind="@username" readonly />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="If you wish to change your password you can enter it here. Please choose a sufficiently secure password." ResourceKey="Password"></Label>
<div class="col-sm-9">
<input id="password" type="password" class="form-control" @bind="@password" autocomplete="new-password" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<input id="confirm" type="password" class="form-control" @bind="@confirm" autocomplete="new-password" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to 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="Your full name" 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="@photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
<div class="col-sm-9">
<FileManager FileId="@photofileid" @ref="filemanager" />
</div>
</div> </div>
</div> </div>
<div class="row mb-1 align-items-center"> <br />
<Label Class="col-sm-3" For="password" HelpText="If you wish to change your password you can enter it here. Please choose a sufficiently secure password." ResourceKey="Password"></Label> <button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
<div class="col-sm-9"> <button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
<input id="password" type="password" class="form-control" @bind="@password" autocomplete="new-password" /> </form>
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="If you are changing your password you must enter it again to confirm it matches" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<input id="confirm" type="password" class="form-control" @bind="@confirm" autocomplete="new-password" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="email" HelpText="Your email address where you wish to 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="Your full name" 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="@photofileid.ToString()" HelpText="A photo of yourself" ResourceKey="Photo"></Label>
<div class="col-sm-9">
<FileManager FileId="@photofileid" @ref="filemanager" />
</div>
</div>
</div>
<br />
<button type="button" class="btn btn-success" @onclick="Save">@SharedLocalizer["Save"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@SharedLocalizer["Cancel"]</button>
} }
</TabPanel> </TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile"> <TabPanel Name="Profile" ResourceKey="Profile">
@ -132,11 +134,11 @@ else
{ {
<Pager Items="@notifications"> <Pager Items="@notifications">
<Header> <Header>
<th style="width: 1px;">&nbsp;</th> <th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th> <th style="width: 1px;">&nbsp;</th>
<th>@Localizer["From"]</th> <th>@Localizer["From"]</th>
<th>@Localizer["Subject"]</th> <th>@Localizer["Subject"]</th>
<th>@Localizer["Received"]</th> <th>@Localizer["Received"]</th>
</Header> </Header>
<Row> <Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td> <td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td>
@ -165,11 +167,11 @@ else
{ {
<Pager Items="@notifications"> <Pager Items="@notifications">
<Header> <Header>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>&nbsp;</th> <th>&nbsp;</th>
<th>@Localizer["To"]</th> <th>@Localizer["To"]</th>
<th>@Localizer["Subject"]</th> <th>@Localizer["Subject"]</th>
<th>@Localizer["Sent"]</th> <th>@Localizer["Sent"]</th>
</Header> </Header>
<Row> <Row>
<td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td> <td><ActionLink Action="View" Parameters="@($"id=" + context.NotificationId.ToString())" Security="SecurityAccessLevel.View" EditMode="false" ResourceKey="ViewNotification" /></td>
@ -204,6 +206,8 @@ else
</TabStrip> </TabStrip>
@code { @code {
private ElementReference form;
private bool validated = false;
private string username = string.Empty; private string username = string.Empty;
private string password = string.Empty; private string password = string.Empty;
private string confirm = string.Empty; private string confirm = string.Empty;
@ -269,43 +273,52 @@ else
private async Task Save() private async Task Save()
{ {
try validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
if (username != string.Empty && email != string.Empty && ValidateProfiles()) try
{ {
if (password == confirm) if (username != string.Empty && email != string.Empty && ValidateProfiles())
{ {
var user = PageState.User; if (password == confirm)
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = (displayname == string.Empty ? username : displayname);
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
{ {
user.PhotoFileId = null; var user = PageState.User;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = (displayname == string.Empty ? username : displayname);
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
{
user.PhotoFileId = null;
}
await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning);
} }
await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, PageState.User.UserId);
await logger.LogInformation("User Profile Saved");
NavigationManager.NavigateTo(NavigateUrl());
} }
else else
{ {
AddModuleMessage(Localizer["Message.Password.Invalid"], MessageType.Warning); AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
} }
} }
else catch (Exception ex)
{ {
AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning); await logger.LogError(ex, "Error Saving User Profile {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Profile.Save"], MessageType.Error);
} }
} }
catch (Exception ex) else
{ {
await logger.LogError(ex, "Error Saving User Profile {Error}", ex.Message); AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
AddModuleMessage(Localizer["Error.Profile.Save"], MessageType.Error);
} }
} }

View File

@ -7,86 +7,91 @@
@inject IStringLocalizer<Add> Localizer @inject IStringLocalizer<Add> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer @inject IStringLocalizer<SharedResources> SharedLocalizer
<TabStrip> <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<TabPanel Name="Identity" ResourceKey="Identity"> <TabStrip>
@if (profiles != null) <TabPanel Name="Identity" ResourceKey="Identity">
{ @if (profiles != null)
<div class="container"> {
<div class="row mb-1 align-items-center"> <div class="container">
<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="row mb-1 align-items-center">
<div class="col-sm-9"> <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>
<input id="username" class="form-control" @bind="@username" /> <div class="col-sm-9">
</div> <input id="username" class="form-control" @bind="@username" maxlength="256" required />
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
<div class="col-sm-9">
<input id="password" type="password" class="form-control" @bind="@password" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<input id="confirm" type="password" class="form-control" @bind="@confirm" />
</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>
}
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
@if (profiles != null)
{
<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 (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</div>
</div> </div>
} </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
<div class="col-sm-9">
<input id="password" type="password" class="form-control" @bind="@password" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<input id="confirm" type="password" class="form-control" @bind="@confirm" maxlength="256" required />
</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" maxlength="256" required />
</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" maxlength="256" required />
</div>
</div>
</div> </div>
</div>
} }
</TabPanel> </TabPanel>
</TabStrip> <TabPanel Name="Profile" ResourceKey="Profile">
<br /> @if (profiles != null)
<br /> {
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button> <div class="container">
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink> <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 (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</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>
</form>
@code { @code {
private ElementReference form;
private bool validated = false;
private string username = string.Empty; private string username = string.Empty;
private string password = string.Empty; private string password = string.Empty;
private string confirm = string.Empty; private string confirm = string.Empty;
@ -117,56 +122,65 @@
private async Task SaveUser() private async Task SaveUser()
{ {
try validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
if (username != string.Empty && password != string.Empty && confirm != string.Empty && email != string.Empty && ValidateProfiles()) try
{ {
if (password == confirm) if (username != string.Empty && password != string.Empty && confirm != string.Empty && email != string.Empty && ValidateProfiles())
{ {
var user = await UserService.GetUserAsync(username, PageState.Site.SiteId); if (password == confirm)
if (user == null)
{ {
user = new User(); var user = await UserService.GetUserAsync(username, PageState.Site.SiteId);
user.SiteId = PageState.Site.SiteId; if (user == null)
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.PhotoFileId = null;
user = await UserService.AddUserAsync(user);
if (user != null)
{ {
await SettingService.UpdateUserSettingsAsync(settings, user.UserId); user = new User();
await logger.LogInformation("User Created {User}", user); user.SiteId = PageState.Site.SiteId;
NavigationManager.NavigateTo(NavigateUrl()); user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.PhotoFileId = null;
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 else
{ {
await logger.LogError("Error Adding User {Username} {Email}", username, email); AddModuleMessage(Localizer["Message.Username.Exists"], MessageType.Warning);
AddModuleMessage(Localizer["Error.User.AddCheckPass"], MessageType.Error);
} }
} }
else else
{ {
AddModuleMessage(Localizer["Message.Username.Exists"], MessageType.Warning); AddModuleMessage(Localizer["Message.Password.NoMatch"], MessageType.Warning);
} }
} }
else else
{ {
AddModuleMessage(Localizer["Message.Password.NoMatch"], MessageType.Warning); AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
} }
} }
else catch (Exception ex)
{ {
AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning); await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", username, email, ex.Message);
AddModuleMessage(Localizer["Error.User.Add"], MessageType.Error);
} }
} }
catch (Exception ex) else
{ {
await logger.LogError(ex, "Error Adding User {Username} {Email} {Error}", username, email, ex.Message); AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
AddModuleMessage(Localizer["Error.User.Add"], MessageType.Error);
} }
} }

View File

@ -16,102 +16,106 @@ else
{ {
<br /> <br />
} }
<TabStrip> <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<TabPanel Name="Identity" ResourceKey="Identity"> <TabStrip>
@if (profiles != null) <TabPanel Name="Identity" ResourceKey="Identity">
{ @if (profiles != null)
<div class="container"> {
<div class="row mb-1 align-items-center"> <div class="container">
<Label Class="col-sm-3" For="username" HelpText="The unique username for a user. Note that this field can not be modified." ResourceKey="Username"></Label> <div class="row mb-1 align-items-center">
<div class="col-sm-9"> <Label Class="col-sm-3" For="username" HelpText="The unique username for a user. Note that this field can not be modified." ResourceKey="Username"></Label>
<input id="username" class="form-control" @bind="@username" readonly /> <div class="col-sm-9">
</div> <input id="username" class="form-control" @bind="@username" readonly />
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
<div class="col-sm-9">
<input id="password" type="password" class="form-control" @bind="@password" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<input id="confirm" type="password" class="form-control" @bind="@confirm" />
</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="@photofileid.ToString()" HelpText="A photo of the user" ResourceKey="Photo"></Label>
<div class="col-sm-9">
<FileManager FileId="@photofileid" @ref="filemanager" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
<div class="col-sm-9">
<select id="isdeleted" class="form-select" @bind="@isdeleted">
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div>
}
</TabPanel>
<TabPanel Name="Profile" ResourceKey="Profile">
@if (profiles != null)
{
<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 (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</div>
</div> </div>
} </div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="password" HelpText="The user's password. Please choose a password which is sufficiently secure." ResourceKey="Password"></Label>
<div class="col-sm-9">
<input id="password" type="password" class="form-control" @bind="@password" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="confirm" HelpText="Please enter the password again to confirm it matches with the value above" ResourceKey="Confirm"></Label>
<div class="col-sm-9">
<input id="confirm" type="password" class="form-control" @bind="@confirm" maxlength="256" required />
</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" maxlength="256" required />
</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" maxlength="256" required />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="@photofileid.ToString()" HelpText="A photo of the user" ResourceKey="Photo"></Label>
<div class="col-sm-9">
<FileManager FileId="@photofileid" @ref="filemanager" />
</div>
</div>
<div class="row mb-1 align-items-center">
<Label Class="col-sm-3" For="isdeleted" HelpText="Indicate if the user is active" ResourceKey="IsDeleted"></Label>
<div class="col-sm-9">
<select id="isdeleted" class="form-select" @bind="@isdeleted" required>
<option value="True">@SharedLocalizer["Yes"]</option>
<option value="False">@SharedLocalizer["No"]</option>
</select>
</div>
</div>
</div> </div>
</div>
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button> }
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink> </TabPanel>
<br /> <TabPanel Name="Profile" ResourceKey="Profile">
<br /> @if (profiles != null)
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo> {
<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 (p.IsRequired)
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" required @onchange="@(e => ProfileChanged(e, p.Name))" />
}
else
{
<input id="@p.Name" class="form-control" maxlength="@p.MaxLength" value="@GetProfileValue(p.Name, p.DefaultValue)" @onchange="@(e => ProfileChanged(e, p.Name))" />
}
</div>
</div>
}
</div>
</div>
}
</TabPanel>
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SaveUser">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<br />
<br />
<AuditInfo CreatedBy="@createdby" CreatedOn="@createdon" ModifiedBy="@modifiedby" ModifiedOn="@modifiedon" DeletedBy="@deletedby" DeletedOn="@deletedon"></AuditInfo>
</form>
@code { @code {
private ElementReference form;
private bool validated = false;
private int userid; private int userid;
private string username = string.Empty; private string username = string.Empty;
private string password = string.Empty; private string password = string.Empty;
@ -182,47 +186,56 @@ else
private async Task SaveUser() private async Task SaveUser()
{ {
try validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
if (username != string.Empty && email != string.Empty && ValidateProfiles()) try
{ {
if (password == confirm) if (username != string.Empty && email != string.Empty && ValidateProfiles())
{ {
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId); if (password == confirm)
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.PhotoFileId = null;
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
{ {
var user = await UserService.GetUserAsync(userid, PageState.Site.SiteId);
user.SiteId = PageState.Site.SiteId;
user.Username = username;
user.Password = password;
user.Email = email;
user.DisplayName = string.IsNullOrWhiteSpace(displayname) ? username : displayname;
user.PhotoFileId = null; user.PhotoFileId = null;
user.PhotoFileId = filemanager.GetFileId();
if (user.PhotoFileId == -1)
{
user.PhotoFileId = null;
}
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
user = await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
await logger.LogInformation("User Saved {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
}
else
{
AddModuleMessage(Localizer["Message.Password.NoMatch"], MessageType.Warning);
} }
user.IsDeleted = (isdeleted == null ? true : Boolean.Parse(isdeleted));
user = await UserService.UpdateUserAsync(user);
await SettingService.UpdateUserSettingsAsync(settings, user.UserId);
await logger.LogInformation("User Saved {User}", user);
NavigationManager.NavigateTo(NavigateUrl());
} }
else else
{ {
AddModuleMessage(Localizer["Message.Password.NoMatch"], MessageType.Warning); AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning);
} }
} }
else catch (Exception ex)
{ {
AddModuleMessage(Localizer["Message.Required.ProfileInfo"], MessageType.Warning); await logger.LogError(ex, "Error Saving User {Username} {Email} {Error}", username, email, ex.Message);
AddModuleMessage(Localizer["Error.User.Save"], MessageType.Error);
} }
} }
catch (Exception ex) else
{ {
await logger.LogError(ex, "Error Saving User {Username} {Email} {Error}", username, email, ex.Message); AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
AddModuleMessage(Localizer["Error.User.Save"], MessageType.Error);
} }
} }

View File

@ -12,65 +12,69 @@
} }
else else
{ {
<div class="container"> <form @ref="form" class="@(validated ? "was-validated" : "needs-validation")" novalidate>
<div class="row mb-1 align-items-center"> <div class="container">
<Label Class="col-sm-3" For="user" HelpText="The user you are assigning roles to" ResourceKey="User">User: </Label> <div class="row mb-1 align-items-center">
<div class="col-sm-9"> <Label Class="col-sm-3" For="user" HelpText="The user you are assigning roles to" ResourceKey="User">User: </Label>
<input id="user" class="form-control" @bind="@name" disabled /> <div class="col-sm-9">
<input id="user" class="form-control" @bind="@name" disabled />
</div>
</div> </div>
</div> <div class="row mb-1 align-items-center">
<div class="row mb-1 align-items-center"> <Label Class="col-sm-3" For="role" HelpText="Select a role" ResourceKey="Role">Role: </Label>
<Label Class="col-sm-3" For="role" HelpText="Select a role" ResourceKey="Role">Role: </Label> <div class="col-sm-9">
<div class="col-sm-9"> <select id="role" class="form-select" @bind="@roleid" required>
<select id="role" class="form-select" @bind="@roleid"> <option value="-1">&lt;@Localizer["Role.Select"]&gt;</option>
<option value="-1">&lt;@Localizer["Role.Select"]&gt;</option> @foreach (Role role in roles)
@foreach (Role role in roles) {
{ <option value="@(role.RoleId)">@role.Name</option>
<option value="@(role.RoleId)">@role.Name</option> }
} </select>
</select> </div>
</div> </div>
</div> <div class="row mb-1 align-items-center">
<div class="row mb-1 align-items-center"> <Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this role assignment is active" ResourceKey="EffectiveDate">Effective Date: </Label>
<Label Class="col-sm-3" For="effectiveDate" HelpText="The date that this role assignment is active" ResourceKey="EffectiveDate">Effective Date: </Label> <div class="col-sm-9">
<div class="col-sm-9"> <input id="effectiveDate" class="form-control" @bind="@effectivedate" required />
<input id="effectiveDate" class="form-control" @bind="@effectivedate" /> </div>
</div> </div>
</div> <div class="row mb-1 align-items-center">
<div class="row mb-1 align-items-center"> <Label Class="col-sm-3" For="expiryDate" HelpText="The date that this role assignment expires" ResourceKey="ExpiryDate">Expiry Date: </Label>
<Label Class="col-sm-3" For="expiryDate" HelpText="The date that this role assignment expires" ResourceKey="ExpiryDate">Expiry Date: </Label> <div class="col-sm-9">
<div class="col-sm-9"> <input id="expiryDate" class="form-control" @bind="@expirydate" required />
<input id="expiryDate" class="form-control" @bind="@expirydate" /> </div>
</div> </div>
</div>
</div> </div>
<br /> <br />
<br /> <br />
<button type="button" class="btn btn-success" @onclick="SaveUserRole">@SharedLocalizer["Save"]</button> <button type="button" class="btn btn-success" @onclick="SaveUserRole">@SharedLocalizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink> <NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
<hr class="app-rule" /> <hr class="app-rule" />
<p align="center"> <p align="center">
<Pager Items="@userroles"> <Pager Items="@userroles">
<Header> <Header>
<th>@Localizer["Roles"]</th> <th>@Localizer["Roles"]</th>
<th>@Localizer["Effective"]</th> <th>@Localizer["Effective"]</th>
<th>@Localizer["Expiry"]</th> <th>@Localizer["Expiry"]</th>
<th>&nbsp;</th> <th>&nbsp;</th>
</Header> </Header>
<Row> <Row>
<td>@context.Role.Name</td> <td>@context.Role.Name</td>
<td>@context.EffectiveDate</td> <td>@context.EffectiveDate</td>
<td>@context.ExpiryDate</td> <td>@context.ExpiryDate</td>
<td> <td>
<ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" /> <ActionDialog Header="Remove Role" Message="@string.Format(Localizer["Confirm.User.RemoveRole"], context.Role.Name)" Action="Delete" Security="SecurityAccessLevel.Admin" Class="btn btn-danger" OnClick="@(async () => await DeleteUserRole(context.UserRoleId))" Disabled="@(context.Role.IsAutoAssigned || (context.Role.Name == RoleNames.Host && userid == PageState.User.UserId))" ResourceKey="DeleteUserRole" />
</td> </td>
</Row> </Row>
</Pager> </Pager>
</p> </p>
</form>
} }
@code { @code {
private ElementReference form;
private bool validated = false;
private int userid; private int userid;
private string name = string.Empty; private string name = string.Empty;
private List<Role> roles; private List<Role> roles;
@ -122,73 +126,82 @@ else
private async Task SaveUserRole() private async Task SaveUserRole()
{ {
try validated = true;
var interop = new Interop(JSRuntime);
if (await interop.FormValid(form))
{ {
if (roleid != -1) try
{ {
var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault(); if (roleid != -1)
if (userrole != null)
{ {
if (string.IsNullOrEmpty(effectivedate)) var userrole = userroles.Where(item => item.UserId == userid && item.RoleId == roleid).FirstOrDefault();
if (userrole != null)
{ {
userrole.EffectiveDate = null; if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.UpdateUserRoleAsync(userrole);
} }
else else
{ {
userrole.EffectiveDate = DateTime.Parse(effectivedate); userrole = new UserRole();
userrole.UserId = userid;
userrole.RoleId = roleid;
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.AddUserRoleAsync(userrole);
} }
if (string.IsNullOrEmpty(expirydate)) await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
{ AddModuleMessage(Localizer["Success.User.AssignRole"], MessageType.Success);
userrole.ExpiryDate = null; await GetUserRoles();
} StateHasChanged();
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.UpdateUserRoleAsync(userrole);
} }
else else
{ {
userrole = new UserRole(); AddModuleMessage(Localizer["Message.Required.Role"], MessageType.Warning);
userrole.UserId = userid;
userrole.RoleId = roleid;
if (string.IsNullOrEmpty(effectivedate))
{
userrole.EffectiveDate = null;
}
else
{
userrole.EffectiveDate = DateTime.Parse(effectivedate);
}
if (string.IsNullOrEmpty(expirydate))
{
userrole.ExpiryDate = null;
}
else
{
userrole.ExpiryDate = DateTime.Parse(expirydate);
}
await UserRoleService.AddUserRoleAsync(userrole);
} }
await logger.LogInformation("User Assigned To Role {UserRole}", userrole);
AddModuleMessage(Localizer["Success.User.AssignRole"], MessageType.Success);
await GetUserRoles();
StateHasChanged();
} }
else catch (Exception ex)
{ {
AddModuleMessage(Localizer["Message.Required.Role"], MessageType.Warning); await logger.LogError(ex, "Error Saving User Roles {UserId} {Error}", userid, ex.Message);
AddModuleMessage(Localizer["Error.User.SaveRole"], MessageType.Error);
} }
} }
catch (Exception ex) else
{ {
await logger.LogError(ex, "Error Saving User Roles {UserId} {Error}", userid, ex.Message); AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
AddModuleMessage(Localizer["Error.User.SaveRole"], MessageType.Error);
} }
} }