summaryrefslogtreecommitdiff
path: root/Pages
diff options
context:
space:
mode:
Diffstat (limited to 'Pages')
-rw-r--r--Pages/Component/AclActionSwitch.razor20
-rw-r--r--Pages/Component/AclActionSwitch.razor.css48
-rw-r--r--Pages/Component/AclDialog.razor95
-rw-r--r--Pages/Component/AclDialog.razor.css32
-rw-r--r--Pages/Component/Titlebar.razor2
-rw-r--r--Pages/ViewMedia.razor4
6 files changed, 195 insertions, 6 deletions
diff --git a/Pages/Component/AclActionSwitch.razor b/Pages/Component/AclActionSwitch.razor
new file mode 100644
index 0000000..8bc61d2
--- /dev/null
+++ b/Pages/Component/AclActionSwitch.razor
@@ -0,0 +1,20 @@
+<label>
+ <input
+ type="checkbox"
+ checked=@InitialValue
+ @onchange=@(e => OnToggle.InvokeAsync((e.Value as bool?) ?? false))
+ hidden>
+ <div class="outer">
+ <p>Deny</p>
+ <p>Allow</p>
+ <div class="inner"/>
+ </div>
+</label>
+
+@code {
+ [Parameter]
+ public bool InitialValue { get; set; } = false;
+
+ [Parameter]
+ public EventCallback<bool> OnToggle { get; set; }
+} \ No newline at end of file
diff --git a/Pages/Component/AclActionSwitch.razor.css b/Pages/Component/AclActionSwitch.razor.css
new file mode 100644
index 0000000..e9de5a2
--- /dev/null
+++ b/Pages/Component/AclActionSwitch.razor.css
@@ -0,0 +1,48 @@
+div.outer {
+ align-items: center;
+ border-radius: 10px;
+ border: 1px solid var(--color-aclaction-deny);
+ cursor: pointer;
+ display: flex;
+ flex-direction: row;
+ height: 20px;
+ position: relative;
+ transition: border-color 0.1s linear;
+ user-select: none;
+ width: min-content;
+}
+
+div.inner {
+ background: var(--color-aclaction-deny);
+ border-radius: 8px;
+ height: calc(100% - 2px);
+ left: 1px;
+ position: absolute;
+ top: 1px;
+ transition: left 0.1s linear, background 0.1s linear;
+ width: calc(50% - 2px);
+ z-index: 1;
+}
+
+div.outer p {
+ color: white;
+ font-family: 'Trebuchet MS';
+ font-size: 8pt;
+ text-align: center;
+ transition: color 0.1s linear;
+ width: 50px;
+ z-index: 2;
+}
+
+input:checked + div.outer {
+ border-color: var(--color-aclaction-allow);
+}
+
+input:checked + div.outer > div.inner {
+ background: var(--color-aclaction-allow);
+ left: calc(50% + 1px);
+}
+
+input:checked + div.outer p:nth-child(2) {
+ color: black;
+} \ No newline at end of file
diff --git a/Pages/Component/AclDialog.razor b/Pages/Component/AclDialog.razor
index 33d1f03..8116f04 100644
--- a/Pages/Component/AclDialog.razor
+++ b/Pages/Component/AclDialog.razor
@@ -1,19 +1,104 @@
-@implements IDialog
+@using System.Numerics;
+@inject IDbContextFactory<HBContext> dbFactory;
+@implements IDialog
<Dialog Title="Edit permissions" @ref=dialog>
+ @if(obj?.Acl is not null) {
+ <table class="data-table">
+ <tr>
+ <th>Action</th>
+ <th>Subject</th>
+ <th>Permissions</th>
+ <th></th>
+ </tr>
+ @foreach(var rule in obj.Acl.Rules.OrderByDescending(r => r.Action)) {
+ <tr>
+ <td><div><AclActionSwitch InitialValue=@(rule.Action == AclRuleAction.Allow)/></div></td>
+ <td>@rule.Principal.ToString()</td>
+ <td>@GetActivePermissions(rule)</td>
+ <td>
+ <a title="Edit" href="javascript:;">&#x1F589</a>
+ <a title="Delete" href="javascript:;">&#x2716</a>
+ </td>
+ </tr>
+ }
+ </table>
+ <br/>
+ <center><a href="javascript:;">Add new</a></center>
+ <ButtonContainer>
+ <button class="secondary" @onclick=Hide>Cancel</button>
+ <button data-keyboard-shortcut="a" @onclick=Hide><u>A</u>pply</button>
+ </ButtonContainer>
+ } else {
+ <center><i>This item does not have any permissions set!</i></center>
+ <ButtonContainer>
+ <button class="secondary" @onclick=Hide>Cancel</button>
+ </ButtonContainer>
+ }
</Dialog>
@code {
- [Parameter]
- public HBObject Object { get; set; }
-
public bool Visible {
get => dialog.Visible;
- set => dialog.Visible = value;
+ set {
+ dialog.Visible = value;
+ if(value)
+ StateHasChanged();
+ }
}
+ private HBObject? obj;
+
private Dialog dialog;
public void Show() => Visible = true;
public void Hide() => Visible = false;
+
+ public void Show(HBObject obj) {
+ Object = obj;
+ Show();
+ }
+
+ public HBObject? Object {
+ get => obj;
+ set {
+ if(value is null) {
+ obj = null;
+ return;
+ }
+
+ using var db = dbFactory.CreateDbContext();
+
+ obj = db.Objects
+ .Include(o => o.Acl)
+ .First(o => o.ObjectId == value.ObjectId);
+
+ if(obj.Acl is not null)
+ db.Entry(obj.Acl).Collection(a => a.Rules).Load();
+ }
+ }
+
+ public string GetActivePermissions(AclRule rule) {
+ var perms = Acl.GetPermissionDescriptions(obj!)
+ .Where(kv => (rule.Permissions & kv.Value) == kv.Value)
+ .ToList();
+
+ // Filter the list of matching permissions to include the
+ // most relevant encapsulation permissions only. E.g. if
+ // 'Full access' includes 'Read' and 'Write', then only
+ // show 'Full access'.
+ List<int> toRemove = new();
+ for(int i = 0; i < perms.Count(); i++)
+ for(int j = 0; j < perms.Count(); j++)
+ if(i != j)
+ if((perms[i].Value & perms[j].Value) == perms[i].Value)
+ toRemove.Add(i);
+ for(int i = toRemove.Count() - 1; i >= 0; i--)
+ perms.RemoveAt(toRemove[i]);
+
+ return string.Join(", ", perms
+ .OrderByDescending(kv => BitOperations.PopCount(kv.Value))
+ .ThenByDescending(kv => kv.Value)
+ .Select(kv => kv.Key));
+ }
} \ No newline at end of file
diff --git a/Pages/Component/AclDialog.razor.css b/Pages/Component/AclDialog.razor.css
new file mode 100644
index 0000000..f1b7931
--- /dev/null
+++ b/Pages/Component/AclDialog.razor.css
@@ -0,0 +1,32 @@
+table p {
+ margin: 8px 0 8px 0;
+}
+
+table tr {
+ background: none !important;
+}
+
+table td {
+ font-family: 'Lucida Console';
+ font-size: 8pt;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+table td:last-child {
+ font-size: 12pt;
+}
+
+table tr:nth-child(2n+1) td:not(:first-child) {
+ background: rgba(255, 255, 255, 0.1);
+}
+
+table td:nth-child(2n) {
+ white-space: nowrap;
+ width: 1px;
+}
+
+table td > div {
+ margin: auto;
+ width: min-content;
+} \ No newline at end of file
diff --git a/Pages/Component/Titlebar.razor b/Pages/Component/Titlebar.razor
index ad41532..766787a 100644
--- a/Pages/Component/Titlebar.razor
+++ b/Pages/Component/Titlebar.razor
@@ -74,5 +74,5 @@
private AboutDialog aboutDialog;
- private string username => AuthState.GetAwaiter().GetResult().User.Identity?.Name ?? "fugg";
+ private string username => AuthState.GetAwaiter().GetResult().User.Identity?.Name!;
}
diff --git a/Pages/ViewMedia.razor b/Pages/ViewMedia.razor
index 444fbc5..05cf700 100644
--- a/Pages/ViewMedia.razor
+++ b/Pages/ViewMedia.razor
@@ -84,6 +84,7 @@
<div id="button-container">
<ButtonContainer>
<button @onclick=@(() => deleteDialog.Show()) class="warning" data-keyboard-shortcut="d"><u>D</u>elete</button>
+ <button @onclick=@(() => aclDialog.Show(media)) class="secondary" data-keyboard-shortcut="p">Edit <u>P</u>ermissions</button>
<button @onclick=@(() => tagDialog.Show()) class="secondary" data-keyboard-shortcut="t">Add <u>T</u>ag</button>
<button @onclick=@(() => ocrDialog.Show()) class="secondary" data-keyboard-shortcut="o">View <u>O</u>CR</button>
@if(infoEditMode) {
@@ -125,6 +126,8 @@
OnSubmit=AddTags
@ref=tagDialog/>
+<AclDialog @ref=aclDialog/>
+
@code {
[Parameter]
[SupplyParameterFromQuery(Name = "m")]
@@ -142,6 +145,7 @@
private Dialog deleteDialog;
private Dialog ocrDialog;
private TagSelectDialog tagDialog;
+ private AclDialog aclDialog;
private ElementReference shortDescriptionInput;