feature: flag permissions
feature: flag permissions
This commit is contained in:
@@ -47,6 +47,9 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
m.ThemeColours = UIHelpers.ThemeColours;
|
||||
}
|
||||
|
||||
var (_, permission) = DeviceFlagService.GetDeviceFlag(m.DeviceFlag.Id);
|
||||
m.Permission = permission;
|
||||
|
||||
// UI Extensions
|
||||
UIExtensions.ExecuteExtensions<ConfigDeviceFlagShowModel>(ControllerContext, m);
|
||||
|
||||
@@ -121,7 +124,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
var m = new ExportModel()
|
||||
{
|
||||
Options = Database.DiscoConfiguration.DeviceFlags.LastExportOptions,
|
||||
DeviceFlags = DeviceFlagService.GetDeviceFlags(),
|
||||
DeviceFlags = DeviceFlagService.GetDeviceFlags().Select(f => f.flag).ToList(),
|
||||
};
|
||||
|
||||
m.Fields = ExportFieldsModel.Create(m.Options, DeviceFlagExportOptions.DefaultOptions(), nameof(DeviceFlagExportOptions.CurrentOnly));
|
||||
|
||||
@@ -46,6 +46,9 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
m.ThemeColours = UIHelpers.ThemeColours;
|
||||
}
|
||||
|
||||
var (flag, permission) = UserFlagService.GetUserFlag(m.UserFlag.Id);
|
||||
m.Permission = permission;
|
||||
|
||||
// UI Extensions
|
||||
UIExtensions.ExecuteExtensions<ConfigUserFlagShowModel>(ControllerContext, m);
|
||||
|
||||
@@ -122,7 +125,7 @@ namespace Disco.Web.Areas.Config.Controllers
|
||||
var m = new ExportModel()
|
||||
{
|
||||
Options = Database.DiscoConfiguration.UserFlags.LastExportOptions,
|
||||
UserFlags = UserFlagService.GetUserFlags(),
|
||||
UserFlags = UserFlagService.GetUserFlags().Select(f => f.flag).ToList(),
|
||||
};
|
||||
|
||||
m.Fields = ExportFieldsModel.Create(m.Options, UserFlagExportOptions.DefaultOptions(), nameof(UserFlagExportOptions.CurrentOnly));
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.Models.UI.Config.DeviceFlag;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.UI.Config.DeviceFlag;
|
||||
using Disco.Services.Devices.DeviceFlags;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -16,5 +17,7 @@ namespace Disco.Web.Areas.Config.Models.DeviceFlag
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> Icons { get; set; }
|
||||
public IEnumerable<KeyValuePair<string, string>> ThemeColours { get; set; }
|
||||
|
||||
public FlagPermission Permission { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Disco.Models.UI.Config.UserFlag;
|
||||
using Disco.Models.Repository;
|
||||
using Disco.Models.UI.Config.UserFlag;
|
||||
using Disco.Services.Users.UserFlags;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -16,5 +17,7 @@ namespace Disco.Web.Areas.Config.Models.UserFlag
|
||||
|
||||
public IEnumerable<KeyValuePair<string, string>> Icons { get; set; }
|
||||
public IEnumerable<KeyValuePair<string, string>> ThemeColours { get; set; }
|
||||
|
||||
public FlagPermission Permission { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -237,7 +237,7 @@
|
||||
<div id="Config_AuthRoles_Claims_Tree">
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" id="Config_AuthRoles_Claims_SaveChanges" class="button small disabled" data-saveurl="@Url.Action(MVC.API.AuthorizationRole.UpdateClaims(Model.Token.Role.Id))">Save Changes</button>@AjaxHelpers.AjaxLoader()
|
||||
<button type="button" typeof="button" id="Config_AuthRoles_Claims_SaveChanges" class="button small disabled" data-saveurl="@Url.Action(MVC.API.AuthorizationRole.UpdateClaims(Model.Token.Role.Id))">Save Changes</button>@AjaxHelpers.AjaxLoader()
|
||||
</div>
|
||||
<script id="Config_AuthRoles_Claims_NodesJson" type="application/json">
|
||||
@Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(Model.ClaimNavigatorFancyTreeNodes))
|
||||
@@ -286,7 +286,7 @@
|
||||
saveButton.addClass('disabled');
|
||||
ajaxLoading.next('.ajaxOk').show().delay('fast').fadeOut('slow');
|
||||
} else {
|
||||
alert('Unable to save changes:\n' + response);
|
||||
alert('Unable to save changes:\n' + response.statusText);
|
||||
}
|
||||
} catch (e) {
|
||||
alert('Error: ' + e);
|
||||
|
||||
@@ -656,6 +656,8 @@ WriteLiteral(">\r\n </div>\r\n <div>\r\n
|
||||
|
||||
WriteLiteral(" type=\"button\"");
|
||||
|
||||
WriteLiteral(" typeof=\"button\"");
|
||||
|
||||
WriteLiteral(" id=\"Config_AuthRoles_Claims_SaveChanges\"");
|
||||
|
||||
WriteLiteral(" class=\"button small disabled\"");
|
||||
@@ -664,7 +666,7 @@ WriteLiteral(" data-saveurl=\"");
|
||||
|
||||
|
||||
#line 240 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.UpdateClaims(Model.Token.Role.Id)));
|
||||
Write(Url.Action(MVC.API.AuthorizationRole.UpdateClaims(Model.Token.Role.Id)));
|
||||
|
||||
|
||||
#line default
|
||||
@@ -675,7 +677,7 @@ WriteLiteral(">Save Changes</button>");
|
||||
|
||||
|
||||
#line 240 "..\..\Areas\Config\Views\AuthorizationRole\Show.cshtml"
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
Write(AjaxHelpers.AjaxLoader());
|
||||
|
||||
|
||||
#line default
|
||||
@@ -728,13 +730,13 @@ WriteLiteral("\r\n </script>\r\n <script>\r\n
|
||||
"dClass(\'disabled\');\r\n ajaxLoading.nex" +
|
||||
"t(\'.ajaxOk\').show().delay(\'fast\').fadeOut(\'slow\');\r\n " +
|
||||
" } else {\r\n alert(\'Unable " +
|
||||
"to save changes:\\n\' + response);\r\n }\r\n " +
|
||||
" } catch (e) {\r\n " +
|
||||
" alert(\'Error: \' + e);\r\n }\r\n " +
|
||||
" ajaxLoading.hide();\r\n }" +
|
||||
"\r\n });\r\n });\r\n " +
|
||||
" })();\r\n </script>\r\n </td>\r\n </tr>\r\n </ta" +
|
||||
"ble>\r\n</div>\r\n<div");
|
||||
"to save changes:\\n\' + response.statusText);\r\n " +
|
||||
" }\r\n } catch (e) {\r\n " +
|
||||
" alert(\'Error: \' + e);\r\n }\r" +
|
||||
"\n ajaxLoading.hide();\r\n " +
|
||||
" }\r\n });\r\n });\r\n " +
|
||||
" })();\r\n </script>\r\n </td>\r\n </tr" +
|
||||
">\r\n </table>\r\n</div>\r\n<div");
|
||||
|
||||
WriteLiteral(" class=\"actionBar\"");
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
var canExportAll = Model.TotalAssignmentCount > 0 && Authorization.Has(Claims.Config.DeviceFlag.Export);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.Permission.IsDefault() &&
|
||||
Model.DeviceFlag.DevicesLinkedGroup == null &&
|
||||
Model.DeviceFlag.DeviceUsersLinkedGroup == null &&
|
||||
Model.DeviceFlag.OnAssignmentExpression == null &&
|
||||
@@ -38,10 +39,11 @@
|
||||
</th>
|
||||
<td>
|
||||
@if (canConfig)
|
||||
{@Html.EditorFor(model => model.DeviceFlag.Name)
|
||||
@AjaxHelpers.AjaxSave()
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
{
|
||||
@Html.EditorFor(model => model.DeviceFlag.Name)
|
||||
@AjaxHelpers.AjaxSave()
|
||||
@AjaxHelpers.AjaxLoader()
|
||||
<script type="text/javascript">
|
||||
$(function () {
|
||||
document.DiscoFunctions.PropertyChangeHelper(
|
||||
$('#DeviceFlag_Name'),
|
||||
@@ -50,12 +52,12 @@
|
||||
'FlagName'
|
||||
);
|
||||
});
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Model.DeviceFlag.Name
|
||||
}
|
||||
</script>
|
||||
}
|
||||
else
|
||||
{
|
||||
@Model.DeviceFlag.Name
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
@@ -227,6 +229,340 @@
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>
|
||||
Assignment Permission<br />
|
||||
Override:
|
||||
</th>
|
||||
<td>
|
||||
@if (!Model.Permission.IsDefault())
|
||||
{
|
||||
var permission = Model.Permission;
|
||||
<div>
|
||||
@if (permission.Inherit)
|
||||
{
|
||||
<span><i class="fa fa-check-square-o"></i> Inheriting from Authorization Roles</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span><i class="fa fa-square-o"></i> Authorization Roles are Ignored</span>
|
||||
}
|
||||
</div>
|
||||
if (!permission.HasSubjects())
|
||||
{
|
||||
<span class="smallMessage">There are no users/groups associated with this permission override</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (permission.IsSimple())
|
||||
{
|
||||
<table class="tableData">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Users/Groups/Roles</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var subjectId in permission.CanShowSubjectIds)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@{
|
||||
int roleId;
|
||||
if (subjectId.StartsWith("[") && int.TryParse(subjectId.Trim('[', ']'), out roleId))
|
||||
{
|
||||
<span>@Disco.Services.Users.UserService.GetAuthorizationRoleName(roleId) @subjectId</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@subjectId</span>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="info-box">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-fw fa-info-circle"></i> All users/groups/roles can view, assign, edit assignments, and remove assignments for this flag.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
var subjects = permission.AllSubjects();
|
||||
<table class="tableData">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Users/Groups/Roles</th>
|
||||
<th>View</th>
|
||||
<th>Assign</th>
|
||||
<th>Edit</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var subjectId in subjects.OrderBy(s => s))
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<i class="fa"></i> @{
|
||||
int roleId;
|
||||
if (subjectId.StartsWith("[") && int.TryParse(subjectId.Trim('[', ']'), out roleId))
|
||||
{
|
||||
<span>@Disco.Services.Users.UserService.GetAuthorizationRoleName(roleId) @subjectId</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@subjectId</span>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanShowSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanAssignSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanEditSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanRemoveSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@if (canConfig)
|
||||
{
|
||||
var permission = Model.Permission;
|
||||
<button id="Config_Flag_Permission_Edit" class="button small">@(permission.IsDefault() ? "Override" : "Edit") Permission</button>
|
||||
|
||||
<div id="Config_Flag_Permissions" class="dialog" title="Flag Assignment Permission Override">
|
||||
@using (Html.BeginForm(MVC.API.DeviceFlag.Permission(Model.DeviceFlag.Id)))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<input type="hidden" name="IsOverride" value="true" />
|
||||
<div id="Config_Flag_Permissions_Inherit_Container">
|
||||
<label>
|
||||
<input id="Config_Flag_Permissions_Inherit" type="checkbox" name="Inherit" value="true" @(permission.Inherit ? "checked" : null) /> Inherit Authorization from Authorization Roles
|
||||
</label>
|
||||
</div>
|
||||
<div class="tableDataContainer">
|
||||
<table class="tableData">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User/Group/Role</th>
|
||||
<th>View</th>
|
||||
<th>Assign</th>
|
||||
<th>Edit</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
var subjects = permission.AllSubjects();
|
||||
|
||||
foreach (var subjectId in subjects.OrderBy(s => s))
|
||||
{
|
||||
<tr data-subjectid="@subjectId">
|
||||
<td><i class="fa type"></i> <span>@subjectId</span><i class="fa fa-times-circle remove"></i></td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanShow" value="@subjectId" @(permission.CanShowSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanAssign" value="@subjectId" @(permission.CanAssignSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanEdit" value="@subjectId" @(permission.CanEditSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanRemove" value="@subjectId" @(permission.CanRemoveSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" id="Config_Flag_Permissions_Subject_Input" placeholder="Search Users/Groups/Roles" data-autocompleteurl="@(Url.Action(MVC.API.System.SearchSubjects(null, includeAuthorizationRoles: true)))" />
|
||||
<button type="button" id="Config_Flag_Permissions_Subject_Add" class="button small" data-subjecturl="@Url.Action(MVC.API.System.Subject(null, includeAuthorizationRoles: true))">Add</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
let $dialog = null;
|
||||
let originalSubjects = null;
|
||||
let originalInherit = null;
|
||||
$('#Config_Flag_Permission_Edit').on('click', async function () {
|
||||
if (!$dialog) {
|
||||
$dialog = $('#Config_Flag_Permissions');
|
||||
const $tbody = $dialog.find('tbody');
|
||||
const $inherit = $dialog.find('#Config_Flag_Permissions_Inherit');
|
||||
const $input = $dialog.find('#Config_Flag_Permissions_Subject_Input');
|
||||
const $add = $dialog.find('#Config_Flag_Permissions_Subject_Add');
|
||||
|
||||
$dialog.dialog({
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 550,
|
||||
height: 420,
|
||||
buttons: {
|
||||
Cancel: function () {
|
||||
$(this).dialog('close');
|
||||
$tbody.html(originalSubjects);
|
||||
$inherit.prop('checked', originalInherit);
|
||||
},
|
||||
'Remove Override': function () {
|
||||
const $this = $(this);
|
||||
$(this).dialog('option', 'buttons', null);
|
||||
$this.find('input[name="IsOverride"]').val('false');
|
||||
$this.find('form').trigger('submit');
|
||||
},
|
||||
'Save Changes': function () {
|
||||
$(this).dialog('option', 'buttons', null);
|
||||
$(this).find('form').trigger('submit');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$tbody.on('click', 'i.remove', function () {
|
||||
$(this).closest('tr').remove();
|
||||
});
|
||||
|
||||
$input
|
||||
.autocomplete({
|
||||
source: $input.attr('data-autocompleteurl'),
|
||||
minLength: 2,
|
||||
focus: function (e, ui) {
|
||||
$input.val(ui.item.Id);
|
||||
return false;
|
||||
},
|
||||
select: function (e, ui) {
|
||||
$input.val(ui.item.Id).blur();
|
||||
$add.trigger('click');
|
||||
$input.val('');
|
||||
return false;
|
||||
}
|
||||
}).data('ui-autocomplete')._renderItem = function (ul, item) {
|
||||
return $("<li></li>")
|
||||
.data('item.autocomplete', item)
|
||||
.append('<a><strong>' + item.Name + '</strong><br>' + item.Id + ' (' + item.Type + ')</a>')
|
||||
.appendTo(ul);
|
||||
};
|
||||
|
||||
$add.on('click', async function () {
|
||||
const value = $input.val();
|
||||
if (!value) {
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
const existing = $tbody.find('tr').filter(function () {
|
||||
return $(this).attr('data-subjectid') === value;
|
||||
});
|
||||
if (existing.length !== 0) {
|
||||
$input.val('');
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const body = new FormData();
|
||||
body.append('id', value);
|
||||
const response = await fetch($add.attr('data-subjecturl'), {
|
||||
body: body,
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
alert('Unable to lookup User/Group/Role: ' + response.statusText);
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const subject = await response.json();
|
||||
|
||||
if (!subject) {
|
||||
alert('Invalid User/Group/Role');
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const $record = $('<tr><td><i class="fa type"></i> <span></span><i class="fa fa-times-circle remove"></i></td><td><input type="checkbox" name="CanShow" checked /></td><td><input type="checkbox" name="CanAssign" checked /></td><td><input type="checkbox" name="CanEdit" checked /></td><td><input type="checkbox" name="CanRemove" checked /></td></tr>');
|
||||
$record.attr('data-subjectid', subject.Id);
|
||||
$record.find('span').text(subject.Name + ' ' + subject.Id);
|
||||
$record.find('i.type').addClass(subject.Type === 'role' ? 'fa-lock' : subject.IsGroup ? 'fa-users' : 'fa-user');
|
||||
$record.find('input').val(subject.Id);
|
||||
$tbody.append($record);
|
||||
$input.val('');
|
||||
$input.focus();
|
||||
});
|
||||
|
||||
const $records = $tbody.find('tr');
|
||||
for (var i = 0; i < $records.length; i++) {
|
||||
const $record = $($records[i]);
|
||||
const body = new FormData();
|
||||
body.append('id', $record.attr('data-subjectid'));
|
||||
const response = await fetch($add.attr('data-subjecturl'), {
|
||||
body: body,
|
||||
method: 'POST'
|
||||
});
|
||||
if (response.ok) {
|
||||
const subject = await response.json();
|
||||
if (subject) {
|
||||
$record.find('span').text(subject.Name + ' ' + subject.Id);
|
||||
$record.find('i.type').addClass(subject.Type === 'role' ? 'fa-lock' : subject.IsGroup ? 'fa-users' : 'fa-user');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$record.remove();
|
||||
}
|
||||
originalInherit = $inherit.prop('checked');
|
||||
originalSubjects = $tbody.html();
|
||||
$dialog.dialog('open');
|
||||
} else {
|
||||
$dialog.dialog('open');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
<div class="info-box">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-fw fa-info-circle"></i> Flag actions are normally authorized globally by
|
||||
@if (Authorization.Has(Claims.DiscoAdminAccount))
|
||||
{
|
||||
<span><a href="@Url.Action(MVC.Config.AuthorizationRole.Index(null))">Authorization Roles</a>.</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Authorization Roles.</span>
|
||||
}
|
||||
Overriding individual flag permissions allows for targeted authorization.
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>
|
||||
On Assignment<br />Expression:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -15,6 +15,7 @@
|
||||
var canExportAll = Model.TotalAssignmentCount > 0 && Authorization.Has(Claims.Config.UserFlag.Export);
|
||||
|
||||
var hideAdvanced =
|
||||
Model.Permission.IsDefault() &&
|
||||
Model.UserFlag.UserDevicesLinkedGroup == null &&
|
||||
Model.UserFlag.UsersLinkedGroup == null &&
|
||||
Model.UserFlag.OnAssignmentExpression == null &&
|
||||
@@ -229,6 +230,340 @@
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>
|
||||
Assignment Permission<br />
|
||||
Override:
|
||||
</th>
|
||||
<td>
|
||||
@if (!Model.Permission.IsDefault())
|
||||
{
|
||||
var permission = Model.Permission;
|
||||
<div>
|
||||
@if (permission.Inherit)
|
||||
{
|
||||
<span><i class="fa fa-check-square-o"></i> Inheriting from Authorization Roles</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span><i class="fa fa-square-o"></i> Authorization Roles are Ignored</span>
|
||||
}
|
||||
</div>
|
||||
if (!permission.HasSubjects())
|
||||
{
|
||||
<span class="smallMessage">There are no users/groups associated with this permission override</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
if (permission.IsSimple())
|
||||
{
|
||||
<table class="tableData">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Users/Groups/Roles</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var subjectId in permission.CanShowSubjectIds)
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
@{
|
||||
int roleId;
|
||||
if (subjectId.StartsWith("[") && int.TryParse(subjectId.Trim('[', ']'), out roleId))
|
||||
{
|
||||
<span>@Disco.Services.Users.UserService.GetAuthorizationRoleName(roleId) @subjectId</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@subjectId</span>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="info-box">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-fw fa-info-circle"></i> All users/groups/roles can view, assign, edit assignments, and remove assignments for this flag.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
var subjects = permission.AllSubjects();
|
||||
<table class="tableData">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Users/Groups/Roles</th>
|
||||
<th>View</th>
|
||||
<th>Assign</th>
|
||||
<th>Edit</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach (var subjectId in subjects.OrderBy(s => s))
|
||||
{
|
||||
<tr>
|
||||
<td>
|
||||
<i class="fa"></i> @{
|
||||
int roleId;
|
||||
if (subjectId.StartsWith("[") && int.TryParse(subjectId.Trim('[', ']'), out roleId))
|
||||
{
|
||||
<span>@Disco.Services.Users.UserService.GetAuthorizationRoleName(roleId) @subjectId</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>@subjectId</span>
|
||||
}
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanShowSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanAssignSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanEditSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
<td>
|
||||
@if (permission.CanRemoveSubjectIds.Contains(subjectId))
|
||||
{
|
||||
<i class="fa fa-fw fa-check"></i>
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@if (canConfig)
|
||||
{
|
||||
var permission = Model.Permission;
|
||||
<button id="Config_Flag_Permission_Edit" class="button small">@(permission.IsDefault() ? "Override" : "Edit") Permission</button>
|
||||
|
||||
<div id="Config_Flag_Permissions" class="dialog" title="Flag Assignment Permission Override">
|
||||
@using (Html.BeginForm(MVC.API.UserFlag.Permission(Model.UserFlag.Id)))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<input type="hidden" name="IsOverride" value="true" />
|
||||
<div id="Config_Flag_Permissions_Inherit_Container">
|
||||
<label>
|
||||
<input id="Config_Flag_Permissions_Inherit" type="checkbox" name="Inherit" value="true" @(permission.Inherit ? "checked" : null) /> Inherit Authorization from Authorization Roles
|
||||
</label>
|
||||
</div>
|
||||
<div class="tableDataContainer">
|
||||
<table class="tableData">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>User/Group/Role</th>
|
||||
<th>View</th>
|
||||
<th>Assign</th>
|
||||
<th>Edit</th>
|
||||
<th>Remove</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@{
|
||||
var subjects = permission.AllSubjects();
|
||||
|
||||
foreach (var subjectId in subjects.OrderBy(s => s))
|
||||
{
|
||||
<tr data-subjectid="@subjectId">
|
||||
<td><i class="fa type"></i> <span>@subjectId</span><i class="fa fa-times-circle remove"></i></td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanShow" value="@subjectId" @(permission.CanShowSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanAssign" value="@subjectId" @(permission.CanAssignSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanEdit" value="@subjectId" @(permission.CanEditSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
<td>
|
||||
<input type="checkbox" name="CanRemove" value="@subjectId" @(permission.CanRemoveSubjectIds.Contains(subjectId) ? " checked" : null) />
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div>
|
||||
<input type="text" id="Config_Flag_Permissions_Subject_Input" placeholder="Search Users/Groups" data-autocompleteurl="@(Url.Action(MVC.API.System.SearchSubjects(null, includeAuthorizationRoles: true)))" />
|
||||
<button type="button" id="Config_Flag_Permissions_Subject_Add" class="button small" data-subjecturl="@Url.Action(MVC.API.System.Subject(null, includeAuthorizationRoles: true))">Add</button>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<script>
|
||||
$(function () {
|
||||
let $dialog = null;
|
||||
let originalSubjects = null;
|
||||
let originalInherit = null;
|
||||
$('#Config_Flag_Permission_Edit').on('click', async function () {
|
||||
if (!$dialog) {
|
||||
$dialog = $('#Config_Flag_Permissions');
|
||||
const $tbody = $dialog.find('tbody');
|
||||
const $inherit = $dialog.find('#Config_Flag_Permissions_Inherit');
|
||||
const $input = $dialog.find('#Config_Flag_Permissions_Subject_Input');
|
||||
const $add = $dialog.find('#Config_Flag_Permissions_Subject_Add');
|
||||
|
||||
$dialog.dialog({
|
||||
resizable: false,
|
||||
modal: true,
|
||||
autoOpen: false,
|
||||
width: 550,
|
||||
height: 420,
|
||||
buttons: {
|
||||
Cancel: function () {
|
||||
$(this).dialog('close');
|
||||
$tbody.html(originalSubjects);
|
||||
$inherit.prop('checked', originalInherit);
|
||||
},
|
||||
'Remove Override': function () {
|
||||
const $this = $(this);
|
||||
$(this).dialog('option', 'buttons', null);
|
||||
$this.find('input[name="IsOverride"]').val('false');
|
||||
$this.find('form').trigger('submit');
|
||||
},
|
||||
'Save Changes': function () {
|
||||
$(this).dialog('option', 'buttons', null);
|
||||
$(this).find('form').trigger('submit');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$tbody.on('click', 'i.remove', function () {
|
||||
$(this).closest('tr').remove();
|
||||
});
|
||||
|
||||
$input
|
||||
.autocomplete({
|
||||
source: $input.attr('data-autocompleteurl'),
|
||||
minLength: 2,
|
||||
focus: function (e, ui) {
|
||||
$input.val(ui.item.Id);
|
||||
return false;
|
||||
},
|
||||
select: function (e, ui) {
|
||||
$input.val(ui.item.Id).blur();
|
||||
$add.trigger('click');
|
||||
$input.val('');
|
||||
return false;
|
||||
}
|
||||
}).data('ui-autocomplete')._renderItem = function (ul, item) {
|
||||
return $("<li></li>")
|
||||
.data('item.autocomplete', item)
|
||||
.append('<a><strong>' + item.Name + '</strong><br>' + item.Id + ' (' + item.Type + ')</a>')
|
||||
.appendTo(ul);
|
||||
};
|
||||
|
||||
$add.on('click', async function () {
|
||||
const value = $input.val();
|
||||
if (!value) {
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
const existing = $tbody.find('tr').filter(function () {
|
||||
return $(this).attr('data-subjectid') === value;
|
||||
});
|
||||
if (existing.length !== 0) {
|
||||
$input.val('');
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const body = new FormData();
|
||||
body.append('id', value);
|
||||
const response = await fetch($add.attr('data-subjecturl'), {
|
||||
body: body,
|
||||
method: 'POST'
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
alert('Unable to lookup User/Group/Role: ' + response.statusText);
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const subject = await response.json();
|
||||
|
||||
if (!subject) {
|
||||
alert('Invalid User/Group');
|
||||
$input.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
const $record = $('<tr><td><i class="fa type"></i> <span></span><i class="fa fa-times-circle remove"></i></td><td><input type="checkbox" name="CanShow" checked /></td><td><input type="checkbox" name="CanAssign" checked /></td><td><input type="checkbox" name="CanEdit" checked /></td><td><input type="checkbox" name="CanRemove" checked /></td></tr>');
|
||||
$record.attr('data-subjectid', subject.Id);
|
||||
$record.find('span').text(subject.Name + ' ' + subject.Id);
|
||||
$record.find('i.type').addClass(subject.Type === 'role' ? 'fa-lock' : subject.IsGroup ? 'fa-users' : 'fa-user');
|
||||
$record.find('input').val(subject.Id);
|
||||
$tbody.append($record);
|
||||
$input.val('');
|
||||
$input.focus();
|
||||
});
|
||||
|
||||
const $records = $tbody.find('tr');
|
||||
for (var i = 0; i < $records.length; i++) {
|
||||
const $record = $($records[i]);
|
||||
const body = new FormData();
|
||||
body.append('id', $record.attr('data-subjectid'));
|
||||
const response = await fetch($add.attr('data-subjecturl'), {
|
||||
body: body,
|
||||
method: 'POST'
|
||||
});
|
||||
if (response.ok) {
|
||||
const subject = await response.json();
|
||||
if (subject) {
|
||||
$record.find('span').text(subject.Name + ' ' + subject.Id);
|
||||
$record.find('i.type').addClass(subject.Type === 'role' ? 'fa-lock' : subject.IsGroup ? 'fa-users' : 'fa-user');
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$record.remove();
|
||||
}
|
||||
originalInherit = $inherit.prop('checked');
|
||||
originalSubjects = $tbody.html();
|
||||
$dialog.dialog('open');
|
||||
} else {
|
||||
$dialog.dialog('open');
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
}
|
||||
<div class="info-box">
|
||||
<p class="fa-p">
|
||||
<i class="fa fa-fw fa-info-circle"></i> Flag actions are normally authorized globally by
|
||||
@if (Authorization.Has(Claims.DiscoAdminAccount))
|
||||
{
|
||||
<span><a href="@Url.Action(MVC.Config.AuthorizationRole.Index(null))">Authorization Roles</a>.</span>
|
||||
}
|
||||
else
|
||||
{
|
||||
<span>Authorization Roles.</span>
|
||||
}
|
||||
Overriding individual flag permissions allows for targeted authorization.
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>
|
||||
On Assignment<br />Expression:
|
||||
@@ -369,7 +704,6 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="Config_HideAdvanced_Item">
|
||||
<th>
|
||||
Linked Groups:
|
||||
@@ -605,4 +939,4 @@
|
||||
@Html.ActionLinkButton(string.Format("Show {0} user{1}", Model.CurrentAssignmentCount, (Model.CurrentAssignmentCount == 1 ? null : "s")), MVC.Search.Query(Model.UserFlag.Id.ToString(), "UserFlag"), "Config_UserFlags_Actions_ShowUsers_Button")
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user