feature: flag permissions

feature: flag permissions
This commit is contained in:
Gary Sharp committed 2025-07-31 19:03:33 +10:00
1 parent 7deead494b
commit be7ee4cae8
72 files changed
+5521 -2040

No files matched your search

+7
View File
@@ -197,6 +197,10 @@
<Compile Include="Migrations\202507110430252_DBv27.Designer.cs">
<DependentUpon>202507110430252_DBv27.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\202507170522576_DBv28.cs" />
<Compile Include="Migrations\202507170522576_DBv28.Designer.cs">
<DependentUpon>202507170522576_DBv28.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" />
<Compile Include="Migrations\DiscoDataMigrator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@@ -293,6 +297,9 @@
<EmbeddedResource Include="Migrations\202507110430252_DBv27.resx">
<DependentUpon>202507110430252_DBv27.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Migrations\202507170522576_DBv28.resx">
<DependentUpon>202507170522576_DBv28.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
+27
View File
@@ -0,0 +1,27 @@
// <auto-generated />
namespace Disco.Data.Migrations
{
using System.Data.Entity.Migrations;
using System.Data.Entity.Migrations.Infrastructure;
using System.Resources;
public sealed partial class DBv28 : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(DBv28));
string IMigrationMetadata.Id
{
get { return "202507170522576_DBv28"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}
@@ -0,0 +1,40 @@
namespace Disco.Data.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class DBv28 : DbMigration
{
public override void Up()
{
AddColumn("dbo.UserFlagAssignments", "RemoveDate", c => c.DateTime());
AddColumn("dbo.UserFlagAssignments", "RemoveUserId", c => c.String(maxLength: 50));
AddColumn("dbo.UserFlags", "Permissions", c => c.String());
AddColumn("dbo.UserFlags", "DefaultRemoveDays", c => c.Int());
AddColumn("dbo.DeviceFlagAssignments", "RemoveDate", c => c.DateTime());
AddColumn("dbo.DeviceFlagAssignments", "RemoveUserId", c => c.String(maxLength: 50));
AddColumn("dbo.DeviceFlags", "Permissions", c => c.String());
AddColumn("dbo.DeviceFlags", "DefaultRemoveDays", c => c.Int());
AddForeignKey("dbo.UserFlagAssignments", "RemoveUserId", "dbo.Users", "Id");
AddForeignKey("dbo.DeviceFlagAssignments", "RemoveUserId", "dbo.Users", "Id");
CreateIndex("dbo.UserFlagAssignments", "RemoveUserId");
CreateIndex("dbo.DeviceFlagAssignments", "RemoveUserId");
}
public override void Down()
{
DropIndex("dbo.DeviceFlagAssignments", new[] { "RemoveUserId" });
DropIndex("dbo.UserFlagAssignments", new[] { "RemoveUserId" });
DropForeignKey("dbo.DeviceFlagAssignments", "RemoveUserId", "dbo.Users");
DropForeignKey("dbo.UserFlagAssignments", "RemoveUserId", "dbo.Users");
DropColumn("dbo.DeviceFlags", "DefaultRemoveDays");
DropColumn("dbo.DeviceFlags", "Permissions");
DropColumn("dbo.DeviceFlagAssignments", "RemoveUserId");
DropColumn("dbo.DeviceFlagAssignments", "RemoveDate");
DropColumn("dbo.UserFlags", "DefaultRemoveDays");
DropColumn("dbo.UserFlags", "Permissions");
DropColumn("dbo.UserFlagAssignments", "RemoveUserId");
DropColumn("dbo.UserFlagAssignments", "RemoveDate");
}
}
}
@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="Target" xml:space="preserve">
<value>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 truncated
</data>
</root>
+2
View File
@@ -59,7 +59,9 @@
<Compile Include="Repository\Device\Flag\DeviceFlag.cs" />
<Compile Include="Repository\Device\Flag\DeviceFlagAssignment.cs" />
<Compile Include="Repository\Device\DeviceComment.cs" />
<Compile Include="Repository\FlagType.cs" />
<Compile Include="Repository\User\UserComment.cs" />
<Compile Include="Repository\FlagPermission.cs" />
<Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportOptions.cs" />
<Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportRecord.cs" />
<Compile Include="Services\Documents\DocumentExportOptions.cs" />
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using Disco.Models.Services.Authorization;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Models.Repository
{
@@ -27,11 +29,20 @@ namespace Disco.Models.Repository
[DataType(DataType.MultilineText)]
public string OnUnassignmentExpression { get; set; }
[Column("Permissions")]
public string PermissionsJson { get; set; }
[NotMapped]
public FlagPermission Permissions
{
get => FlagPermission.FromFlag(this);
set => PermissionsJson = value?.ToJson();
}
public int? DefaultRemoveDays { get; set; }
public virtual IList<DeviceFlagAssignment> DeviceFlagAssignments { get; set; }
public override string ToString()
{
return Name;
}
=> Name;
}
}
@@ -19,26 +19,28 @@ namespace Disco.Models.Repository
public string AddedUserId { get; set; }
public DateTime? RemovedDate { get; set; }
public string RemovedUserId { get; set; }
public DateTime? RemoveDate { get; set; }
public string RemoveUserId { get; set; }
public string Comments { get; set; }
public string OnAssignmentExpressionResult { get; set; }
public string OnUnassignmentExpressionResult { get; set; }
[ForeignKey(nameof(DeviceFlagId)), InverseProperty("DeviceFlagAssignments")]
[ForeignKey(nameof(DeviceFlagId)), InverseProperty(nameof(Repository.DeviceFlag.DeviceFlagAssignments))]
public virtual DeviceFlag DeviceFlag { get; set; }
[ForeignKey(nameof(DeviceSerialNumber)), InverseProperty("DeviceFlagAssignments")]
[ForeignKey(nameof(DeviceSerialNumber)), InverseProperty(nameof(Repository.Device.DeviceFlagAssignments))]
public virtual Device Device { get; set; }
[ForeignKey("AddedUserId")]
[ForeignKey(nameof(AddedUserId))]
public virtual User AddedUser { get; set; }
[ForeignKey("RemovedUserId")]
[ForeignKey(nameof(RemovedUserId))]
public virtual User RemovedUser { get; set; }
[ForeignKey(nameof(RemoveUserId))]
public virtual User RemoveUser { get; set; }
public override string ToString()
{
return $"Device Flag Id: {DeviceFlagId}; Device Serial Number: {DeviceSerialNumber}; Added: {AddedDate:s}";
}
=> $"Device Flag Id: {DeviceFlagId}; Device Serial Number: {DeviceSerialNumber}; Added: {AddedDate:s}";
}
}
+121
View File
@@ -0,0 +1,121 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
namespace Disco.Models.Repository
{
public class FlagPermission
{
private static readonly FlagPermission DefaultDeviceFlagPermissions = new FlagPermission(FlagType.Device, 0);
private static readonly FlagPermission DefaultUserFlagPermissions = new FlagPermission(FlagType.User, 0);
[JsonIgnore]
public FlagType FlagType { get; }
[JsonIgnore]
public int FlagId { get; }
public bool Inherit { get; set; }
public HashSet<string> CanShowSubjectIds { get; }
public HashSet<string> CanAssignSubjectIds { get; }
public HashSet<string> CanEditSubjectIds { get; }
public HashSet<string> CanRemoveSubjectIds { get; }
private FlagPermission(FlagType flagType, int flagId)
{
FlagType = flagType;
FlagId = flagId;
Inherit = true;
CanShowSubjectIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
CanAssignSubjectIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
CanEditSubjectIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
CanRemoveSubjectIds = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
}
public bool IsDefault()
{
return ReferenceEquals(this, DefaultDeviceFlagPermissions) ||
ReferenceEquals(this, DefaultUserFlagPermissions);
}
public bool IsSimple()
{
return CanShowSubjectIds.SetEquals(CanAssignSubjectIds) &&
CanAssignSubjectIds.SetEquals(CanEditSubjectIds) &&
CanEditSubjectIds.SetEquals(CanRemoveSubjectIds);
}
public bool HasSubjects()
{
return CanShowSubjectIds.Count > 0 ||
CanAssignSubjectIds.Count > 0 ||
CanEditSubjectIds.Count > 0 ||
CanRemoveSubjectIds.Count > 0;
}
public HashSet<string> AllSubjects()
{
var allSubjects = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
allSubjects.UnionWith(CanShowSubjectIds);
allSubjects.UnionWith(CanAssignSubjectIds);
allSubjects.UnionWith(CanEditSubjectIds);
allSubjects.UnionWith(CanRemoveSubjectIds);
return allSubjects;
}
public static FlagPermission FromFlag(UserFlag userFlag)
{
if (userFlag.PermissionsJson == null)
return DefaultUserFlagPermissions;
var permission = new FlagPermission(FlagType.User, userFlag.Id);
JsonConvert.PopulateObject(userFlag.PermissionsJson, permission);
return permission;
}
public static FlagPermission FromFlag(DeviceFlag deviceFlag)
{
if (deviceFlag.PermissionsJson == null)
return DefaultDeviceFlagPermissions;
var permission = new FlagPermission(FlagType.Device, deviceFlag.Id);
JsonConvert.PopulateObject(deviceFlag.PermissionsJson, permission);
return permission;
}
public static FlagPermission Create(UserFlag userFlag, bool inherit, IEnumerable<string> canShow, IEnumerable<string> canAssign, IEnumerable<string> canEdit, IEnumerable<string> canRemove)
{
var permission = new FlagPermission(FlagType.User, userFlag.Id);
return Create(permission, inherit, canShow, canAssign, canEdit, canRemove);
}
public static FlagPermission Create(DeviceFlag deviceFlag, bool inherit, IEnumerable<string> canShow, IEnumerable<string> canAssign, IEnumerable<string> canEdit, IEnumerable<string> canRemove)
{
var permission = new FlagPermission(FlagType.Device, deviceFlag.Id);
return Create(permission, inherit, canShow, canAssign, canEdit, canRemove);
}
private static FlagPermission Create(FlagPermission permission, bool inherit, IEnumerable<string> canShow, IEnumerable<string> canAssign, IEnumerable<string> canEdit, IEnumerable<string> canRemove)
{
permission.Inherit = inherit;
if (canShow != null)
permission.CanShowSubjectIds.UnionWith(canShow);
if (canAssign != null)
permission.CanAssignSubjectIds.UnionWith(canAssign);
if (canEdit != null)
permission.CanEditSubjectIds.UnionWith(canEdit);
if (canRemove != null)
permission.CanRemoveSubjectIds.UnionWith(canRemove);
return permission;
}
public string ToJson()
{
if (IsDefault())
return null;
return JsonConvert.SerializeObject(this);
}
}
}
+8
View File
@@ -0,0 +1,8 @@
namespace Disco.Models.Repository
{
public enum FlagType
{
User = 1,
Device = 2,
}
}
+15 -4
View File
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using Disco.Models.Services.Authorization;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Models.Repository
{
@@ -27,11 +29,20 @@ namespace Disco.Models.Repository
[DataType(DataType.MultilineText)]
public string OnUnassignmentExpression { get; set; }
[Column("Permissions")]
public string PermissionsJson { get; set; }
[NotMapped]
public FlagPermission Permissions
{
get => FlagPermission.FromFlag(this);
set => PermissionsJson = value?.ToJson();
}
public int? DefaultRemoveDays { get; set; }
public virtual IList<UserFlagAssignment> UserFlagAssignments { get; set; }
public override string ToString()
{
return Name;
}
=> Name;
}
}
@@ -19,26 +19,28 @@ namespace Disco.Models.Repository
public string AddedUserId { get; set; }
public DateTime? RemovedDate { get; set; }
public string RemovedUserId { get; set; }
public DateTime? RemoveDate { get; set; }
public string RemoveUserId { get; set; }
public string Comments { get; set; }
public string OnAssignmentExpressionResult { get; set; }
public string OnUnassignmentExpressionResult { get; set; }
[ForeignKey("UserFlagId"), InverseProperty("UserFlagAssignments")]
[ForeignKey(nameof(UserFlagId)), InverseProperty(nameof(Repository.UserFlag.UserFlagAssignments))]
public virtual UserFlag UserFlag { get; set; }
[ForeignKey("UserId"), InverseProperty("UserFlagAssignments")]
[ForeignKey(nameof(UserId)), InverseProperty(nameof(Repository.User.UserFlagAssignments))]
public virtual User User { get; set; }
[ForeignKey("AddedUserId")]
[ForeignKey(nameof(AddedUserId))]
public virtual User AddedUser { get; set; }
[ForeignKey("RemovedUserId")]
[ForeignKey(nameof(RemovedUserId))]
public virtual User RemovedUser { get; set; }
[ForeignKey(nameof(RemoveUserId))]
public virtual User RemoveUser { get; set; }
public override string ToString()
{
return $"User Flag Id: {UserFlagId}; User Id: {UserId}; Added: {AddedDate:s}";
}
=> $"User Flag Id: {UserFlagId}; User Id: {UserId}; Added: {AddedDate:s}";
}
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Disco.Models.Repository;
using System.Collections.Generic;
namespace Disco.Models.UI.Config.DeviceFlag
{
@@ -11,5 +12,7 @@ namespace Disco.Models.UI.Config.DeviceFlag
IEnumerable<KeyValuePair<string, string>> Icons { get; set; }
IEnumerable<KeyValuePair<string, string>> ThemeColours { get; set; }
FlagPermission Permission { get; set; }
}
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Disco.Models.Repository;
using System.Collections.Generic;
namespace Disco.Models.UI.Config.UserFlag
{
@@ -11,5 +12,7 @@ namespace Disco.Models.UI.Config.UserFlag
IEnumerable<KeyValuePair<string, string>> Icons { get; set; }
IEnumerable<KeyValuePair<string, string>> ThemeColours { get; set; }
FlagPermission Permission { get; set; }
}
}
+24 -16
View File
@@ -18,7 +18,7 @@ namespace Disco.Services.Authorization
static Claims()
{
#region Role Claim Dictionary
#region Role Claim Dictionary
_roleClaims = new Dictionary<string, Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>>()
{
{ "Config.DeviceCertificate.DownloadCertificates", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Config.DeviceCertificate.DownloadCertificates, (c, v) => c.Config.DeviceCertificate.DownloadCertificates = v, "Download Certificates", "Can download certificates", false) },
@@ -242,9 +242,9 @@ namespace Disco.Services.Authorization
{ "ComputerAccount", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.ComputerAccount, (c, v) => c.ComputerAccount = v, "Computer Account", "Represents a computer account", true) },
{ "DiscoAdminAccount", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.DiscoAdminAccount, (c, v) => c.DiscoAdminAccount = v, "Disco Administrator Account", "Represents a Disco ICT Administrator account", true) }
};
#endregion
#endregion
#region Role Claim Navigator
#region Role Claim Navigator
_claimNavigator =
new ClaimNavigatorItem("Claims", "Permissions", "Top-level node for all permissions", false, new List<IClaimNavigatorItem>() {
new ClaimNavigatorItem("Config", "Configuration", "Permissions related to Disco ICT Configuration", false, new List<IClaimNavigatorItem>() {
@@ -524,7 +524,7 @@ namespace Disco.Services.Authorization
new ClaimNavigatorItem("ComputerAccount", true),
new ClaimNavigatorItem("DiscoAdminAccount", true)
});
#endregion
#endregion
}
public static ClaimNavigatorItem RoleClaimNavigator
@@ -532,31 +532,36 @@ namespace Disco.Services.Authorization
get { return _claimNavigator; }
}
internal static Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool> GetClaimDefinition(string ClaimKey) {
internal static Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool> GetClaimDefinition(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return claimDef;
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
}
public static Func<RoleClaims, bool> GetClaimAccessor(string ClaimKey) {
public static Func<RoleClaims, bool> GetClaimAccessor(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return claimDef.Item1;
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
}
public static Action<RoleClaims, bool> GetClaimSetter(string ClaimKey) {
public static Action<RoleClaims, bool> GetClaimSetter(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return claimDef.Item2;
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
}
public static Tuple<string, string, bool> GetClaimDetails(string ClaimKey) {
public static Tuple<string, string, bool> GetClaimDetails(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return Tuple.Create(claimDef.Item3, claimDef.Item4, claimDef.Item5);
throw new ArgumentException("Unknown Claim Key", "ClaimKey");
}
public static RoleClaims BuildClaims(IEnumerable<string> ClaimKeys){
public static RoleClaims BuildClaims(IEnumerable<string> ClaimKeys)
{
var c = new RoleClaims();
foreach (var claimKey in ClaimKeys)
c.Set(claimKey, true);
@@ -570,9 +575,10 @@ namespace Disco.Services.Authorization
return _roleClaims.Where(rc => rc.Value.Item1(claims)).Select(rc => rc.Key).ToList();
}
public static RoleClaims AdministratorClaims() {
public static RoleClaims AdministratorClaims()
{
var c = new RoleClaims();
#region Set All Administrator Claims
#region Set All Administrator Claims
c.Config.DeviceCertificate.DownloadCertificates = true;
c.Config.Enrolment.Configure = true;
c.Config.Enrolment.DownloadBootstrapper = true;
@@ -792,17 +798,19 @@ namespace Disco.Services.Authorization
c.User.ShowFlagAssignments = true;
c.User.ShowJobs = true;
c.DiscoAdminAccount = true;
#endregion
#endregion
return c;
}
public static RoleClaims ComputerAccountClaims() {
return new RoleClaims() {
public static RoleClaims ComputerAccountClaims()
{
return new RoleClaims()
{
ComputerAccount = true
};
}
#region Role Claim Constants
#region Role Claim Constants
/// <summary>Configuration
/// <para>Permissions related to Disco ICT Configuration</para>
@@ -2099,7 +2107,7 @@ namespace Disco.Services.Authorization
/// <para>Represents a Disco ICT Administrator account</para>
/// </summary>
public const string DiscoAdminAccount = "DiscoAdminAccount";
#endregion
#endregion
}
public static class ClaimExtensions
{
+24 -16
View File
@@ -66,17 +66,17 @@ namespace Disco.Services.Authorization
static Claims()
{
#region Role Claim Dictionary
#region Role Claim Dictionary
_roleClaims = new Dictionary<string, Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>>()
{
<#WriteAccessHashes(permissionRoot);#>
};
#endregion
#endregion
#region Role Claim Navigator
#region Role Claim Navigator
_claimNavigator =
<#WriteNavigator(permissionRoot);#>;
#endregion
#endregion
}
public static ClaimNavigatorItem RoleClaimNavigator
@@ -84,31 +84,36 @@ namespace Disco.Services.Authorization
get { return _claimNavigator; }
}
internal static Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool> GetClaimDefinition(string ClaimKey) {
internal static Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool> GetClaimDefinition(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return claimDef;
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
}
public static Func<RoleClaims, bool> GetClaimAccessor(string ClaimKey) {
public static Func<RoleClaims, bool> GetClaimAccessor(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return claimDef.Item1;
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
}
public static Action<RoleClaims, bool> GetClaimSetter(string ClaimKey) {
public static Action<RoleClaims, bool> GetClaimSetter(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return claimDef.Item2;
throw new ArgumentException("Unknown Claim Key", nameof(ClaimKey));
}
public static Tuple<string, string, bool> GetClaimDetails(string ClaimKey) {
public static Tuple<string, string, bool> GetClaimDetails(string ClaimKey)
{
if (_roleClaims.TryGetValue(ClaimKey, out var claimDef))
return Tuple.Create(claimDef.Item3, claimDef.Item4, claimDef.Item5);
throw new ArgumentException("Unknown Claim Key", "ClaimKey");
}
public static RoleClaims BuildClaims(IEnumerable<string> ClaimKeys){
public static RoleClaims BuildClaims(IEnumerable<string> ClaimKeys)
{
var c = new RoleClaims();
foreach (var claimKey in ClaimKeys)
c.Set(claimKey, true);
@@ -122,23 +127,26 @@ namespace Disco.Services.Authorization
return _roleClaims.Where(rc => rc.Value.Item1(claims)).Select(rc => rc.Key).ToList();
}
public static RoleClaims AdministratorClaims() {
public static RoleClaims AdministratorClaims()
{
var c = new RoleClaims();
#region Set All Administrator Claims
#region Set All Administrator Claims
<#WriteAdministratorClaims(permissionRoot);#>
#endregion
#endregion
return c;
}
public static RoleClaims ComputerAccountClaims() {
return new RoleClaims() {
public static RoleClaims ComputerAccountClaims()
{
return new RoleClaims()
{
ComputerAccount = true
};
}
#region Role Claim Constants
#region Role Claim Constants
<#WritePermissionConsts(permissionRoot);#>
#endregion
#endregion
}
public static class ClaimExtensions
{
+44 -58
View File
@@ -4,6 +4,7 @@ using Disco.Models.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Newtonsoft.Json;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
@@ -16,41 +17,41 @@ namespace Disco.Services.Authorization.Roles
internal const string ClaimsJsonEmpty = "null";
internal static readonly string[] _RequiredAdministratorSubjectIds = new string[] { "Domain Admins" };
private static List<RoleToken> _Cache;
private static ConcurrentDictionary<int, RoleToken> cache;
private static RoleToken _AdministratorToken;
internal static void Initialize(DiscoDataContext Database)
internal static void Initialize(DiscoDataContext database)
{
MigrateAuthorizationRoles(Database);
MigrateAuthorizationRoles(database);
_Cache = Database.AuthorizationRoles.ToList().Select(ar => RoleToken.FromAuthorizationRole(ar)).ToList();
cache = new ConcurrentDictionary<int, RoleToken>(database.AuthorizationRoles.ToList().Select(ar => RoleToken.FromAuthorizationRole(ar)).ToDictionary(r => r.Role.Id));
// Add System Roles
AddSystemRoles(Database);
AddSystemRoles(database);
}
private static void AddSystemRoles(DiscoDataContext Database)
private static void AddSystemRoles(DiscoDataContext database)
{
// Disco Administrators
_AdministratorToken = RoleToken.FromAuthorizationRole(new AuthorizationRole()
{
Id = AdministratorsTokenId,
Name = "Disco Administrators",
SubjectIds = string.Join(",", GenerateAdministratorSubjectIds(Database))
SubjectIds = string.Join(",", GenerateAdministratorSubjectIds(database))
}, Claims.AdministratorClaims());
_Cache.Add(_AdministratorToken);
cache.TryAdd(AdministratorsTokenId, _AdministratorToken);
// Computer Accounts
_Cache.Add(RoleToken.FromAuthorizationRole(new AuthorizationRole()
cache.TryAdd(ComputerAccountTokenId, RoleToken.FromAuthorizationRole(new AuthorizationRole()
{
Id = ComputerAccountTokenId,
Name = "Domain Computer Account"
}, Claims.ComputerAccountClaims()));
}
private static IEnumerable<string> GenerateAdministratorSubjectIds(DiscoDataContext Database)
private static IEnumerable<string> GenerateAdministratorSubjectIds(DiscoDataContext database)
{
var configuredSubjectIds = Database.DiscoConfiguration.Administrators.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => ActiveDirectory.ParseDomainAccountId(s));
var configuredSubjectIds = database.DiscoConfiguration.Administrators.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(s => ActiveDirectory.ParseDomainAccountId(s));
return RequiredAdministratorSubjectIds
.Concat(configuredSubjectIds)
@@ -58,94 +59,79 @@ namespace Disco.Services.Authorization.Roles
.OrderBy(s => s);
}
public static IEnumerable<string> RequiredAdministratorSubjectIds
{
get
{
return _RequiredAdministratorSubjectIds.Select(s => ActiveDirectory.ParseDomainAccountId(s));
}
}
=> _RequiredAdministratorSubjectIds.Select(s => ActiveDirectory.ParseDomainAccountId(s));
public static IEnumerable<string> AdministratorSubjectIds
{
get
{
return _AdministratorToken.SubjectIds.ToList();
}
}
=> _AdministratorToken.SubjectIds.ToList();
public static void UpdateAdministratorSubjectIds(DiscoDataContext Database, IEnumerable<string> SubjectIds)
public static void UpdateAdministratorSubjectIds(DiscoDataContext database, IEnumerable<string> subjectIds)
{
// Clean
SubjectIds = SubjectIds
subjectIds = subjectIds
.Where(s => !string.IsNullOrWhiteSpace(s))
.Concat(RequiredAdministratorSubjectIds)
.Distinct(StringComparer.OrdinalIgnoreCase)
.OrderBy(s => s);
var subjectIdsString = string.Join(",", SubjectIds);
var subjectIdsString = string.Join(",", subjectIds);
// Update Database
Database.DiscoConfiguration.Administrators = subjectIdsString;
Database.SaveChanges();
database.DiscoConfiguration.Administrators = subjectIdsString;
database.SaveChanges();
// Update State
_AdministratorToken.SubjectIds = SubjectIds.ToList();
_AdministratorToken.SubjectIdHashes = new HashSet<string>(SubjectIds, StringComparer.OrdinalIgnoreCase);
_AdministratorToken.SubjectIds = subjectIds.ToList();
_AdministratorToken.SubjectIdHashes = new HashSet<string>(subjectIds, StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// Create a clone of an Authorization Role
/// <para>Creates immutable clones to avoid side-effects</para>
/// </summary>
/// <param name="TemplateRole">Authorization Role to Clone</param>
/// <param name="templateRole">Authorization Role to Clone</param>
/// <returns>A copy of the Authorization Role</returns>
private static AuthorizationRole CloneAuthoriationRole(AuthorizationRole TemplateRole)
private static AuthorizationRole CloneAuthoriationRole(AuthorizationRole templateRole)
{
return new AuthorizationRole()
{
Id = TemplateRole.Id,
Name = TemplateRole.Name,
ClaimsJson = TemplateRole.ClaimsJson,
SubjectIds = TemplateRole.SubjectIds
Id = templateRole.Id,
Name = templateRole.Name,
ClaimsJson = templateRole.ClaimsJson,
SubjectIds = templateRole.SubjectIds
};
}
internal static RoleToken AddRole(AuthorizationRole Role)
{
var token = RoleToken.FromAuthorizationRole(CloneAuthoriationRole(Role));
_Cache.Add(token);
return token;
}
internal static void RemoveRole(AuthorizationRole Role)
{
var token = GetRoleToken(Role.Id);
if (token != null)
_Cache.Remove(token);
cache.TryRemove(Role.Id, out _);
}
internal static RoleToken UpdateRole(AuthorizationRole Role)
internal static RoleToken AddOrUpdateRole(AuthorizationRole role)
{
RemoveRole(Role);
return AddRole(Role);
var token = RoleToken.FromAuthorizationRole(CloneAuthoriationRole(role));
cache.AddOrUpdate(token.Role.Id, token, (i, e) => token);
return token;
}
internal static RoleToken GetRoleToken(int Id)
internal static RoleToken GetRoleToken(int id)
{
return _Cache.FirstOrDefault(t => t.Role.Id == Id);
if (cache.TryGetValue(id, out var result))
return result;
else
return null;
}
internal static RoleToken GetRoleToken(string SecurityGroup)
internal static RoleToken GetRoleToken(string securityGroup)
{
return _Cache.FirstOrDefault(t => t.SubjectIdHashes.Contains(SecurityGroup));
return cache.Values.FirstOrDefault(t => t.SubjectIdHashes.Contains(securityGroup));
}
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup)
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> securityGroups)
{
return _Cache.Where(t => SecurityGroup.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
return cache.Values.Where(t => securityGroups.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
}
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> SecurityGroup, User User)
internal static List<IRoleToken> GetRoleTokens(IEnumerable<string> securityGroups, User user)
{
var subjectIds = SecurityGroup.Concat(new string[] { User.UserId });
var subjectIds = securityGroups.Concat(new string[] { user.UserId });
return _Cache.Where(t => subjectIds.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
return cache.Values.Where(t => subjectIds.Any(sg => t.SubjectIdHashes.Contains(sg))).Cast<IRoleToken>().ToList();
}
/// <summary>
+11 -17
View File
@@ -8,7 +8,7 @@ namespace Disco.Services.Devices.DeviceFlags
{
internal class Cache
{
private ConcurrentDictionary<int, DeviceFlag> _Cache;
private ConcurrentDictionary<int, (DeviceFlag, FlagPermission permission)> cache;
public Cache(DiscoDataContext Database)
{
@@ -26,36 +26,30 @@ namespace Disco.Services.Devices.DeviceFlags
var flags = Database.DeviceFlags.ToList();
// Add Queues to In-Memory Cache
_Cache = new ConcurrentDictionary<int, DeviceFlag>(flags.Select(f => new KeyValuePair<int, DeviceFlag>(f.Id, f)));
cache = new ConcurrentDictionary<int, (DeviceFlag, FlagPermission permission)>(flags.Select(f => new KeyValuePair<int, (DeviceFlag, FlagPermission permission)>(f.Id, (f, f.Permissions))));
}
public DeviceFlag GetDeviceFlag(int deviceFlagId)
public (DeviceFlag flag, FlagPermission permission) GetDeviceFlag(int deviceFlagId)
{
if (_Cache.TryGetValue(deviceFlagId, out var item))
if (cache.TryGetValue(deviceFlagId, out var item))
return item;
else
return null;
return (null, null);
}
public List<DeviceFlag> GetDeviceFlags()
public List<(DeviceFlag flag, FlagPermission permission)> GetDeviceFlags()
{
return _Cache.Values.ToList();
return cache.Values.ToList();
}
public void AddOrUpdate(DeviceFlag flag)
{
_Cache.AddOrUpdate(flag.Id, flag, (key, existingItem) => flag);
var value = (flag, flag.Permissions);
cache.AddOrUpdate(flag.Id, value, (key, existingItem) => value);
}
public DeviceFlag Remove(int deviceFlagId)
public void Remove(int deviceFlagId)
{
if (_Cache.TryRemove(deviceFlagId, out var item))
return item;
else
return null;
}
public DeviceFlag Remove(DeviceFlag deviceFlag)
{
return Remove(deviceFlag.Id);
cache.TryRemove(deviceFlagId, out _);
}
}
}
@@ -1,6 +1,7 @@
using Disco.Data.Repository;
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Devices.DeviceFlags;
using Disco.Services.Expressions;
using Disco.Services.Logging;
using Disco.Services.Users;
@@ -15,16 +16,18 @@ namespace Disco.Services
{
#region Edit Comments
public static bool CanEditComments(this DeviceFlagAssignment fa)
public static bool CanEdit(this DeviceFlagAssignment fa)
{
return UserService.CurrentAuthorization.Has(Claims.Device.Actions.EditFlags);
var (_, permission) = DeviceFlagService.GetDeviceFlag(fa.DeviceFlagId);
return permission.CanEdit();
}
public static void OnEditComments(this DeviceFlagAssignment fa, string Comments)
public static void OnEdit(this DeviceFlagAssignment fa, string comments)
{
if (!fa.CanEditComments())
if (!fa.CanEdit())
throw new InvalidOperationException("Editing comments for device flags is denied");
fa.Comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
fa.Comments = string.IsNullOrWhiteSpace(comments) ? null : comments.Trim();
}
#endregion
@@ -34,36 +37,38 @@ namespace Disco.Services
if (fa.RemovedDate.HasValue)
return false;
return UserService.CurrentAuthorization.Has(Claims.Device.Actions.RemoveFlags);
var (_, permission) = DeviceFlagService.GetDeviceFlag(fa.DeviceFlagId);
return permission.CanRemove();
}
public static void OnRemove(this DeviceFlagAssignment fa, DiscoDataContext Database, User RemovingUser)
public static void OnRemove(this DeviceFlagAssignment fa, DiscoDataContext database)
{
if (!fa.CanRemove())
throw new InvalidOperationException("Removing device flags is denied");
fa.OnRemoveUnsafe(Database, RemovingUser);
fa.OnRemoveUnsafe(database, UserService.CurrentUser);
}
public static void OnRemoveUnsafe(this DeviceFlagAssignment fa, DiscoDataContext Database, User RemovingUser)
public static void OnRemoveUnsafe(this DeviceFlagAssignment fa, DiscoDataContext database, User removingUser)
{
fa = Database.DeviceFlagAssignments
fa = database.DeviceFlagAssignments
.Include(a => a.DeviceFlag)
.First(a => a.Id == fa.Id);
RemovingUser = Database.Users.First(u => u.UserId == RemovingUser.UserId);
removingUser = database.Users.First(u => u.UserId == removingUser.UserId);
fa.RemovedDate = DateTime.Now;
fa.RemovedUserId = RemovingUser.UserId;
fa.RemovedUserId = removingUser.UserId;
if (!string.IsNullOrWhiteSpace(fa.DeviceFlag.OnUnassignmentExpression))
{
try
{
Database.SaveChanges();
var expressionResult = fa.EvaluateOnUnassignmentExpression(Database, RemovingUser, fa.AddedDate);
database.SaveChanges();
var expressionResult = fa.EvaluateOnUnassignmentExpression(database, removingUser, fa.AddedDate);
if (!string.IsNullOrWhiteSpace(expressionResult))
{
fa.OnUnassignmentExpressionResult = expressionResult;
Database.SaveChanges();
database.SaveChanges();
}
}
catch (Exception ex)
@@ -75,58 +80,52 @@ namespace Disco.Services
#endregion
#region Add
public static bool CanAddDeviceFlags(this Device d)
{
return UserService.CurrentAuthorization.Has(Claims.Device.Actions.AddFlags);
}
public static bool CanAddDeviceFlag(this Device d, DeviceFlag flag)
{
// Shortcut
if (!d.CanAddDeviceFlags())
return false;
// Already has Device Flag?
if (d.DeviceFlagAssignments.Any(fa => !fa.RemovedDate.HasValue && fa.DeviceFlagId == flag.Id))
return false;
return true;
var (_, permission) = DeviceFlagService.GetDeviceFlag(flag.Id);
return permission.CanAssign();
}
public static DeviceFlagAssignment OnAddDeviceFlag(this Device d, DiscoDataContext Database, DeviceFlag flag, User AddingUser, string Comments)
public static DeviceFlagAssignment OnAddDeviceFlag(this Device d, DiscoDataContext database, DeviceFlag flag, string comments)
{
if (!d.CanAddDeviceFlag(flag))
throw new InvalidOperationException("Adding device flag is denied");
return d.OnAddDeviceFlagUnsafe(Database, flag, AddingUser, Comments);
return d.OnAddDeviceFlagUnsafe(database, flag, UserService.CurrentUser, comments);
}
public static DeviceFlagAssignment OnAddDeviceFlagUnsafe(this Device d, DiscoDataContext Database, DeviceFlag flag, User AddingUser, string Comments)
public static DeviceFlagAssignment OnAddDeviceFlagUnsafe(this Device d, DiscoDataContext database, DeviceFlag flag, User addingUser, string comments)
{
flag = Database.DeviceFlags.First(f => f.Id == flag.Id);
d = Database.Devices.First(de => de.SerialNumber == d.SerialNumber);
AddingUser = Database.Users.First(user => user.UserId == AddingUser.UserId);
flag = database.DeviceFlags.First(f => f.Id == flag.Id);
d = database.Devices.First(de => de.SerialNumber == d.SerialNumber);
addingUser = database.Users.First(user => user.UserId == addingUser.UserId);
var fa = new DeviceFlagAssignment()
{
DeviceFlag = flag,
Device = d,
AddedDate = DateTime.Now,
AddedUser = AddingUser,
AddedUserId = AddingUser.UserId,
Comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim()
AddedUser = addingUser,
AddedUserId = addingUser.UserId,
Comments = string.IsNullOrWhiteSpace(comments) ? null : comments.Trim()
};
Database.DeviceFlagAssignments.Add(fa);
database.DeviceFlagAssignments.Add(fa);
if (!string.IsNullOrWhiteSpace(flag.OnAssignmentExpression))
{
try
{
Database.SaveChanges();
var expressionResult = fa.EvaluateOnAssignmentExpression(Database, AddingUser, fa.AddedDate);
database.SaveChanges();
var expressionResult = fa.EvaluateOnAssignmentExpression(database, addingUser, fa.AddedDate);
if (!string.IsNullOrWhiteSpace(expressionResult))
{
fa.OnAssignmentExpressionResult = expressionResult;
Database.SaveChanges();
database.SaveChanges();
}
}
catch (Exception ex)
@@ -13,7 +13,7 @@ namespace Disco.Services.Devices.DeviceFlags
{
public static class DeviceFlagService
{
private static Cache _cache;
private static Cache cache;
internal static Lazy<IObservable<RepositoryMonitorEvent>> DeviceFlagAssignmentRepositoryEvents;
static DeviceFlagService()
@@ -31,18 +31,51 @@ namespace Disco.Services.Devices.DeviceFlags
public static void Initialize(DiscoDataContext database)
{
_cache = new Cache(database);
cache = new Cache(database);
// Initialize Managed Groups (if configured)
_cache.GetDeviceFlags().ForEach(uf =>
cache.GetDeviceFlags().ForEach(uf =>
{
DeviceFlagDevicesManagedGroup.Initialize(uf);
DeviceFlagDeviceAssignedUsersManagedGroup.Initialize(uf);
DeviceFlagDevicesManagedGroup.Initialize(uf.flag);
DeviceFlagDeviceAssignedUsersManagedGroup.Initialize(uf.flag);
});
}
public static List<DeviceFlag> GetDeviceFlags() { return _cache.GetDeviceFlags(); }
public static DeviceFlag GetDeviceFlag(int deviceFlagId) { return _cache.GetDeviceFlag(deviceFlagId); }
public static IEnumerable<(DeviceFlag flag, FlagPermission permission)> GetDeviceFlags() { return cache.GetDeviceFlags(); }
public static (DeviceFlag flag, FlagPermission permission) GetDeviceFlag(int deviceFlagId) { return cache.GetDeviceFlag(deviceFlagId); }
public static DeviceFlag GetAvailableUserFlag(int deviceFlagId, Device targetDevice)
{
var (deviceFlag, permission) = cache.GetDeviceFlag(deviceFlagId);
if (targetDevice.DeviceFlagAssignments
.Where(a => a.DeviceFlagId == deviceFlagId && !a.RemovedDate.HasValue).Any())
return null;
if (permission.CanAssign())
return deviceFlag;
return null;
}
public static IEnumerable<DeviceFlag> GetAvailableDeviceFlags(Device targetDevice)
{
var records = cache.GetDeviceFlags();
var usedFlags = targetDevice.DeviceFlagAssignments
.Where(a => !a.RemovedDate.HasValue)
.Select(a => a.DeviceFlagId)
.ToList();
foreach (var (flag, permission) in records)
{
if (usedFlags.Contains(flag.Id))
continue;
if (permission.CanAssign())
yield return flag;
}
}
#region Device Flag Maintenance
public static DeviceFlag CreateDeviceFlag(DiscoDataContext database, string name, string description)
@@ -52,7 +85,7 @@ namespace Disco.Services.Devices.DeviceFlags
throw new ArgumentException("The Device Flag Name is required", nameof(name));
// Name Unique
if (_cache.GetDeviceFlags().Any(f => f.Name.Equals(name, StringComparison.Ordinal)))
if (cache.GetDeviceFlags().Any(f => f.flag.Name.Equals(name, StringComparison.Ordinal)))
throw new ArgumentException("Another Device Flag already exists with that name", nameof(name));
// Clone to break reference
@@ -67,7 +100,7 @@ namespace Disco.Services.Devices.DeviceFlags
database.DeviceFlags.Add(flag);
database.SaveChanges();
_cache.AddOrUpdate(flag);
cache.AddOrUpdate(flag);
return flag;
}
@@ -78,12 +111,12 @@ namespace Disco.Services.Devices.DeviceFlags
throw new ArgumentException("The Device Flag Name is required", nameof(deviceFlag));
// Name Unique
if (_cache.GetDeviceFlags().Any(f => f.Id != deviceFlag.Id && f.Name == deviceFlag.Name))
if (cache.GetDeviceFlags().Any(f => f.flag.Id != deviceFlag.Id && f.flag.Name == deviceFlag.Name))
throw new ArgumentException("Another Device Flag already exists with that name", nameof(deviceFlag));
database.SaveChanges();
_cache.AddOrUpdate(deviceFlag);
cache.AddOrUpdate(deviceFlag);
DeviceFlagDevicesManagedGroup.Initialize(deviceFlag);
DeviceFlagDeviceAssignedUsersManagedGroup.Initialize(deviceFlag);
@@ -113,7 +146,7 @@ namespace Disco.Services.Devices.DeviceFlags
database.SaveChanges();
// Remove from Cache
_cache.Remove(deviceFlagId);
cache.Remove(deviceFlagId);
status.Finished($"Successfully Deleted Device Flag: '{flag.Name}' [{flag.Id}]");
}
@@ -140,7 +173,7 @@ namespace Disco.Services.Devices.DeviceFlags
{
status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Assigning Flag: {device}");
return device.OnAddDeviceFlag(database, deviceFlag, technician, comments);
return device.OnAddDeviceFlagUnsafe(database, deviceFlag, technician, comments);
}).ToList();
// Save Chunk Items to Database
@@ -206,7 +239,7 @@ namespace Disco.Services.Devices.DeviceFlags
{
status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Assigning Flag: {device}");
return device.OnAddDeviceFlag(database, deviceFlag, technician, comments);
return device.OnAddDeviceFlagUnsafe(database, deviceFlag, technician, comments);
}).ToList();
// Save Chunk Items to Database
@@ -229,11 +262,11 @@ namespace Disco.Services.Devices.DeviceFlags
public static string RandomUnusedIcon()
{
return UIHelpers.RandomIcon(_cache.GetDeviceFlags().Select(f => f.Icon));
return UIHelpers.RandomIcon(cache.GetDeviceFlags().Select(f => f.flag.Icon));
}
public static string RandomUnusedThemeColour()
{
return UIHelpers.RandomThemeColour(_cache.GetDeviceFlags().Select(f => f.IconColour));
return UIHelpers.RandomThemeColour(cache.GetDeviceFlags().Select(f => f.flag.IconColour));
}
}
}
+1
View File
@@ -609,6 +609,7 @@
<Compile Include="Users\Contact\UserContactService.cs" />
<Compile Include="Users\UserExtensions.cs" />
<Compile Include="Users\UserFlags\Cache.cs" />
<Compile Include="Users\UserFlags\FlagPermissionExtensions.cs" />
<Compile Include="Users\UserFlags\UserFlagExport.cs" />
<Compile Include="Users\UserFlags\UserFlagExtensions.cs" />
<Compile Include="Users\UserFlags\UserFlagUserDevicesManagedGroup.cs" />
+11 -17
View File
@@ -8,7 +8,7 @@ namespace Disco.Services.Users.UserFlags
{
internal class Cache
{
private ConcurrentDictionary<int, UserFlag> _Cache;
private ConcurrentDictionary<int, (UserFlag flag, FlagPermission permission)> cache;
public Cache(DiscoDataContext Database)
{
@@ -26,36 +26,30 @@ namespace Disco.Services.Users.UserFlags
var flags = Database.UserFlags.ToList();
// Add Queues to In-Memory Cache
_Cache = new ConcurrentDictionary<int, UserFlag>(flags.Select(f => new KeyValuePair<int, UserFlag>(f.Id, f)));
cache = new ConcurrentDictionary<int, (UserFlag, FlagPermission)>(flags.Select(f => new KeyValuePair<int, (UserFlag, FlagPermission)>(f.Id, (f, f.Permissions))));
}
public UserFlag GetUserFlag(int UserFlagId)
public (UserFlag flag, FlagPermission permission) GetUserFlag(int UserFlagId)
{
if (_Cache.TryGetValue(UserFlagId, out var item))
if (cache.TryGetValue(UserFlagId, out var item))
return item;
else
return null;
return (null, null);
}
public List<UserFlag> GetUserFlags()
public List<(UserFlag flag, FlagPermission permission)> GetUserFlags()
{
return _Cache.Values.ToList();
return cache.Values.ToList();
}
public void AddOrUpdate(UserFlag UserFlag)
{
_Cache.AddOrUpdate(UserFlag.Id, UserFlag, (key, existingItem) => UserFlag);
var value = (UserFlag, UserFlag.Permissions);
cache.AddOrUpdate(UserFlag.Id, value, (key, existingItem) => value);
}
public UserFlag Remove(int UserFlagId)
public void Remove(int UserFlagId)
{
if (_Cache.TryRemove(UserFlagId, out var item))
return item;
else
return null;
}
public UserFlag Remove(UserFlag UserFlag)
{
return Remove(UserFlag.Id);
cache.TryRemove(UserFlagId, out _);
}
}
}
@@ -0,0 +1,144 @@
using Disco.Models.Repository;
using Disco.Services.Authorization;
using Disco.Services.Devices.DeviceFlags;
using Disco.Services.Users;
using Disco.Services.Users.UserFlags;
using System.Collections.Generic;
using System.Linq;
namespace Disco
{
public static class FlagPermissionExtensions
{
public static bool CanShow(this FlagPermission permission)
{
var authorization = UserService.CurrentAuthorization;
// inherited permission
if (permission.Inherit &&
authorization.Has(permission.FlagType == FlagType.User ? Claims.User.ShowFlagAssignments : Claims.Device.ShowFlagAssignments))
{
return true;
}
// permission override
if (permission != null && (
permission.CanShowSubjectIds.Contains(authorization.User.UserId) ||
permission.CanShowSubjectIds.Overlaps(authorization.GroupMembership) ||
permission.CanShowSubjectIds.Overlaps(authorization.RoleTokens.Select(r => $"[{r.Role.Id}]"))
))
{
return true;
}
return false;
}
public static bool CanAssign(this FlagPermission permission)
{
var authorization = UserService.CurrentAuthorization;
// inherited permission
if (permission.Inherit &&
authorization.Has(permission.FlagType == FlagType.User ? Claims.User.Actions.AddFlags : Claims.Device.Actions.AddFlags))
{
return true;
}
// permission override
if (permission != null && (
permission.CanAssignSubjectIds.Contains(authorization.User.UserId) ||
permission.CanAssignSubjectIds.Overlaps(authorization.GroupMembership) ||
permission.CanAssignSubjectIds.Overlaps(authorization.RoleTokens.Select(r => $"[{r.Role.Id}]"))
))
{
return true;
}
return false;
}
public static bool CanEdit(this FlagPermission permission)
{
var authorization = UserService.CurrentAuthorization;
// inherited permission
if (permission.Inherit &&
authorization.Has(permission.FlagType == FlagType.User ? Claims.User.Actions.EditFlags : Claims.Device.Actions.EditFlags))
{
return true;
}
// permission override
if (permission != null && (
permission.CanEditSubjectIds.Contains(authorization.User.UserId) ||
permission.CanEditSubjectIds.Overlaps(authorization.GroupMembership) ||
permission.CanEditSubjectIds.Overlaps(authorization.RoleTokens.Select(r => $"[{r.Role.Id}]"))
))
{
return true;
}
return false;
}
public static bool CanRemove(this FlagPermission permission)
{
var authorization = UserService.CurrentAuthorization;
// inherited permission
if (permission.Inherit &&
authorization.Has(permission.FlagType == FlagType.User ? Claims.User.Actions.RemoveFlags : Claims.Device.Actions.RemoveFlags))
{
return true;
}
// permission override
if (permission != null && (
permission.CanRemoveSubjectIds.Contains(authorization.User.UserId) ||
permission.CanRemoveSubjectIds.Overlaps(authorization.GroupMembership) ||
permission.CanRemoveSubjectIds.Overlaps(authorization.RoleTokens.Select(r => $"[{r.Role.Id}]"))
))
{
return true;
}
return false;
}
public static bool CanShowAny(this IEnumerable<UserFlagAssignment> assignments)
{
if (assignments == null)
return false;
foreach (var assignment in assignments)
{
if (assignment.RemovedDate.HasValue)
continue;
var (_, permission) = UserFlagService.GetUserFlag(assignment.UserFlagId);
if (permission.CanShow())
return true;
}
return false;
}
public static bool CanShowAny(this IEnumerable<DeviceFlagAssignment> assignments)
{
if (assignments == null)
return false;
foreach (var assignment in assignments)
{
if (assignment.RemovedDate.HasValue)
continue;
var (_, permission) = DeviceFlagService.GetDeviceFlag(assignment.DeviceFlagId);
if (permission.CanShow())
return true;
}
return false;
}
}
}
@@ -4,6 +4,7 @@ using Disco.Services.Authorization;
using Disco.Services.Expressions;
using Disco.Services.Logging;
using Disco.Services.Users;
using Disco.Services.Users.UserFlags;
using System;
using System.Collections;
using System.Linq;
@@ -14,16 +15,18 @@ namespace Disco.Services
{
#region Edit Comments
public static bool CanEditComments(this UserFlagAssignment fa)
public static bool CanEdit(this UserFlagAssignment fa)
{
return UserService.CurrentAuthorization.Has(Claims.User.Actions.EditFlags);
var (_, permission) = UserFlagService.GetUserFlag(fa.UserFlagId);
return permission.CanEdit();
}
public static void OnEditComments(this UserFlagAssignment fa, string Comments)
public static void OnEdit(this UserFlagAssignment fa, string comments)
{
if (!fa.CanEditComments())
if (!fa.CanEdit())
throw new InvalidOperationException("Editing comments for user flags is denied");
fa.Comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
fa.Comments = string.IsNullOrWhiteSpace(comments) ? null : comments.Trim();
}
#endregion
@@ -33,34 +36,36 @@ namespace Disco.Services
if (fa.RemovedDate.HasValue)
return false;
return UserService.CurrentAuthorization.Has(Claims.User.Actions.RemoveFlags);
var (_, permission) = UserFlagService.GetUserFlag(fa.UserFlagId);
return permission.CanRemove();
}
public static void OnRemove(this UserFlagAssignment fa, DiscoDataContext Database, User RemovingUser)
public static void OnRemove(this UserFlagAssignment fa, DiscoDataContext database)
{
if (!fa.CanRemove())
throw new InvalidOperationException("Removing user flags is denied");
fa.OnRemoveUnsafe(Database, RemovingUser);
fa.OnRemoveUnsafe(database, UserService.CurrentUser);
}
public static void OnRemoveUnsafe(this UserFlagAssignment fa, DiscoDataContext Database, User RemovingUser)
public static void OnRemoveUnsafe(this UserFlagAssignment fa, DiscoDataContext database, User removingUser)
{
fa = Database.UserFlagAssignments.First(a => a.Id == fa.Id);
RemovingUser = Database.Users.First(u => u.UserId == RemovingUser.UserId);
fa = database.UserFlagAssignments.First(a => a.Id == fa.Id);
removingUser = database.Users.First(u => u.UserId == removingUser.UserId);
fa.RemovedDate = DateTime.Now;
fa.RemovedUserId = RemovingUser.UserId;
fa.RemovedUserId = removingUser.UserId;
if (!string.IsNullOrWhiteSpace(fa.UserFlag.OnUnassignmentExpression))
{
try
{
Database.SaveChanges();
var expressionResult = fa.EvaluateOnUnassignmentExpression(Database, RemovingUser, fa.AddedDate);
database.SaveChanges();
var expressionResult = fa.EvaluateOnUnassignmentExpression(database, removingUser, fa.AddedDate);
if (!string.IsNullOrWhiteSpace(expressionResult))
{
fa.OnUnassignmentExpressionResult = expressionResult;
Database.SaveChanges();
database.SaveChanges();
}
}
catch (Exception ex)
@@ -72,58 +77,52 @@ namespace Disco.Services
#endregion
#region Add
public static bool CanAddUserFlags(this User u)
{
return UserService.CurrentAuthorization.Has(Claims.User.Actions.AddFlags);
}
public static bool CanAddUserFlag(this User u, UserFlag flag)
{
// Shortcut
if (!u.CanAddUserFlags())
return false;
// Already has User Flag?
if (u.UserFlagAssignments.Any(fa => !fa.RemovedDate.HasValue && fa.UserFlagId == flag.Id))
return false;
return true;
var (_, permission) = UserFlagService.GetUserFlag(flag.Id);
return permission.CanAssign();
}
public static UserFlagAssignment OnAddUserFlag(this User u, DiscoDataContext Database, UserFlag flag, User AddingUser, string Comments)
public static UserFlagAssignment OnAddUserFlag(this User u, DiscoDataContext database, UserFlag flag, string comments)
{
if (!u.CanAddUserFlag(flag))
throw new InvalidOperationException("Adding user flag is denied");
return u.OnAddUserFlagUnsafe(Database, flag, AddingUser, Comments);
return u.OnAddUserFlagUnsafe(database, flag, UserService.CurrentUser, comments);
}
public static UserFlagAssignment OnAddUserFlagUnsafe(this User u, DiscoDataContext Database, UserFlag flag, User AddingUser, string Comments)
public static UserFlagAssignment OnAddUserFlagUnsafe(this User u, DiscoDataContext database, UserFlag flag, User addingUser, string comments)
{
flag = Database.UserFlags.First(f => f.Id == flag.Id);
u = Database.Users.First(user => user.UserId == u.UserId);
AddingUser = Database.Users.First(user => user.UserId == AddingUser.UserId);
flag = database.UserFlags.First(f => f.Id == flag.Id);
u = database.Users.First(user => user.UserId == u.UserId);
addingUser = database.Users.First(user => user.UserId == addingUser.UserId);
var fa = new UserFlagAssignment()
{
UserFlag = flag,
User = u,
AddedDate = DateTime.Now,
AddedUser = AddingUser,
AddedUserId = AddingUser.UserId,
Comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim()
AddedUser = addingUser,
AddedUserId = addingUser.UserId,
Comments = string.IsNullOrWhiteSpace(comments) ? null : comments.Trim()
};
Database.UserFlagAssignments.Add(fa);
database.UserFlagAssignments.Add(fa);
if (!string.IsNullOrWhiteSpace(flag.OnAssignmentExpression))
{
try
{
Database.SaveChanges();
var expressionResult = fa.EvaluateOnAssignmentExpression(Database, AddingUser, fa.AddedDate);
database.SaveChanges();
var expressionResult = fa.EvaluateOnAssignmentExpression(database, addingUser, fa.AddedDate);
if (!string.IsNullOrWhiteSpace(expressionResult))
{
fa.OnAssignmentExpressionResult = expressionResult;
Database.SaveChanges();
database.SaveChanges();
}
}
catch (Exception ex)
@@ -5,6 +5,7 @@ using Disco.Services.Extensions;
using Disco.Services.Tasks;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Reactive.Linq;
@@ -12,7 +13,7 @@ namespace Disco.Services.Users.UserFlags
{
public static class UserFlagService
{
private static Cache _cache;
private static Cache cache;
internal static Lazy<IObservable<RepositoryMonitorEvent>> UserFlagAssignmentRepositoryEvents;
static UserFlagService()
@@ -24,25 +25,58 @@ namespace Disco.Services.Users.UserFlags
RepositoryMonitor.StreamAfterCommit.Where(e =>
e.EntityType == typeof(UserFlagAssignment) &&
(e.EventType != RepositoryMonitorEventType.Modified ||
e.ModifiedProperties.Contains("RemovedDate"))
e.ModifiedProperties.Contains(nameof(UserFlagAssignment.RemovedDate)))
)
);
}
public static void Initialize(DiscoDataContext Database)
{
_cache = new Cache(Database);
cache = new Cache(Database);
// Initialize Managed Groups (if configured)
_cache.GetUserFlags().ForEach(uf =>
cache.GetUserFlags().ForEach(uf =>
{
UserFlagUsersManagedGroup.Initialize(uf);
UserFlagUserDevicesManagedGroup.Initialize(uf);
UserFlagUsersManagedGroup.Initialize(uf.flag);
UserFlagUserDevicesManagedGroup.Initialize(uf.flag);
});
}
public static List<UserFlag> GetUserFlags() { return _cache.GetUserFlags(); }
public static UserFlag GetUserFlag(int UserFlagId) { return _cache.GetUserFlag(UserFlagId); }
public static IEnumerable<(UserFlag flag, FlagPermission permission)> GetUserFlags() { return cache.GetUserFlags(); }
public static (UserFlag flag, FlagPermission permission) GetUserFlag(int UserFlagId) { return cache.GetUserFlag(UserFlagId); }
public static UserFlag GetAvailableUserFlag(int userFlagId, User targetUser)
{
var (userFlag, permission) = cache.GetUserFlag(userFlagId);
if (targetUser.UserFlagAssignments
.Where(a => a.UserFlagId == userFlagId && !a.RemovedDate.HasValue).Any())
return null;
if (permission.CanAssign())
return userFlag;
return null;
}
public static IEnumerable<UserFlag> GetAvailableUserFlags(User targetUser)
{
var records = cache.GetUserFlags();
var usedFlags = targetUser.UserFlagAssignments
.Where(a => !a.RemovedDate.HasValue)
.Select(a => a.UserFlagId)
.ToList();
foreach (var (flag, permission) in records)
{
if (usedFlags.Contains(flag.Id))
continue;
if (permission.CanAssign())
yield return flag;
}
}
#region User Flag Maintenance
public static UserFlag CreateUserFlag(DiscoDataContext Database, string name, string description)
@@ -52,7 +86,7 @@ namespace Disco.Services.Users.UserFlags
throw new ArgumentException("The User Flag Name is required", nameof(name));
// Name Unique
if (_cache.GetUserFlags().Any(f => f.Name.Equals(name, StringComparison.Ordinal)))
if (cache.GetUserFlags().Any(f => f.flag.Name.Equals(name, StringComparison.Ordinal)))
throw new ArgumentException("Another User Flag already exists with that name", nameof(name));
// Clone to break reference
@@ -67,7 +101,7 @@ namespace Disco.Services.Users.UserFlags
Database.UserFlags.Add(flag);
Database.SaveChanges();
_cache.AddOrUpdate(flag);
cache.AddOrUpdate(flag);
return flag;
}
@@ -78,12 +112,12 @@ namespace Disco.Services.Users.UserFlags
throw new ArgumentException("The User Flag Name is required");
// Name Unique
if (_cache.GetUserFlags().Any(f => f.Id != UserFlag.Id && f.Name == UserFlag.Name))
throw new ArgumentException("Another User Flag already exists with that name", "UserFlag");
if (cache.GetUserFlags().Any(f => f.flag.Id != UserFlag.Id && f.flag.Name == UserFlag.Name))
throw new ArgumentException("Another User Flag already exists with that name", nameof(UserFlag));
Database.SaveChanges();
_cache.AddOrUpdate(UserFlag);
cache.AddOrUpdate(UserFlag);
UserFlagUsersManagedGroup.Initialize(UserFlag);
UserFlagUserDevicesManagedGroup.Initialize(UserFlag);
@@ -113,22 +147,22 @@ namespace Disco.Services.Users.UserFlags
Database.SaveChanges();
// Remove from Cache
_cache.Remove(UserFlagId);
cache.Remove(UserFlagId);
Status.Finished($"Successfully Deleted User Flag: '{flag.Name}' [{flag.Id}]");
}
#endregion
#region Bulk Assignment
public static IEnumerable<UserFlagAssignment> BulkAssignAddUsers(DiscoDataContext Database, UserFlag UserFlag, User Technician, string Comments, List<User> Users, IScheduledTaskStatus Status)
public static IEnumerable<UserFlagAssignment> BulkAssignAddUsers(DiscoDataContext database, UserFlag userFlag, User techUser, string comments, List<User> users, IScheduledTaskStatus status)
{
if (Users.Count > 0)
if (users.Count > 0)
{
double progressInterval;
const int databaseChunkSize = 100;
string comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
comments = string.IsNullOrWhiteSpace(comments) ? null : comments.Trim();
var addUsers = Users.Where(u => !u.UserFlagAssignments.Any(a => a.UserFlagId == UserFlag.Id && !a.RemovedDate.HasValue)).ToList();
var addUsers = users.Where(u => !u.UserFlagAssignments.Any(a => a.UserFlagId == userFlag.Id && !a.RemovedDate.HasValue)).ToList();
progressInterval = (double)100 / addUsers.Count;
@@ -138,39 +172,39 @@ namespace Disco.Services.Users.UserFlags
var chunkResults = chunk.Select((user, index) =>
{
Status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Assigning Flag: {user.ToString()}");
status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Assigning Flag: {user}");
return user.OnAddUserFlag(Database, UserFlag, Technician, comments);
return user.OnAddUserFlagUnsafe(database, userFlag, techUser, comments);
}).ToList();
// Save Chunk Items to Database
Database.SaveChanges();
database.SaveChanges();
return chunkResults;
}).Where(fa => fa != null).ToList();
Status.SetFinishedMessage($"{addUsers.Count} Users/s Added; {(Users.Count - addUsers.Count)} User/s Skipped");
status.SetFinishedMessage($"{addUsers.Count} Users/s Added; {users.Count - addUsers.Count} User/s Skipped");
return addedUserAssignments;
}
else
{
Status.SetFinishedMessage("No changes found");
status.SetFinishedMessage("No changes found");
return Enumerable.Empty<UserFlagAssignment>();
}
}
public static IEnumerable<UserFlagAssignment> BulkAssignOverrideUsers(DiscoDataContext Database, UserFlag UserFlag, User Technician, string Comments, List<User> Users, IScheduledTaskStatus Status)
public static IEnumerable<UserFlagAssignment> BulkAssignOverrideUsers(DiscoDataContext database, UserFlag userFlag, User techUser, string comments, List<User> users, IScheduledTaskStatus status)
{
double progressInterval;
const int databaseChunkSize = 100;
string comments = string.IsNullOrWhiteSpace(Comments) ? null : Comments.Trim();
comments = string.IsNullOrWhiteSpace(comments) ? null : comments.Trim();
Status.UpdateStatus(0, "Calculating assignment changes");
status.UpdateStatus(0, "Calculating assignment changes");
var currentAssignments = Database.UserFlagAssignments.Include("User").Where(a => a.UserFlagId == UserFlag.Id && !a.RemovedDate.HasValue).ToList();
var removeAssignments = currentAssignments.Where(ca => !Users.Any(u => u.UserId.Equals(ca.UserId, StringComparison.OrdinalIgnoreCase))).ToList();
var addUsers = Users.Where(u => !currentAssignments.Any(ca => ca.UserId.Equals(u.UserId, StringComparison.OrdinalIgnoreCase))).ToList();
var currentAssignments = database.UserFlagAssignments.Include(a => a.User).Where(a => a.UserFlagId == userFlag.Id && !a.RemovedDate.HasValue).ToList();
var removeAssignments = currentAssignments.Where(ca => !users.Any(u => u.UserId.Equals(ca.UserId, StringComparison.OrdinalIgnoreCase))).ToList();
var addUsers = users.Where(u => !currentAssignments.Any(ca => ca.UserId.Equals(u.UserId, StringComparison.OrdinalIgnoreCase))).ToList();
if (removeAssignments.Count > 0 || addUsers.Count > 0)
{
@@ -184,15 +218,15 @@ namespace Disco.Services.Users.UserFlags
var chunkResults = chunk.Select((flagAssignment, index) =>
{
Status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Removing Flag: {flagAssignment.User.ToString()}");
status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Removing Flag: {flagAssignment.User}");
flagAssignment.OnRemoveUnsafe(Database, Technician);
flagAssignment.OnRemoveUnsafe(database, techUser);
return flagAssignment;
}).ToList();
// Save Chunk Items to Database
Database.SaveChanges();
database.SaveChanges();
return chunkResults;
}).ToList();
@@ -204,24 +238,24 @@ namespace Disco.Services.Users.UserFlags
var chunkResults = chunk.Select((user, index) =>
{
Status.UpdateStatus((chunkIndexOffset + index) * progressInterval, $"Assigning Flag: {user.ToString()}");
status.UpdateStatus((chunkIndexOffset + index) * progressInterval, string.Format("Assigning Flag: {0}", user.ToString()));
return user.OnAddUserFlag(Database, UserFlag, Technician, comments);
return user.OnAddUserFlagUnsafe(database, userFlag, techUser, comments);
}).ToList();
// Save Chunk Items to Database
Database.SaveChanges();
database.SaveChanges();
return chunkResults;
}).ToList();
Status.SetFinishedMessage($"{addUsers.Count} Users/s Added; {removeAssignments.Count} User/s Removed; {(Users.Count - addUsers.Count)} User/s Skipped");
status.SetFinishedMessage($"{addUsers.Count} Users/s Added; {removeAssignments.Count} User/s Removed; {users.Count - addUsers.Count} User/s Skipped");
return addedUserAssignments;
}
else
{
Status.SetFinishedMessage("No changes found");
status.SetFinishedMessage("No changes found");
return Enumerable.Empty<UserFlagAssignment>();
}
}
@@ -229,11 +263,11 @@ namespace Disco.Services.Users.UserFlags
public static string RandomUnusedIcon()
{
return UIHelpers.RandomIcon(_cache.GetUserFlags().Select(f => f.Icon));
return UIHelpers.RandomIcon(cache.GetUserFlags().Select(f => f.flag.Icon));
}
public static string RandomUnusedThemeColour()
{
return UIHelpers.RandomThemeColour(_cache.GetUserFlags().Select(f => f.IconColour));
return UIHelpers.RandomThemeColour(cache.GetUserFlags().Select(f => f.flag.IconColour));
}
}
}
+13 -5
View File
@@ -154,7 +154,7 @@ namespace Disco.Services.Users
AuthorizationLog.LogRoleCreated(role, CurrentUserId);
// Add to Cache
RoleCache.AddRole(role);
RoleCache.AddOrUpdateRole(role);
// Flush User Cache
Cache.FlushCache();
@@ -164,7 +164,7 @@ namespace Disco.Services.Users
public static void DeleteAuthorizationRole(DiscoDataContext Database, AuthorizationRole Role)
{
if (Role == null)
throw new ArgumentNullException("Role");
throw new ArgumentNullException(nameof(Role));
Database.AuthorizationRoles.Remove(Role);
Database.SaveChanges();
@@ -180,19 +180,27 @@ namespace Disco.Services.Users
public static void UpdateAuthorizationRole(DiscoDataContext Database, AuthorizationRole Role)
{
if (Role == null)
throw new ArgumentNullException("Role");
throw new ArgumentNullException(nameof(Role));
if (Database == null)
throw new ArgumentNullException("Database");
throw new ArgumentNullException(nameof(Database));
Database.SaveChanges();
// Update Role Cache
RoleCache.UpdateRole(Role);
RoleCache.AddOrUpdateRole(Role);
// Flush User Cache
Cache.FlushCache();
}
public static string GetAuthorizationRoleName(int roleId)
{
var role = RoleCache.GetRoleToken(roleId);
if (role == null)
return "Unknown authorization role";
return role.Role.Name;
}
public static IEnumerable<string> AdministratorSubjectIds
{
get
+8 -2
View File
@@ -12,7 +12,13 @@ namespace Disco.Services.Web
protected static HttpStatusCodeResult BadRequest(string message = null)
=> StatusCode(HttpStatusCode.BadRequest, message);
protected static HttpStatusCodeResult StatusCode(HttpStatusCode statusCode, string message = null)
=> new HttpStatusCodeResult(statusCode, message);
protected static HttpStatusCodeResult StatusCode(HttpStatusCode statusCode, string statusDescription = null)
=> new HttpStatusCodeResult(statusCode, statusDescription);
protected static HttpNotFoundResult NotFound(string statusDescription = null)
=> new HttpNotFoundResult(statusDescription);
protected static HttpUnauthorizedResult Unauthorized(string statusDescription = null)
=> new HttpUnauthorizedResult(statusDescription);
}
}
@@ -78,14 +78,16 @@ namespace Disco.Web.Areas.API.Controllers
}
}
private void UpdateClaims(AuthorizationRole AuthorizationRole, string[] ClaimKeys)
private void UpdateClaims(AuthorizationRole AuthorizationRole, string[] claimKeys)
{
var proposedClaims = Claims.BuildClaims(ClaimKeys);
claimKeys = claimKeys ?? Array.Empty<string>();
var proposedClaims = Claims.BuildClaims(claimKeys);
var currentToken = RoleToken.FromAuthorizationRole(AuthorizationRole);
var currentClaimKeys = Claims.GetClaimKeys(currentToken.Claims);
var removedClaims = currentClaimKeys.Except(ClaimKeys).ToArray();
var addedClaims = ClaimKeys.Except(currentClaimKeys).ToArray();
var removedClaims = currentClaimKeys.Except(claimKeys).ToArray();
var addedClaims = claimKeys.Except(currentClaimKeys).ToArray();
AuthorizationRole.SetClaims(proposedClaims);
UserService.UpdateAuthorizationRole(Database, AuthorizationRole);
@@ -1,6 +1,5 @@
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using System;
using System.Data.Entity;
@@ -12,7 +11,7 @@ namespace Disco.Web.Areas.API.Controllers
public partial class DeviceFlagAssignmentController : AuthorizedDatabaseController
{
const string pComments = "comments";
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Update(int id, string key, string value = null, bool? redirect = null)
{
try
@@ -21,7 +20,9 @@ namespace Disco.Web.Areas.API.Controllers
throw new ArgumentOutOfRangeException(nameof(id));
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
var assignment = Database.DeviceFlagAssignments.FirstOrDefault(a => a.Id == id);
var assignment = Database.DeviceFlagAssignments
.Include(a => a.DeviceFlag)
.FirstOrDefault(a => a.Id == id);
if (assignment != null)
{
switch (key.ToLower())
@@ -52,7 +53,7 @@ namespace Disco.Web.Areas.API.Controllers
}
#region Update Shortcut Methods
[DiscoAuthorizeAny(Claims.Device.Actions.EditFlags)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult UpdateComments(int id, string Comments = null, bool? redirect = null)
{
return Update(id, pComments, Comments, redirect);
@@ -60,20 +61,19 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
#region Update Properties
private void UpdateComments(DeviceFlagAssignment assignment, string Comments)
private void UpdateComments(DeviceFlagAssignment assignment, string comments)
{
if (!assignment.CanEditComments())
if (!assignment.CanEdit())
throw new InvalidOperationException("Editing comments for device flags is denied");
assignment.OnEditComments(Comments);
assignment.OnEdit(comments);
Database.SaveChanges();
}
#endregion
#region Actions
[DiscoAuthorizeAny(Claims.Device.Actions.AddFlags)]
public virtual ActionResult AddDevice(int id, string DeviceSerialNumber, string Comments)
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult AddDevice(int id, string deviceSerialNumber, string comments)
{
Database.Configuration.LazyLoadingEnabled = true;
@@ -81,37 +81,35 @@ namespace Disco.Web.Areas.API.Controllers
if (flag == null)
throw new ArgumentException("Invalid Device Flag Id", nameof(id));
var device = Database.Devices.Include(u => u.DeviceFlagAssignments).FirstOrDefault(d => d.SerialNumber == DeviceSerialNumber);
var device = Database.Devices.Include(u => u.DeviceFlagAssignments).FirstOrDefault(d => d.SerialNumber == deviceSerialNumber);
if (device == null)
throw new ArgumentException("Invalid Device Serial Number", nameof(DeviceSerialNumber));
throw new ArgumentException("Invalid Device Serial Number", nameof(deviceSerialNumber));
if (!device.CanAddDeviceFlag(flag))
throw new InvalidOperationException("Adding device flag is denied");
return Unauthorized("Adding device flag is denied");
var addingUser = Database.Users.Find(CurrentUser.UserId);
var assignment = device.OnAddDeviceFlag(Database, flag, addingUser, Comments);
var assignment = device.OnAddDeviceFlag(Database, flag, comments);
Database.SaveChanges();
return Redirect($"{Url.Action(MVC.Device.Show(device.SerialNumber))}#DeviceDetailTab-Flags");
}
[DiscoAuthorizeAny(Claims.Device.Actions.RemoveFlags)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult RemoveDevice(int id)
{
Database.Configuration.LazyLoadingEnabled = true;
var assignment = Database.DeviceFlagAssignments.FirstOrDefault(a => a.Id == id);
var assignment = Database.DeviceFlagAssignments
.Include(a => a.DeviceFlag)
.FirstOrDefault(a => a.Id == id);
if (assignment == null)
throw new ArgumentException("Invalid Device Flag Assignment Id", nameof(id));
if (!assignment.CanRemove())
throw new InvalidOperationException("Removing device flag assignment is denied");
return Unauthorized("Removing device flag assignment is denied");
var removingUser = Database.Users.Find(CurrentUser.UserId);
assignment.OnRemove(Database, removingUser);
assignment.OnRemove(Database);
Database.SaveChanges();
return Redirect($"{Url.Action(MVC.Device.Show(assignment.DeviceSerialNumber))}#DeviceDetailTab-Flags");
@@ -5,7 +5,9 @@ using Disco.Services.Devices.DeviceFlags;
using Disco.Services.Exporting;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using Disco.Services.Users.UserFlags;
using Disco.Services.Web;
using Disco.Web.Areas.API.Models.Shared;
using Disco.Web.Areas.Config.Models.DeviceFlag;
using Disco.Web.Extensions;
using System;
@@ -467,6 +469,24 @@ namespace Disco.Web.Areas.API.Controllers
return RedirectToAction(MVC.Config.Export.Create(savedExport.Id));
}
[DiscoAuthorize(Claims.Config.DeviceFlag.Configure)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Permission(int id, FlagPermissionModel model = null)
{
var deviceFlag = Database.DeviceFlags.Find(id);
if (deviceFlag == null)
return NotFound();
if (model == null || !model.IsOverride)
deviceFlag.Permissions = null;
else
deviceFlag.Permissions = model.ToFlagPermission(deviceFlag);
DeviceFlagService.Update(Database, deviceFlag);
return RedirectToAction(MVC.Config.DeviceFlag.Index(deviceFlag.Id));
}
#endregion
}
}
@@ -4,7 +4,9 @@ using Disco.Services.Authorization;
using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Interop.DiscoServices;
using Disco.Services.Messaging;
using Disco.Services.Users;
using Disco.Services.Web;
using Disco.Web.Areas.API.Models.Shared;
using System;
using System.Collections.Generic;
using System.Drawing;
@@ -320,38 +322,64 @@ namespace Disco.Web.Areas.API.Controllers
};
}
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
public virtual ActionResult SearchSubjects(string term)
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure, Claims.Config.UserFlag.Configure, Claims.Config.DeviceFlag.Configure)]
public virtual ActionResult SearchSubjects(string term, bool includeAuthorizationRoles = false)
{
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
var userResults = ActiveDirectory.SearchADUserAccounts(term, true).Cast<IADObject>();
var groupResults = ActiveDirectory.SearchADGroups(term).Select(r => SubjectDescriptorModel.FromActiveDirectoryObject(r));
var userResults = ActiveDirectory.SearchADUserAccounts(term, true).Select(r => SubjectDescriptorModel.FromActiveDirectoryObject(r));
var results = groupResults.Concat(userResults).OrderBy(r => r.SamAccountName)
.Select(r => Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
IEnumerable<SubjectDescriptorModel> roleResults;
if (includeAuthorizationRoles)
{
roleResults = Database.AuthorizationRoles.AsNoTracking().Where(r => r.Name.Contains(term))
.ToList()
.Select(r => SubjectDescriptorModel.FromAuthorizationRole(r));
}
else
roleResults = Enumerable.Empty<SubjectDescriptorModel>();
var results = groupResults.Concat(userResults).Concat(roleResults)
.OrderBy(r => r.Id).ToList();
return Json(results, JsonRequestBehavior.AllowGet);
}
[DiscoAuthorizeAny(Claims.Config.UserFlag.Configure)]
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.DeviceProfile.Configure, Claims.Config.DocumentTemplate.Configure, Claims.Config.Plugin.Configure, Claims.Config.UserFlag.Configure, Claims.Config.DeviceFlag.Configure)]
public virtual ActionResult SearchGroupSubjects(string term)
{
var groupResults = ActiveDirectory.SearchADGroups(term).Cast<IADObject>();
var results = groupResults.OrderBy(r => r.SamAccountName)
.Select(r => Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
.Select(r => SubjectDescriptorModel.FromActiveDirectoryObject(r)).ToList();
return Json(results, JsonRequestBehavior.AllowGet);
}
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure)]
public virtual ActionResult Subject(string Id)
[DiscoAuthorizeAny(Claims.DiscoAdminAccount, Claims.Config.JobQueue.Configure, Claims.Config.UserFlag.Configure, Claims.Config.DeviceFlag.Configure)]
public virtual ActionResult Subject(string Id, bool includeAuthorizationRoles = false)
{
if (string.IsNullOrWhiteSpace(Id))
return Json(null, JsonRequestBehavior.AllowGet);
if (Id.StartsWith("[", StringComparison.Ordinal))
{
if (includeAuthorizationRoles && int.TryParse(Id.Trim('[', ']'), out var roleId))
{
var roleName = UserService.GetAuthorizationRoleName(roleId);
if (roleName != null)
{
return Json(SubjectDescriptorModel.FromAuthorizationRole(roleId, roleName), JsonRequestBehavior.AllowGet);
}
}
return Json(null, JsonRequestBehavior.AllowGet);
}
var subject = ActiveDirectory.RetrieveADObject(Id, Quick: true);
if (subject == null)
return Json(null, JsonRequestBehavior.AllowGet);
else
return Json(Models.Shared.SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
return Json(SubjectDescriptorModel.FromActiveDirectoryObject(subject), JsonRequestBehavior.AllowGet);
}
[DiscoAuthorizeAny(Claims.Config.UserFlag.Configure, Claims.Config.DeviceFlag.Configure, Claims.Config.DeviceProfile.Configure, Claims.Config.DocumentTemplate.Configure)]
@@ -12,7 +12,7 @@ namespace Disco.Web.Areas.API.Controllers
public partial class UserFlagAssignmentController : AuthorizedDatabaseController
{
const string pComments = "comments";
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Update(int id, string key, string value = null, bool? redirect = null)
{
try
@@ -21,7 +21,9 @@ namespace Disco.Web.Areas.API.Controllers
throw new ArgumentOutOfRangeException(nameof(id));
if (string.IsNullOrEmpty(key))
throw new ArgumentNullException(nameof(key));
var userFlagAssignment = Database.UserFlagAssignments.FirstOrDefault(a => a.Id == id);
var userFlagAssignment = Database.UserFlagAssignments
.Include(a => a.UserFlag)
.FirstOrDefault(a => a.Id == id);
if (userFlagAssignment != null)
{
switch (key.ToLower())
@@ -52,7 +54,7 @@ namespace Disco.Web.Areas.API.Controllers
}
#region Update Shortcut Methods
[DiscoAuthorizeAny(Claims.User.Actions.EditFlags)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult UpdateComments(int id, string Comments = null, bool? redirect = null)
{
return Update(id, pComments, Comments, redirect);
@@ -60,19 +62,19 @@ namespace Disco.Web.Areas.API.Controllers
#endregion
#region Update Properties
private void UpdateComments(UserFlagAssignment userFlagAssignment, string Comments)
private void UpdateComments(UserFlagAssignment userFlagAssignment, string comments)
{
if (!userFlagAssignment.CanEditComments())
if (!userFlagAssignment.CanEdit())
throw new InvalidOperationException("Editing comments for user flags is denied");
userFlagAssignment.OnEditComments(Comments);
userFlagAssignment.OnEdit(comments);
Database.SaveChanges();
}
#endregion
#region Actions
[DiscoAuthorizeAny(Claims.User.Actions.AddFlags)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult AddUser(int id, string UserId, string Comments)
{
Database.Configuration.LazyLoadingEnabled = true;
@@ -86,32 +88,30 @@ namespace Disco.Web.Areas.API.Controllers
throw new ArgumentException("Invalid User Id", nameof(UserId));
if (!user.CanAddUserFlag(userFlag))
throw new InvalidOperationException("Adding user flag is denied");
return Unauthorized("Adding user flag is denied");
var addingUser = Database.Users.Find(CurrentUser.UserId);
var userFlagAssignment = user.OnAddUserFlag(Database, userFlag, addingUser, Comments);
var userFlagAssignment = user.OnAddUserFlag(Database, userFlag, Comments);
Database.SaveChanges();
return Redirect($"{Url.Action(MVC.User.Show(user.UserId))}#UserDetailTab-Flags");
}
[DiscoAuthorizeAny(Claims.User.Actions.RemoveFlags)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult RemoveUser(int id)
{
Database.Configuration.LazyLoadingEnabled = true;
var userFlagAssignment = Database.UserFlagAssignments.FirstOrDefault(a => a.Id == id);
var userFlagAssignment = Database.UserFlagAssignments
.Include(a => a.UserFlag)
.FirstOrDefault(a => a.Id == id);
if (userFlagAssignment == null)
throw new ArgumentException("Invalid User Flag Assignment Id", nameof(id));
if (!userFlagAssignment.CanRemove())
throw new InvalidOperationException("Removing user flag assignment is denied");
return Unauthorized("Removing user flag assignment is denied");
var removingUser = Database.Users.Find(CurrentUser.UserId);
userFlagAssignment.OnRemove(Database, removingUser);
userFlagAssignment.OnRemove(Database);
Database.SaveChanges();
return Redirect($"{Url.Action(MVC.User.Show(userFlagAssignment.UserId))}#UserDetailTab-Flags");
@@ -6,6 +6,7 @@ using Disco.Services.Interop.ActiveDirectory;
using Disco.Services.Tasks;
using Disco.Services.Users.UserFlags;
using Disco.Services.Web;
using Disco.Web.Areas.API.Models.Shared;
using Disco.Web.Areas.Config.Models.UserFlag;
using Disco.Web.Extensions;
using System;
@@ -467,6 +468,24 @@ namespace Disco.Web.Areas.API.Controllers
return RedirectToAction(MVC.Config.Export.Create(savedExport.Id));
}
[DiscoAuthorize(Claims.Config.UserFlag.Configure)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Permission(int id, FlagPermissionModel model = null)
{
var userFlag = Database.UserFlags.Find(id);
if (userFlag == null)
return NotFound();
if (model == null || !model.IsOverride)
userFlag.Permissions = null;
else
userFlag.Permissions = model.ToFlagPermission(userFlag);
UserFlagService.Update(Database, userFlag);
return RedirectToAction(MVC.Config.UserFlag.Index(userFlag.Id));
}
#endregion
}
}
@@ -0,0 +1,21 @@
using Disco.Models.Repository;
using System.Collections.Generic;
namespace Disco.Web.Areas.API.Models.Shared
{
public class FlagPermissionModel
{
public bool IsOverride { get; set; }
public bool Inherit { get; set; }
public List<string> CanShow { get; set; }
public List<string> CanAssign { get; set; }
public List<string> CanEdit { get; set; }
public List<string> CanRemove { get; set; }
public FlagPermission ToFlagPermission(UserFlag userFlag)
=> FlagPermission.Create(userFlag, Inherit, CanShow, CanAssign, CanEdit, CanRemove);
public FlagPermission ToFlagPermission(DeviceFlag deviceFlag)
=> FlagPermission.Create(deviceFlag, Inherit, CanShow, CanAssign, CanEdit, CanRemove);
}
}
@@ -1,4 +1,5 @@
using Disco.Services.Interop.ActiveDirectory;
using Disco.Models.Repository;
using Disco.Services.Interop.ActiveDirectory;
namespace Disco.Web.Areas.API.Models.Shared
{
@@ -43,5 +44,19 @@ namespace Disco.Web.Areas.API.Models.Shared
return item;
}
public static SubjectDescriptorModel FromAuthorizationRole(int roleId, string roleName)
{
return new SubjectDescriptorModel()
{
Id = $"[{roleId}]",
Name = roleName,
Type = "role",
IsGroup = true
};
}
public static SubjectDescriptorModel FromAuthorizationRole(AuthorizationRole role)
=> FromAuthorizationRole(role.Id, role.Name);
}
}
@@ -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:
File diff suppressed because it is too large. Load diff
+17
View File
@@ -1960,6 +1960,23 @@ h1.Config_DocumentTemplates {
#Config_DeviceFlags_BulkAssign_AssignDialog.loading > form {
display: none;
}
#Config_Flag_Permissions #Config_Flag_Permissions_Inherit_Container {
margin: 5px 0;
}
#Config_Flag_Permissions .tableDataContainer {
min-height: 260px;
}
#Config_Flag_Permissions .tableDataContainer td i.remove {
float: right;
cursor: pointer;
visibility: hidden;
color: #e51400;
font-size: 1.4em;
opacity: 0.8;
}
#Config_Flag_Permissions .tableDataContainer td:hover i.remove {
visibility: visible;
}
#DocumentTemplate_BulkGenerate .actions {
padding-bottom: 0.5em;
text-align: right;
+27
View File
@@ -2354,6 +2354,33 @@ h1.Config_DocumentTemplates {
}
}
#Config_Flag_Permissions {
#Config_Flag_Permissions_Inherit_Container {
margin: 5px 0;
}
.tableDataContainer {
min-height: 260px;
td {
i.remove {
float: right;
cursor: pointer;
visibility: hidden;
color: @StatusRemove;
font-size: 1.4em;
opacity: .8;
}
}
td:hover {
i.remove {
visibility: visible;
}
}
}
}
#DocumentTemplate_BulkGenerate {
.actions {
padding-bottom: .5em;
+1 -1
View File
@@ -1 +1 @@
.tableData{border:solid 1px #f4f4f4;border-collapse:collapse;}.tableData>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff;}.tableData>tbody>tr:nth-child(odd)>td{background-color:hsl(0,0%,98.5%);}.tableData>thead>tr>th,.tableData>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4;}.tableData>tbody>tr:hover>td{background-color:hsl(0,0%,97.5%);}.tableData>tfoot>tr>th,.tableData>tfoot>tr>td{background-color:#f4f4f4;}.tableDataDark{border:solid 1px #d8d8d8;border-collapse:collapse;}.tableDataDark td{border:solid 1px #d8d8d8;background-color:#fff;}.tableDataDark th{background-color:#eee;border:solid 1px #d8d8d8;}.tableDataContainer{background-color:#fff;}.tableDataVertical{border:solid 1px #f4f4f4;border-collapse:collapse;}.tableDataVertical>tbody>tr:nth-child(odd){background-color:#f4f4f4;margin:0;padding:0;}.tableDataVertical>tbody>tr>th.name{width:170px;text-align:right;}.tableDataVertical table.sub>tbody>tr:not(:first-child)>th,.tableDataVertical table.sub>tbody>tr:not(:first-child)>td{border-top:1px dashed #aaa;}.tableDataVertical table.sub>tbody>tr>th{font-weight:normal;text-align:right;}.tableDataVertical table.sub>tbody>tr>th.name{text-align:right;}.icon16{display:inline-block;height:16px;width:16px;margin-left:2px;cursor:pointer;}.subtleUntilHover{-moz-opacity:.3;opacity:.3;}.subtleUntilHover:hover{-moz-opacity:1;opacity:1;}#updateAvailableContainer{float:right;border:1px dashed #ddd;background-color:#fff;font-size:.6em;line-height:1em;padding:10px 10px 4px 70px;text-align:right;height:50px;}#updateAvailableContainer i{position:absolute;display:block;height:64px;width:64px;vertical-align:middle;margin-left:-70px;font-size:50px;color:#e51400;}#updateAvailableContainer button{font-size:12px;margin-top:8px;}.Config_HideAdvanced .Config_HideAdvanced_Item{display:none;}.Config_LinkedGroup_Instance{margin:4px 0 8px 4px;padding:4px 0 4px 6px;border-left:4px solid #ccc;background-color:#fff;}.Config_LinkedGroup_Instance div.code{margin-left:2px;}#Config_LinkedGroup_Dialog h3{margin-bottom:6px;}#Config_LinkedGroup_Dialog table.input{margin-top:12px;}#Config_LinkedGroup_Dialog table.input th{text-align:right;}#expressionEditor #expressionEditorExceptionContainer{display:none;border:1px dashed #ff9696;background-color:#ffd8d8;margin:10px 0;padding:10px;}#expressionEditor #expressionEditorContainer{border:1px solid #1e6dab;background-color:#f4f4f4;height:100px;}.expressionTree span.dynatree-node span.dynatree-icon{background-image:url(data:image/png;base64,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);background-position-y:0;}.expressionTree span.dynatree-node.object span.dynatree-icon{background-position-x:0;}.expressionTree span.dynatree-node.parameter span.dynatree-icon{background-position-x:-16px;}.expressionTree span.dynatree-node.function span.dynatree-icon{background-position-x:-32px;}.expressionTree span.dynatreeLine truncated
.tableData{border:solid 1px #f4f4f4;border-collapse:collapse;}.tableData>tbody>tr>td{border:solid 1px #f4f4f4;background-color:#fff;}.tableData>tbody>tr:nth-child(odd)>td{background-color:hsl(0,0%,98.5%);}.tableData>thead>tr>th,.tableData>tbody>tr>th{background-color:#f4f4f4;border:solid 1px #f4f4f4;}.tableData>tbody>tr:hover>td{background-color:hsl(0,0%,97.5%);}.tableData>tfoot>tr>th,.tableData>tfoot>tr>td{background-color:#f4f4f4;}.tableDataDark{border:solid 1px #d8d8d8;border-collapse:collapse;}.tableDataDark td{border:solid 1px #d8d8d8;background-color:#fff;}.tableDataDark th{background-color:#eee;border:solid 1px #d8d8d8;}.tableDataContainer{background-color:#fff;}.tableDataVertical{border:solid 1px #f4f4f4;border-collapse:collapse;}.tableDataVertical>tbody>tr:nth-child(odd){background-color:#f4f4f4;margin:0;padding:0;}.tableDataVertical>tbody>tr>th.name{width:170px;text-align:right;}.tableDataVertical table.sub>tbody>tr:not(:first-child)>th,.tableDataVertical table.sub>tbody>tr:not(:first-child)>td{border-top:1px dashed #aaa;}.tableDataVertical table.sub>tbody>tr>th{font-weight:normal;text-align:right;}.tableDataVertical table.sub>tbody>tr>th.name{text-align:right;}.icon16{display:inline-block;height:16px;width:16px;margin-left:2px;cursor:pointer;}.subtleUntilHover{-moz-opacity:.3;opacity:.3;}.subtleUntilHover:hover{-moz-opacity:1;opacity:1;}#updateAvailableContainer{float:right;border:1px dashed #ddd;background-color:#fff;font-size:.6em;line-height:1em;padding:10px 10px 4px 70px;text-align:right;height:50px;}#updateAvailableContainer i{position:absolute;display:block;height:64px;width:64px;vertical-align:middle;margin-left:-70px;font-size:50px;color:#e51400;}#updateAvailableContainer button{font-size:12px;margin-top:8px;}.Config_HideAdvanced .Config_HideAdvanced_Item{display:none;}.Config_LinkedGroup_Instance{margin:4px 0 8px 4px;padding:4px 0 4px 6px;border-left:4px solid #ccc;background-color:#fff;}.Config_LinkedGroup_Instance div.code{margin-left:2px;}#Config_LinkedGroup_Dialog h3{margin-bottom:6px;}#Config_LinkedGroup_Dialog table.input{margin-top:12px;}#Config_LinkedGroup_Dialog table.input th{text-align:right;}#expressionEditor #expressionEditorExceptionContainer{display:none;border:1px dashed #ff9696;background-color:#ffd8d8;margin:10px 0;padding:10px;}#expressionEditor #expressionEditorContainer{border:1px solid #1e6dab;background-color:#f4f4f4;height:100px;}.expressionTree span.dynatree-node span.dynatree-icon{background-image:url(data:image/png;base64,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);background-position-y:0;}.expressionTree span.dynatree-node.object span.dynatree-icon{background-position-x:0;}.expressionTree span.dynatree-node.parameter span.dynatree-icon{background-position-x:-16px;}.expressionTree span.dynatree-node.function span.dynatree-icon{background-position-x:-32px;}.expressionTree span.dynatreeLine truncated
+2 -9
View File
@@ -235,6 +235,7 @@ namespace Disco.Web.Controllers
.Include(d => d.DeviceCertificates)
.Include(d => d.DeviceAttachments.Select(a => a.TechUser))
.Include(d => d.DeviceAttachments.Select(a => a.DocumentTemplate))
.Include(d => d.DeviceFlagAssignments.Select(a => a.DeviceFlag))
.Include(d => d.DeviceFlagAssignments.Select(a => a.AddedUser))
.Include(d => d.DeviceFlagAssignments.Select(a => a.RemovedUser))
.FirstOrDefault(d => d.SerialNumber == id);
@@ -311,15 +312,7 @@ namespace Disco.Web.Controllers
m.DeviceProfileWirelessProfileProviders = m.Device.DeviceProfile.GetWirelessProfileProviders().ToList();
}
if (Authorization.Has(Claims.Device.ShowFlagAssignments))
{
var usedFlags = m.Device.DeviceFlagAssignments
.Where(a => !a.RemovedDate.HasValue)
.Select(a => a.DeviceFlagId)
.Distinct().ToList();
m.AvailableDeviceFlags = DeviceFlagService.GetDeviceFlags().Where(f => !usedFlags.Contains(f.Id)).ToList();
}
m.AvailableDeviceFlags = DeviceFlagService.GetAvailableDeviceFlags(m.Device).ToList();
if (Authorization.Has(Claims.User.ShowDetails))
{
+2 -9
View File
@@ -61,6 +61,7 @@ namespace Disco.Web.Controllers
.Include(u => u.DeviceUserAssignments.Select(dua => dua.Device.DeviceDetails))
.Include(u => u.UserAttachments.Select(ua => ua.TechUser))
.Include(u => u.UserAttachments.Select(ua => ua.DocumentTemplate))
.Include(u => u.UserFlagAssignments.Select(ufa => ufa.UserFlag))
.Include(u => u.UserFlagAssignments.Select(ufa => ufa.AddedUser))
.Include(u => u.UserFlagAssignments.Select(ufa => ufa.RemovedUser))
.Include(u => u.UserDetails)
@@ -84,15 +85,7 @@ namespace Disco.Web.Controllers
m.Jobs.Fill(Database, Services.Searching.Search.BuildJobTableModel(Database).Where(j => j.UserId == id).OrderByDescending(j => j.Id), true);
}
if (Authorization.Has(Claims.User.ShowFlagAssignments))
{
var usedFlags = m.User.UserFlagAssignments
.Where(a => !a.RemovedDate.HasValue)
.Select(a => a.UserFlagId)
.Distinct().ToList();
m.AvailableUserFlags = UserFlagService.GetUserFlags().Where(f => !usedFlags.Contains(f.Id)).ToList();
}
m.AvailableUserFlags = UserFlagService.GetAvailableUserFlags(m.User).ToList();
try
{
+1
View File
@@ -227,6 +227,7 @@
<Compile Include="Areas\API\Models\Job\DeviceHeldLocationModel.cs" />
<Compile Include="Areas\API\Models\Shared\SubjectDescriptorModel.cs" />
<Compile Include="Areas\API\Models\System\DomainOrganisationalUnitsModel.cs" />
<Compile Include="Areas\API\Models\Shared\FlagPermissionModel.cs" />
<Compile Include="Areas\API\Views\_ViewStart.generated.cs">
<DependentUpon>_ViewStart.cshtml</DependentUpon>
<AutoGen>True</AutoGen>
@@ -143,8 +143,8 @@ namespace Disco.Web.Areas.API.Controllers
public class ActionParamsClass_AddDevice
{
public readonly string id = "id";
public readonly string DeviceSerialNumber = "DeviceSerialNumber";
public readonly string Comments = "Comments";
public readonly string deviceSerialNumber = "deviceSerialNumber";
public readonly string comments = "comments";
}
static readonly ActionParamsClass_RemoveDevice s_params_RemoveDevice = new ActionParamsClass_RemoveDevice();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -203,16 +203,16 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
partial void AddDeviceOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, string DeviceSerialNumber, string Comments);
partial void AddDeviceOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, string deviceSerialNumber, string comments);
[NonAction]
public override System.Web.Mvc.ActionResult AddDevice(int id, string DeviceSerialNumber, string Comments)
public override System.Web.Mvc.ActionResult AddDevice(int id, string deviceSerialNumber, string comments)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.AddDevice);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "DeviceSerialNumber", DeviceSerialNumber);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Comments", Comments);
AddDeviceOverride(callInfo, id, DeviceSerialNumber, Comments);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "deviceSerialNumber", deviceSerialNumber);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "comments", comments);
AddDeviceOverride(callInfo, id, deviceSerialNumber, comments);
return callInfo;
}
@@ -155,6 +155,12 @@ namespace Disco.Web.Areas.API.Controllers
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SaveExport);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Permission()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Permission);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public DeviceFlagController Actions { get { return MVC.API.DeviceFlag; } }
@@ -187,6 +193,7 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string Export = "Export";
public readonly string ExportRetrieve = "ExportRetrieve";
public readonly string SaveExport = "SaveExport";
public readonly string Permission = "Permission";
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -208,6 +215,7 @@ namespace Disco.Web.Areas.API.Controllers
public const string Export = "Export";
public const string ExportRetrieve = "ExportRetrieve";
public const string SaveExport = "SaveExport";
public const string Permission = "Permission";
}
@@ -367,6 +375,15 @@ namespace Disco.Web.Areas.API.Controllers
{
public readonly string model = "model";
}
static readonly ActionParamsClass_Permission s_params_Permission = new ActionParamsClass_Permission();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Permission PermissionParams { get { return s_params_Permission; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Permission
{
public readonly string id = "id";
public readonly string model = "model";
}
static readonly ViewsClass s_views = new ViewsClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ViewsClass Views { get { return s_views; } }
@@ -606,6 +623,19 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
[NonAction]
partial void PermissionOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, Disco.Web.Areas.API.Models.Shared.FlagPermissionModel model);
[NonAction]
public override System.Web.Mvc.ActionResult Permission(int id, Disco.Web.Areas.API.Models.Shared.FlagPermissionModel model)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Permission);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "model", model);
PermissionOverride(callInfo, id, model);
return callInfo;
}
}
}
@@ -308,6 +308,7 @@ namespace Disco.Web.Areas.API.Controllers
public class ActionParamsClass_SearchSubjects
{
public readonly string term = "term";
public readonly string includeAuthorizationRoles = "includeAuthorizationRoles";
}
static readonly ActionParamsClass_SearchGroupSubjects s_params_SearchGroupSubjects = new ActionParamsClass_SearchGroupSubjects();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -324,6 +325,7 @@ namespace Disco.Web.Areas.API.Controllers
public class ActionParamsClass_Subject
{
public readonly string Id = "Id";
public readonly string includeAuthorizationRoles = "includeAuthorizationRoles";
}
static readonly ActionParamsClass_SyncActiveDirectoryManagedGroup s_params_SyncActiveDirectoryManagedGroup = new ActionParamsClass_SyncActiveDirectoryManagedGroup();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -587,14 +589,15 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term);
partial void SearchSubjectsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string term, bool includeAuthorizationRoles);
[NonAction]
public override System.Web.Mvc.ActionResult SearchSubjects(string term)
public override System.Web.Mvc.ActionResult SearchSubjects(string term, bool includeAuthorizationRoles)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SearchSubjects);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "term", term);
SearchSubjectsOverride(callInfo, term);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "includeAuthorizationRoles", includeAuthorizationRoles);
SearchSubjectsOverride(callInfo, term, includeAuthorizationRoles);
return callInfo;
}
@@ -611,14 +614,15 @@ namespace Disco.Web.Areas.API.Controllers
}
[NonAction]
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id);
partial void SubjectOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string Id, bool includeAuthorizationRoles);
[NonAction]
public override System.Web.Mvc.ActionResult Subject(string Id)
public override System.Web.Mvc.ActionResult Subject(string Id, bool includeAuthorizationRoles)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Subject);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Id", Id);
SubjectOverride(callInfo, Id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "includeAuthorizationRoles", includeAuthorizationRoles);
SubjectOverride(callInfo, Id, includeAuthorizationRoles);
return callInfo;
}
@@ -155,6 +155,12 @@ namespace Disco.Web.Areas.API.Controllers
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.SaveExport);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Permission()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Permission);
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public UserFlagController Actions { get { return MVC.API.UserFlag; } }
@@ -187,6 +193,7 @@ namespace Disco.Web.Areas.API.Controllers
public readonly string Export = "Export";
public readonly string ExportRetrieve = "ExportRetrieve";
public readonly string SaveExport = "SaveExport";
public readonly string Permission = "Permission";
}
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
@@ -208,6 +215,7 @@ namespace Disco.Web.Areas.API.Controllers
public const string Export = "Export";
public const string ExportRetrieve = "ExportRetrieve";
public const string SaveExport = "SaveExport";
public const string Permission = "Permission";
}
@@ -367,6 +375,15 @@ namespace Disco.Web.Areas.API.Controllers
{
public readonly string model = "model";
}
static readonly ActionParamsClass_Permission s_params_Permission = new ActionParamsClass_Permission();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Permission PermissionParams { get { return s_params_Permission; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Permission
{
public readonly string id = "id";
public readonly string model = "model";
}
static readonly ViewsClass s_views = new ViewsClass();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ViewsClass Views { get { return s_views; } }
@@ -606,6 +623,19 @@ namespace Disco.Web.Areas.API.Controllers
return callInfo;
}
[NonAction]
partial void PermissionOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id, Disco.Web.Areas.API.Models.Shared.FlagPermissionModel model);
[NonAction]
public override System.Web.Mvc.ActionResult Permission(int id, Disco.Web.Areas.API.Models.Shared.FlagPermissionModel model)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Permission);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "model", model);
PermissionOverride(callInfo, id, model);
return callInfo;
}
}
}
@@ -1,15 +1,8 @@
@model Disco.Web.Models.Device.ShowModel
@using Disco.Services.Devices.DeviceFlags;
@{
Authorization.Require(Claims.Device.ShowFlagAssignments);
var hasRemove = Authorization.Has(Claims.Device.Actions.RemoveFlags);
var hasEdit = Authorization.Has(Claims.Device.Actions.EditFlags);
var hasDeviceFlagShow = Authorization.Has(Claims.Config.DeviceFlag.Show);
var activeAssignmentCount = Model.Device.DeviceFlagAssignments == null ? 0 : Model.Device.DeviceFlagAssignments.Count(a => !a.RemovedDate.HasValue);
var flagAssignments = Model.Device.DeviceFlagAssignments.Select(a => Tuple.Create(a, DeviceFlagService.GetDeviceFlag(a.DeviceFlagId))).ToList();
var flagAssignments = Model.Device.DeviceFlagAssignments.Select(a => Tuple.Create(a, DeviceFlagService.GetDeviceFlag(a.DeviceFlagId))).Where(a => a.Item2.permission.CanShow()).ToList();
var activeAssignmentCount = flagAssignments.Count(a => !a.Item1.RemovedDate.HasValue);
}
<div id="DeviceDetailTab-Flags" class="DevicePart">
@if (flagAssignments.Count > 0)
@@ -25,14 +18,14 @@
{
<tr data-deviceflagassignmentid="@fa.Item1.Id" data-flagassignmentaddeddate="@(fa.Item1.AddedDate.ToString("s"))" class="@(!fa.Item1.RemovedDate.HasValue ? "added" : "removed")">
<td class="name">
<i class="fa fa-@(fa.Item2.Icon) fa-fw fa-lg d-@(fa.Item2.IconColour)"></i>
@if (hasDeviceFlagShow)
<i class="fa fa-@(fa.Item2.flag.Icon) fa-fw fa-lg d-@(fa.Item2.flag.IconColour)"></i>
@if (Authorization.Has(Claims.Config.DeviceFlag.Show))
{
@Html.ActionLink(fa.Item2.Name, MVC.Config.DeviceFlag.Index(fa.Item2.Id))
@Html.ActionLink(fa.Item2.flag.Name, MVC.Config.DeviceFlag.Index(fa.Item2.flag.Id))
}
else
{
@fa.Item2.Name
@fa.Item2.flag.Name
}
</td>
<td class="added">
@@ -43,7 +36,7 @@
}
</td>
<td class="comments">
@if (hasEdit)
@if (fa.Item2.permission.CanEdit())
{
<div class="editable"><i class="fa fa-fw fa-edit" title="Edit Comments"></i></div>
}
@@ -77,6 +70,7 @@
<div id="Device_Show_Flags_Actions_Remove_Dialog" class="dialog" title="Remove this flag from the device?">
@using (Html.BeginForm(MVC.API.DeviceFlagAssignment.RemoveDevice()))
{
@Html.AntiForgeryToken()
<input id="Device_Show_Flags_Actions_Remove_Dialog_Id" type="hidden" name="id" value="" />
<p>
<i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?
@@ -86,6 +80,7 @@
<div id="Device_Show_Flags_Actions_EditComments_Dialog" class="dialog" title="Edit the Comments">
@using (Html.BeginForm(MVC.API.DeviceFlagAssignment.UpdateComments()))
{
@Html.AntiForgeryToken()
<input id="Device_Show_Flags_Actions_EditComments_Dialog_Id" type="hidden" name="id" value="" />
<input type="hidden" name="redirect" value="true" />
<h4>Comments:</h4>
@@ -52,15 +52,8 @@ namespace Disco.Web.Views.Device.DeviceParts
#line 3 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Authorization.Require(Claims.Device.ShowFlagAssignments);
var hasRemove = Authorization.Has(Claims.Device.Actions.RemoveFlags);
var hasEdit = Authorization.Has(Claims.Device.Actions.EditFlags);
var hasDeviceFlagShow = Authorization.Has(Claims.Config.DeviceFlag.Show);
var activeAssignmentCount = Model.Device.DeviceFlagAssignments == null ? 0 : Model.Device.DeviceFlagAssignments.Count(a => !a.RemovedDate.HasValue);
var flagAssignments = Model.Device.DeviceFlagAssignments.Select(a => Tuple.Create(a, DeviceFlagService.GetDeviceFlag(a.DeviceFlagId))).ToList();
var flagAssignments = Model.Device.DeviceFlagAssignments.Select(a => Tuple.Create(a, DeviceFlagService.GetDeviceFlag(a.DeviceFlagId))).Where(a => a.Item2.permission.CanShow()).ToList();
var activeAssignmentCount = flagAssignments.Count(a => !a.Item1.RemovedDate.HasValue);
#line default
@@ -74,13 +67,13 @@ WriteLiteral(" class=\"DevicePart\"");
WriteLiteral(">\r\n");
#line 15 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 8 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 15 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 8 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (flagAssignments.Count > 0)
{
@@ -110,13 +103,13 @@ WriteLiteral(" class=\"removed\"");
WriteLiteral(">Removed</th>\r\n </tr>\r\n");
#line 24 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 17 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 24 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 17 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
foreach (var fa in flagAssignments.OrderByDescending(a => a.Item1.AddedDate))
{
@@ -128,7 +121,7 @@ WriteLiteral(" <tr");
WriteLiteral(" data-deviceflagassignmentid=\"");
#line 26 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 19 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item1.Id);
@@ -139,7 +132,7 @@ WriteLiteral("\"");
WriteLiteral(" data-flagassignmentaddeddate=\"");
#line 26 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 19 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item1.AddedDate.ToString("s"));
@@ -147,14 +140,14 @@ WriteLiteral(" data-flagassignmentaddeddate=\"");
#line hidden
WriteLiteral("\"");
WriteAttribute("class", Tuple.Create(" class=\"", 1282), Tuple.Create("\"", 1345)
WriteAttribute("class", Tuple.Create(" class=\"", 967), Tuple.Create("\"", 1030)
#line 26 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1290), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? "added" : "removed"
#line 19 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 975), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? "added" : "removed"
#line default
#line hidden
, 1290), false)
, 975), false)
);
WriteLiteral(">\r\n <td");
@@ -163,53 +156,53 @@ WriteLiteral(" class=\"name\"");
WriteLiteral(">\r\n <i");
WriteAttribute("class", Tuple.Create(" class=\"", 1414), Tuple.Create("\"", 1481)
, Tuple.Create(Tuple.Create("", 1422), Tuple.Create("fa", 1422), true)
, Tuple.Create(Tuple.Create(" ", 1424), Tuple.Create("fa-", 1425), true)
WriteAttribute("class", Tuple.Create(" class=\"", 1099), Tuple.Create("\"", 1176)
, Tuple.Create(Tuple.Create("", 1107), Tuple.Create("fa", 1107), true)
, Tuple.Create(Tuple.Create(" ", 1109), Tuple.Create("fa-", 1110), true)
#line 28 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1428), Tuple.Create<System.Object, System.Int32>(fa.Item2.Icon
#line 21 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1113), Tuple.Create<System.Object, System.Int32>(fa.Item2.flag.Icon
#line default
#line hidden
, 1428), false)
, Tuple.Create(Tuple.Create(" ", 1444), Tuple.Create("fa-fw", 1445), true)
, Tuple.Create(Tuple.Create(" ", 1450), Tuple.Create("fa-lg", 1451), true)
, Tuple.Create(Tuple.Create(" ", 1456), Tuple.Create("d-", 1457), true)
, 1113), false)
, Tuple.Create(Tuple.Create(" ", 1134), Tuple.Create("fa-fw", 1135), true)
, Tuple.Create(Tuple.Create(" ", 1140), Tuple.Create("fa-lg", 1141), true)
, Tuple.Create(Tuple.Create(" ", 1146), Tuple.Create("d-", 1147), true)
#line 28 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1459), Tuple.Create<System.Object, System.Int32>(fa.Item2.IconColour
#line 21 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1149), Tuple.Create<System.Object, System.Int32>(fa.Item2.flag.IconColour
#line default
#line hidden
, 1459), false)
, 1149), false)
);
WriteLiteral("></i>\r\n");
#line 29 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 22 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 29 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (hasDeviceFlagShow)
#line 22 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (Authorization.Has(Claims.Config.DeviceFlag.Show))
{
#line default
#line hidden
#line 31 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(Html.ActionLink(fa.Item2.Name, MVC.Config.DeviceFlag.Index(fa.Item2.Id)));
#line 24 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(Html.ActionLink(fa.Item2.flag.Name, MVC.Config.DeviceFlag.Index(fa.Item2.flag.Id)));
#line default
#line hidden
#line 31 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 24 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
else
@@ -219,14 +212,14 @@ WriteLiteral("></i>\r\n");
#line default
#line hidden
#line 35 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item2.Name);
#line 28 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item2.flag.Name);
#line default
#line hidden
#line 35 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 28 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -242,7 +235,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 39 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 32 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(fa.Item1.AddedDate, fa.Item1.AddedUser));
@@ -251,13 +244,13 @@ WriteLiteral(" ");
WriteLiteral("\r\n");
#line 40 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 33 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 40 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 33 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (fa.Item1.OnAssignmentExpressionResult != null)
{
@@ -271,7 +264,7 @@ WriteLiteral(" class=\"expressionResult\"");
WriteLiteral(">");
#line 42 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 35 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item1.OnAssignmentExpressionResult);
@@ -280,7 +273,7 @@ WriteLiteral(">");
WriteLiteral("</div>\r\n");
#line 43 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 36 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -293,14 +286,14 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">\r\n");
#line 46 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 39 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 46 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (hasEdit)
#line 39 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (fa.Item2.permission.CanEdit())
{
@@ -319,7 +312,7 @@ WriteLiteral(" title=\"Edit Comments\"");
WriteLiteral("></i></div>\r\n");
#line 49 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 42 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -328,7 +321,7 @@ WriteLiteral("></i></div>\r\n");
WriteLiteral(" ");
#line 50 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 43 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (fa.Item1.Comments == null)
{
@@ -342,7 +335,7 @@ WriteLiteral(" class=\"comments smallMessage\"");
WriteLiteral(">[no comments]</div>\r\n");
#line 53 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 46 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
else
{
@@ -357,7 +350,7 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">");
#line 56 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 49 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item1.Comments.ToHtmlComment());
@@ -372,7 +365,7 @@ WriteLiteral(" class=\"commentsRaw\"");
WriteLiteral(">");
#line 57 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 50 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item1.Comments);
@@ -381,7 +374,7 @@ WriteLiteral(">");
WriteLiteral("</div>\r\n");
#line 58 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 51 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -389,27 +382,27 @@ WriteLiteral("</div>\r\n");
#line hidden
WriteLiteral(" </td>\r\n <td");
WriteAttribute("class", Tuple.Create(" class=\"", 3000), Tuple.Create("\"", 3063)
, Tuple.Create(Tuple.Create("", 3008), Tuple.Create("removed", 3008), true)
WriteAttribute("class", Tuple.Create(" class=\"", 2763), Tuple.Create("\"", 2826)
, Tuple.Create(Tuple.Create("", 2771), Tuple.Create("removed", 2771), true)
#line 60 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 3015), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? " na" : null
#line 53 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 2778), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? " na" : null
#line default
#line hidden
, 3015), false)
, 2778), false)
);
WriteLiteral(">\r\n");
#line 61 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 54 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 61 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 54 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (fa.Item1.RemovedDate.HasValue)
{
@@ -417,14 +410,14 @@ WriteLiteral(">\r\n");
#line default
#line hidden
#line 63 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 56 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(fa.Item1.RemovedDate.Value, fa.Item1.RemovedUser));
#line default
#line hidden
#line 63 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 56 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
if (fa.Item1.OnUnassignmentExpressionResult != null)
{
@@ -439,7 +432,7 @@ WriteLiteral(" class=\"expressionResult\"");
WriteLiteral(">");
#line 66 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 59 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(fa.Item1.OnUnassignmentExpressionResult);
@@ -448,7 +441,7 @@ WriteLiteral(">");
WriteLiteral("</div>\r\n");
#line 67 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 60 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
}
else if (fa.Item1.CanRemove())
@@ -466,7 +459,7 @@ WriteLiteral(" class=\"button small remove\"");
WriteLiteral(">Remove</a>\r\n");
#line 72 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 65 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -475,7 +468,7 @@ WriteLiteral(">Remove</a>\r\n");
WriteLiteral(" </td>\r\n </tr>\r\n");
#line 75 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 68 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -494,17 +487,31 @@ WriteLiteral(" title=\"Remove this flag from the device?\"");
WriteLiteral(">\r\n");
#line 78 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 71 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 78 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 71 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
using (Html.BeginForm(MVC.API.DeviceFlagAssignment.RemoveDevice()))
{
#line default
#line hidden
#line 73 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
#line 73 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
WriteLiteral(" <input");
@@ -526,7 +533,7 @@ WriteLiteral(" class=\"fa fa-exclamation-triangle fa-lg\"");
WriteLiteral("></i>&nbsp;Are you sure?\r\n </p>\r\n");
#line 84 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 78 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -545,17 +552,31 @@ WriteLiteral(" title=\"Edit the Comments\"");
WriteLiteral(">\r\n");
#line 87 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 81 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
#line 87 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 81 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
using (Html.BeginForm(MVC.API.DeviceFlagAssignment.UpdateComments()))
{
#line default
#line hidden
#line 83 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
#line 83 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line default
#line hidden
WriteLiteral(" <input");
@@ -593,7 +614,7 @@ WriteLiteral(" class=\"block\"");
WriteLiteral("></textarea>\r\n </p>\r\n");
#line 95 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 90 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -651,7 +672,7 @@ WriteLiteral(">\r\n $(function () {\r\n var deviceFlag
"eturn false;\r\n });\r\n });\r\n </script>\r\n");
#line 174 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 169 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
else
{
@@ -666,7 +687,7 @@ WriteLiteral(" class=\"none\"");
WriteLiteral(">This device has no associated flags</div>\r\n");
#line 178 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 173 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
}
@@ -676,7 +697,7 @@ WriteLiteral(" <script>\r\n $(\'#DeviceDetailTabItems\').append(\'<li>
"ilTab-Flags\">Flags [");
#line 180 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
#line 175 "..\..\Views\Device\DeviceParts\_Flags.cshtml"
Write(activeAssignmentCount);
@@ -239,17 +239,20 @@
<div id="Device_Show_User_EmailAddress" title="Email Address"><a href="mailto:@(Model.Device.AssignedUser.EmailAddress)" data-clipboard="@assignedUser.DisplayName &lt;@assignedUser.EmailAddress&gt;">@assignedUser.EmailAddress</a></div>
}
}
@if (Authorization.Has(Claims.User.ShowFlagAssignments))
@if (assignedUser.UserFlagAssignments.CanShowAny())
{
<div id="Device_Show_User_Flags">
@foreach (var flag in assignedUser.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw d-@(flag.Item2.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
}
}
<script type="text/javascript">
$(function () {
@@ -765,12 +768,13 @@
});
</script>
}
@if (Model.Device.CanAddDeviceFlags() && Model.AvailableDeviceFlags != null && Model.AvailableDeviceFlags.Count > 0)
@if (Model.AvailableDeviceFlags != null && Model.AvailableDeviceFlags.Count > 0)
{
@Html.ActionLinkSmallButton("Add Flag", MVC.API.DeviceFlagAssignment.AddDevice(), "Device_Show_Details_Actions_AddFlag_Button")
<button id="Device_Show_Details_Actions_AddFlag_Button" type="button" class="button small">Add Flag</button>
<div id="Device_Show_Details_Actions_AddFlag_Dialog" class="dialog" title="Add Device Flag">
@using (Html.BeginForm(MVC.API.DeviceFlagAssignment.AddDevice()))
{
@Html.AntiForgeryToken()
<input id="Device_Show_Details_Actions_AddFlag_Dialog_Id" type="hidden" name="id" />
<input id="Device_Show_Details_Actions_AddFlag_Dialog_DeviceSerialNumber" type="hidden" name="DeviceSerialNumber" value="@Model.Device.SerialNumber" />
<div class="flagPicker">
@@ -794,7 +798,6 @@
$(function () {
const button = $('#Device_Show_Details_Actions_AddFlag_Button');
let buttonDialog = null;
const buttonLink = button.attr('href');
let flagPicker = null;
let flagAddId = null;
@@ -814,9 +817,7 @@
flagAddComments.focus().select();
}
button.attr('href', '#').click(function (e) {
e.preventDefault();
button.click(function (e) {
if (!buttonDialog) {
buttonDialog = $('#Device_Show_Details_Actions_AddFlag_Dialog');
buttonDialog.dialog({
@@ -831,10 +832,9 @@
},
"Add Flag": function () {
if (!!flagAddId.val()) {
const $this = $(this);
$this.dialog("disable");
$this.dialog("option", "buttons", null);
buttonDialog.find('form').submit();
buttonDialog
.dialog("option", "buttons", null)
.find('form').submit();
} else {
alert('Select a Device Flag');
}
@@ -868,7 +868,6 @@
$('#Device_Show_Details_Actions_AddFlag_Dialog_Filter').val('');
buttonDialog.dialog('open');
return false;
});
});
</script>
File diff suppressed because it is too large. Load diff
+11 -8
View File
@@ -19,17 +19,20 @@
});
</script>
</div>
@if (Authorization.Has(Claims.Device.ShowFlagAssignments))
@if (Model.Device.DeviceFlagAssignments.CanShowAny())
{
<div id="Device_Show_Flags">
@foreach (var flag in Model.Device.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw fa-lg d-@(flag.Item2.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser)</span>
</span>
</i>
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw fa-lg d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser)</span>
</span>
</i>
}
}
</div>
<script type="text/javascript">
@@ -116,7 +119,7 @@
{
@Html.Partial(MVC.Device.Views.DeviceParts._Resources, Model)
}
@if (Authorization.Has(Claims.Device.ShowFlagAssignments))
@if (Authorization.Has(Claims.Device.ShowFlagAssignments) || Model.Device.DeviceFlagAssignments.CanShowAny())
{
@Html.Partial(MVC.Device.Views.DeviceParts._Flags, Model)
}
+58 -55
View File
@@ -122,7 +122,7 @@ WriteLiteral(">\r\n $(function () {\r\n $(\'#Device_Sh
#line hidden
#line 22 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowFlagAssignments))
if (Model.Device.DeviceFlagAssignments.CanShowAny())
{
@@ -144,48 +144,50 @@ WriteLiteral(">\r\n");
#line 25 "..\..\Views\Device\Show.cshtml"
foreach (var flag in Model.Device.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
if (flag.Item2.permission.CanShow())
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" <i");
WriteAttribute("class", Tuple.Create(" class=\"", 1178), Tuple.Create("\"", 1254)
, Tuple.Create(Tuple.Create("", 1186), Tuple.Create("flag", 1186), true)
, Tuple.Create(Tuple.Create(" ", 1190), Tuple.Create("fa", 1191), true)
, Tuple.Create(Tuple.Create(" ", 1193), Tuple.Create("fa-", 1194), true)
WriteAttribute("class", Tuple.Create(" class=\"", 1250), Tuple.Create("\"", 1336)
, Tuple.Create(Tuple.Create("", 1258), Tuple.Create("flag", 1258), true)
, Tuple.Create(Tuple.Create(" ", 1262), Tuple.Create("fa", 1263), true)
, Tuple.Create(Tuple.Create(" ", 1265), Tuple.Create("fa-", 1266), true)
#line 27 "..\..\Views\Device\Show.cshtml"
, Tuple.Create(Tuple.Create("", 1197), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon
#line 29 "..\..\Views\Device\Show.cshtml"
, Tuple.Create(Tuple.Create("", 1269), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.Icon
#line default
#line hidden
, 1197), false)
, Tuple.Create(Tuple.Create(" ", 1215), Tuple.Create("fa-fw", 1216), true)
, Tuple.Create(Tuple.Create(" ", 1221), Tuple.Create("fa-lg", 1222), true)
, Tuple.Create(Tuple.Create(" ", 1227), Tuple.Create("d-", 1228), true)
, 1269), false)
, Tuple.Create(Tuple.Create(" ", 1292), Tuple.Create("fa-fw", 1293), true)
, Tuple.Create(Tuple.Create(" ", 1298), Tuple.Create("fa-lg", 1299), true)
, Tuple.Create(Tuple.Create(" ", 1304), Tuple.Create("d-", 1305), true)
#line 27 "..\..\Views\Device\Show.cshtml"
, Tuple.Create(Tuple.Create("", 1230), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour
#line 29 "..\..\Views\Device\Show.cshtml"
, Tuple.Create(Tuple.Create("", 1307), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.IconColour
#line default
#line hidden
, 1230), false)
, 1307), false)
);
WriteLiteral(">\r\n <span");
WriteLiteral(">\r\n <span");
WriteLiteral(" class=\"details\"");
WriteLiteral(">\r\n <span");
WriteLiteral(">\r\n <span");
WriteLiteral(" class=\"name\"");
WriteLiteral(">");
#line 29 "..\..\Views\Device\Show.cshtml"
Write(flag.Item2.Name);
#line 31 "..\..\Views\Device\Show.cshtml"
Write(flag.Item2.flag.Name);
#line default
@@ -193,9 +195,9 @@ WriteLiteral(">");
WriteLiteral("</span>");
#line 29 "..\..\Views\Device\Show.cshtml"
if (flag.Item1.Comments != null)
{
#line 31 "..\..\Views\Device\Show.cshtml"
if (flag.Item1.Comments != null)
{
#line default
#line hidden
@@ -206,8 +208,8 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">");
#line 30 "..\..\Views\Device\Show.cshtml"
Write(flag.Item1.Comments.ToHtmlComment());
#line 32 "..\..\Views\Device\Show.cshtml"
Write(flag.Item1.Comments.ToHtmlComment());
#line default
@@ -215,8 +217,8 @@ WriteLiteral(">");
WriteLiteral("</span>");
#line 30 "..\..\Views\Device\Show.cshtml"
}
#line 32 "..\..\Views\Device\Show.cshtml"
}
#line default
#line hidden
@@ -227,16 +229,17 @@ WriteLiteral(" class=\"added\"");
WriteLiteral(">");
#line 30 "..\..\Views\Device\Show.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser));
#line 32 "..\..\Views\Device\Show.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser));
#line default
#line hidden
WriteLiteral("</span>\r\n </span>\r\n </i>\r\n");
WriteLiteral("</span>\r\n </span>\r\n </i>\r\n");
#line 33 "..\..\Views\Device\Show.cshtml"
#line 35 "..\..\Views\Device\Show.cshtml"
}
}
@@ -282,7 +285,7 @@ WriteLiteral(@">
");
#line 66 "..\..\Views\Device\Show.cshtml"
#line 69 "..\..\Views\Device\Show.cshtml"
}
@@ -291,7 +294,7 @@ WriteLiteral(@">
WriteLiteral(" ");
#line 67 "..\..\Views\Device\Show.cshtml"
#line 70 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._Subject, Model));
@@ -332,13 +335,13 @@ WriteLiteral(" id=\"DeviceDetailTabItems\"");
WriteLiteral("></ul>\r\n");
#line 103 "..\..\Views\Device\Show.cshtml"
#line 106 "..\..\Views\Device\Show.cshtml"
#line default
#line hidden
#line 103 "..\..\Views\Device\Show.cshtml"
#line 106 "..\..\Views\Device\Show.cshtml"
if (Authorization.HasAny(Claims.Device.ShowComments, Claims.Device.ShowJobs))
{
@@ -346,14 +349,14 @@ WriteLiteral("></ul>\r\n");
#line default
#line hidden
#line 105 "..\..\Views\Device\Show.cshtml"
#line 108 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._CommentsAndJobs, Model));
#line default
#line hidden
#line 105 "..\..\Views\Device\Show.cshtml"
#line 108 "..\..\Views\Device\Show.cshtml"
}
@@ -363,7 +366,7 @@ WriteLiteral("></ul>\r\n");
WriteLiteral(" ");
#line 107 "..\..\Views\Device\Show.cshtml"
#line 110 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowDetails))
{
@@ -371,14 +374,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 109 "..\..\Views\Device\Show.cshtml"
#line 112 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._Details, Model));
#line default
#line hidden
#line 109 "..\..\Views\Device\Show.cshtml"
#line 112 "..\..\Views\Device\Show.cshtml"
}
@@ -388,7 +391,7 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 111 "..\..\Views\Device\Show.cshtml"
#line 114 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowAssignmentHistory))
{
@@ -396,14 +399,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 113 "..\..\Views\Device\Show.cshtml"
#line 116 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._AssignmentHistory, Model));
#line default
#line hidden
#line 113 "..\..\Views\Device\Show.cshtml"
#line 116 "..\..\Views\Device\Show.cshtml"
}
@@ -413,7 +416,7 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 115 "..\..\Views\Device\Show.cshtml"
#line 118 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowAttachments))
{
@@ -421,14 +424,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 117 "..\..\Views\Device\Show.cshtml"
#line 120 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._Resources, Model));
#line default
#line hidden
#line 117 "..\..\Views\Device\Show.cshtml"
#line 120 "..\..\Views\Device\Show.cshtml"
}
@@ -438,22 +441,22 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 119 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowFlagAssignments))
#line 122 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowFlagAssignments) || Model.Device.DeviceFlagAssignments.CanShowAny())
{
#line default
#line hidden
#line 121 "..\..\Views\Device\Show.cshtml"
#line 124 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._Flags, Model));
#line default
#line hidden
#line 121 "..\..\Views\Device\Show.cshtml"
#line 124 "..\..\Views\Device\Show.cshtml"
}
@@ -463,7 +466,7 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 123 "..\..\Views\Device\Show.cshtml"
#line 126 "..\..\Views\Device\Show.cshtml"
if (Authorization.Has(Claims.Device.ShowCertificates))
{
@@ -471,14 +474,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 125 "..\..\Views\Device\Show.cshtml"
#line 128 "..\..\Views\Device\Show.cshtml"
Write(Html.Partial(MVC.Device.Views.DeviceParts._Certificates, Model));
#line default
#line hidden
#line 125 "..\..\Views\Device\Show.cshtml"
#line 128 "..\..\Views\Device\Show.cshtml"
}
@@ -488,13 +491,13 @@ WriteLiteral(" ");
WriteLiteral(" </div>\r\n");
#line 128 "..\..\Views\Device\Show.cshtml"
#line 131 "..\..\Views\Device\Show.cshtml"
#line default
#line hidden
#line 128 "..\..\Views\Device\Show.cshtml"
#line 131 "..\..\Views\Device\Show.cshtml"
if (requiresLive)
{
@@ -550,7 +553,7 @@ WriteLiteral(" <script>\r\n $(function () {\r\n
" </script>\r\n");
#line 197 "..\..\Views\Device\Show.cshtml"
#line 200 "..\..\Views\Device\Show.cshtml"
}
+41 -41
View File
@@ -32,22 +32,22 @@
{@Html.ActionLink(item.Id, MVC.Device.Show(item.Id))}
else
{@item.Id}
@if (Authorization.Has(Claims.Device.ShowFlagAssignments))
@if (item.DeviceFlagAssignments.CanShowAny())
{
@if (item.DeviceFlagAssignments != null && item.DeviceFlagAssignments.Count > 0)
{
<div class="flags">
@foreach (var flag in item.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
<div class="flags">
@foreach (var flag in item.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
@if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw d-@(flag.Item2.IconColour)">
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
}
</div>
}
}
</div>
}
</td>
<td>
@@ -117,43 +117,43 @@
</tbody>
</table>
<script type="text/javascript">
$(function () {
var userTable = $('table.deviceTable');
$(function () {
var userTable = $('table.deviceTable');
userTable.each(function () {
var $this = $(this);
userTable.each(function () {
var $this = $(this);
if (!$this.data('deviceTable_Flags')) {
$this.tooltip({
items: 'i.flag',
content: function () {
var $this = $(this);
return $this.children('.details').html();
},
tooltipClass: 'FlagAssignment_Tooltip',
position: {
my: "right top",
at: "right bottom",
collision: "flipfit flip"
},
hade: {
effect: ''
},
close: function (e, ui) {
ui.tooltip.hover(
function () {
$(this).stop(true).fadeTo(100, 1);
if (!$this.data('deviceTable_Flags')) {
$this.tooltip({
items: 'i.flag',
content: function () {
var $this = $(this);
return $this.children('.details').html();
},
function () {
$(this).fadeOut(100, function () { $(this).remove(); });
});
tooltipClass: 'FlagAssignment_Tooltip',
position: {
my: "right top",
at: "right bottom",
collision: "flipfit flip"
},
hade: {
effect: ''
},
close: function (e, ui) {
ui.tooltip.hover(
function () {
$(this).stop(true).fadeTo(100, 1);
},
function () {
$(this).fadeOut(100, function () { $(this).remove(); });
});
}
});
$this.data('deviceTable_Flags', true)
}
});
$this.data('deviceTable_Flags', true)
}
});
});
});
</script>
}
else
@@ -175,35 +175,35 @@ WriteLiteral(" ");
#line 35 "..\..\Views\Device\_DeviceTable.cshtml"
if (Authorization.Has(Claims.Device.ShowFlagAssignments))
if (item.DeviceFlagAssignments.CanShowAny())
{
#line default
#line hidden
#line 37 "..\..\Views\Device\_DeviceTable.cshtml"
if (item.DeviceFlagAssignments != null && item.DeviceFlagAssignments.Count > 0)
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" <div");
WriteLiteral(" class=\"flags\"");
WriteLiteral(">\r\n");
#line 40 "..\..\Views\Device\_DeviceTable.cshtml"
#line 38 "..\..\Views\Device\_DeviceTable.cshtml"
#line default
#line hidden
#line 38 "..\..\Views\Device\_DeviceTable.cshtml"
foreach (var flag in item.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
#line default
#line hidden
#line 40 "..\..\Views\Device\_DeviceTable.cshtml"
foreach (var flag in item.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
if (flag.Item2.permission.CanShow())
{
@@ -211,26 +211,26 @@ WriteLiteral(">\r\n");
#line hidden
WriteLiteral(" <i");
WriteAttribute("class", Tuple.Create(" class=\"", 1953), Tuple.Create("\"", 2023)
, Tuple.Create(Tuple.Create("", 1961), Tuple.Create("flag", 1961), true)
, Tuple.Create(Tuple.Create(" ", 1965), Tuple.Create("fa", 1966), true)
, Tuple.Create(Tuple.Create(" ", 1968), Tuple.Create("fa-", 1969), true)
WriteAttribute("class", Tuple.Create(" class=\"", 1901), Tuple.Create("\"", 1981)
, Tuple.Create(Tuple.Create("", 1909), Tuple.Create("flag", 1909), true)
, Tuple.Create(Tuple.Create(" ", 1913), Tuple.Create("fa", 1914), true)
, Tuple.Create(Tuple.Create(" ", 1916), Tuple.Create("fa-", 1917), true)
#line 42 "..\..\Views\Device\_DeviceTable.cshtml"
, Tuple.Create(Tuple.Create("", 1972), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon
, Tuple.Create(Tuple.Create("", 1920), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.Icon
#line default
#line hidden
, 1972), false)
, Tuple.Create(Tuple.Create(" ", 1990), Tuple.Create("fa-fw", 1991), true)
, Tuple.Create(Tuple.Create(" ", 1996), Tuple.Create("d-", 1997), true)
, 1920), false)
, Tuple.Create(Tuple.Create(" ", 1943), Tuple.Create("fa-fw", 1944), true)
, Tuple.Create(Tuple.Create(" ", 1949), Tuple.Create("d-", 1950), true)
#line 42 "..\..\Views\Device\_DeviceTable.cshtml"
, Tuple.Create(Tuple.Create("", 1999), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour
, Tuple.Create(Tuple.Create("", 1952), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.IconColour
#line default
#line hidden
, 1999), false)
, 1952), false)
);
WriteLiteral(">\r\n <span");
@@ -245,7 +245,7 @@ WriteLiteral(">");
#line 44 "..\..\Views\Device\_DeviceTable.cshtml"
Write(flag.Item2.Name);
Write(flag.Item2.flag.Name);
#line default
@@ -254,7 +254,7 @@ WriteLiteral("</span>");
#line 44 "..\..\Views\Device\_DeviceTable.cshtml"
if (flag.Item1.Comments != null)
if (flag.Item1.Comments != null)
{
#line default
@@ -302,17 +302,18 @@ WriteLiteral("</span>\r\n </span>
#line default
#line hidden
WriteLiteral("\r\n </div>\r\n");
#line 48 "..\..\Views\Device\_DeviceTable.cshtml"
}
#line 50 "..\..\Views\Device\_DeviceTable.cshtml"
}
#line default
#line hidden
WriteLiteral(" </div>\r\n");
#line 50 "..\..\Views\Device\_DeviceTable.cshtml"
#line 51 "..\..\Views\Device\_DeviceTable.cshtml"
}
@@ -627,46 +628,27 @@ WriteLiteral(" <script");
WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(@">
$(function () {
var userTable = $('table.deviceTable');
userTable.each(function () {
var $this = $(this);
if (!$this.data('deviceTable_Flags')) {
$this.tooltip({
items: 'i.flag',
content: function () {
var $this = $(this);
return $this.children('.details').html();
},
tooltipClass: 'FlagAssignment_Tooltip',
position: {
my: ""right top"",
at: ""right bottom"",
collision: ""flipfit flip""
},
hade: {
effect: ''
},
close: function (e, ui) {
ui.tooltip.hover(
function () {
$(this).stop(true).fadeTo(100, 1);
},
function () {
$(this).fadeOut(100, function () { $(this).remove(); });
});
}
});
$this.data('deviceTable_Flags', true)
}
});
});
</script>
");
WriteLiteral(">\r\n $(function () {\r\n var userTable = $(\'table.deviceTa" +
"ble\');\r\n\r\n userTable.each(function () {\r\n var " +
"$this = $(this);\r\n\r\n if (!$this.data(\'deviceTable_Flags\')) {\r" +
"\n $this.tooltip({\r\n items: \'i." +
"flag\',\r\n content: function () {\r\n " +
" var $this = $(this);\r\n return $this.c" +
"hildren(\'.details\').html();\r\n },\r\n " +
" tooltipClass: \'FlagAssignment_Tooltip\',\r\n po" +
"sition: {\r\n my: \"right top\",\r\n " +
" at: \"right bottom\",\r\n collision: \"fl" +
"ipfit flip\"\r\n },\r\n hade: {" +
"\r\n effect: \'\'\r\n },\r\n " +
" close: function (e, ui) {\r\n " +
" ui.tooltip.hover(\r\n function () {\r\n " +
" $(this).stop(true).fadeTo(100, 1);\r\n " +
" },\r\n function () {" +
"\r\n $(this).fadeOut(100, function () { $(t" +
"his).remove(); });\r\n });\r\n " +
" }\r\n });\r\n\r\n $this.data(\'d" +
"eviceTable_Flags\', true)\r\n }\r\n });\r\n " +
" });\r\n </script>\r\n");
#line 158 "..\..\Views\Device\_DeviceTable.cshtml"
+20 -16
View File
@@ -256,19 +256,20 @@
</div>
}
}
@if (Authorization.Has(Claims.Device.ShowFlagAssignments) &&
Model.Job.Device.DeviceFlagAssignments != null &&
Model.Job.Device.DeviceFlagAssignments.Any(a => !a.RemovedDate.HasValue))
@if (Model.Job.Device.DeviceFlagAssignments.CanShowAny())
{
<div id="Job_Show_Device_Flags">
@foreach (var flag in Model.Job.Device.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw d-@(flag.Item2.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
}
}
<script type="text/javascript">
$(function () {
@@ -506,17 +507,20 @@
if (!string.IsNullOrWhiteSpace(Model.Job.User.EmailAddress))
{<div id="Job_Show_User_EmailAddress" title="Email Address">Email: <a href="mailto:@(Model.Job.User.EmailAddress)" data-clipboard="@Model.Job.User.DisplayName &lt;@Model.Job.User.EmailAddress&gt;">@Model.Job.User.EmailAddress</a></div>}
}
@if (Authorization.Has(Claims.User.ShowFlagAssignments))
@if (Model.Job.User.UserFlagAssignments.CanShowAny())
{
<div id="Job_Show_User_Flags">
@foreach (var flag in Model.Job.User.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw d-@(flag.Item2.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
}
}
<script type="text/javascript">
$(function () {
File diff suppressed because it is too large. Load diff
+11 -8
View File
@@ -13,17 +13,20 @@
}
}
<div id="User_Show" data-userid="@Model.User.UserId">
@if (Authorization.Has(Claims.User.ShowFlagAssignments))
@if (Model.User.UserFlagAssignments.CanShowAny())
{
<div id="User_Show_Flags">
@foreach (var flag in Model.User.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw fa-lg d-@(flag.Item2.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser)</span>
</span>
</i>
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw fa-lg d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser)</span>
</span>
</i>
}
}
</div>
<script type="text/javascript">
@@ -106,7 +109,7 @@
{
@Html.Partial(MVC.User.Views.UserParts._Resources, Model)
}
@if (Authorization.Has(Claims.User.ShowFlagAssignments))
@if (Authorization.Has(Claims.User.ShowFlagAssignments) || Model.User.UserFlagAssignments.CanShowAny())
{
@Html.Partial(MVC.User.Views.UserParts._Flags, Model)
}
+55 -52
View File
@@ -91,7 +91,7 @@ WriteLiteral(">\r\n");
#line hidden
#line 16 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowFlagAssignments))
if (Model.User.UserFlagAssignments.CanShowAny())
{
@@ -113,48 +113,50 @@ WriteLiteral(">\r\n");
#line 19 "..\..\Views\User\Show.cshtml"
foreach (var flag in Model.User.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{
if (flag.Item2.permission.CanShow())
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" <i");
WriteAttribute("class", Tuple.Create(" class=\"", 867), Tuple.Create("\"", 943)
, Tuple.Create(Tuple.Create("", 875), Tuple.Create("flag", 875), true)
, Tuple.Create(Tuple.Create(" ", 879), Tuple.Create("fa", 880), true)
, Tuple.Create(Tuple.Create(" ", 882), Tuple.Create("fa-", 883), true)
WriteAttribute("class", Tuple.Create(" class=\"", 937), Tuple.Create("\"", 1023)
, Tuple.Create(Tuple.Create("", 945), Tuple.Create("flag", 945), true)
, Tuple.Create(Tuple.Create(" ", 949), Tuple.Create("fa", 950), true)
, Tuple.Create(Tuple.Create(" ", 952), Tuple.Create("fa-", 953), true)
#line 21 "..\..\Views\User\Show.cshtml"
, Tuple.Create(Tuple.Create("", 886), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon
#line 23 "..\..\Views\User\Show.cshtml"
, Tuple.Create(Tuple.Create("", 956), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.Icon
#line default
#line hidden
, 886), false)
, Tuple.Create(Tuple.Create(" ", 904), Tuple.Create("fa-fw", 905), true)
, Tuple.Create(Tuple.Create(" ", 910), Tuple.Create("fa-lg", 911), true)
, Tuple.Create(Tuple.Create(" ", 916), Tuple.Create("d-", 917), true)
, 956), false)
, Tuple.Create(Tuple.Create(" ", 979), Tuple.Create("fa-fw", 980), true)
, Tuple.Create(Tuple.Create(" ", 985), Tuple.Create("fa-lg", 986), true)
, Tuple.Create(Tuple.Create(" ", 991), Tuple.Create("d-", 992), true)
#line 21 "..\..\Views\User\Show.cshtml"
, Tuple.Create(Tuple.Create("", 919), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour
#line 23 "..\..\Views\User\Show.cshtml"
, Tuple.Create(Tuple.Create("", 994), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.IconColour
#line default
#line hidden
, 919), false)
, 994), false)
);
WriteLiteral(">\r\n <span");
WriteLiteral(">\r\n <span");
WriteLiteral(" class=\"details\"");
WriteLiteral(">\r\n <span");
WriteLiteral(">\r\n <span");
WriteLiteral(" class=\"name\"");
WriteLiteral(">");
#line 23 "..\..\Views\User\Show.cshtml"
Write(flag.Item2.Name);
#line 25 "..\..\Views\User\Show.cshtml"
Write(flag.Item2.flag.Name);
#line default
@@ -162,9 +164,9 @@ WriteLiteral(">");
WriteLiteral("</span>");
#line 23 "..\..\Views\User\Show.cshtml"
if (flag.Item1.Comments != null)
{
#line 25 "..\..\Views\User\Show.cshtml"
if (flag.Item1.Comments != null)
{
#line default
#line hidden
@@ -175,8 +177,8 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">");
#line 24 "..\..\Views\User\Show.cshtml"
Write(flag.Item1.Comments.ToHtmlComment());
#line 26 "..\..\Views\User\Show.cshtml"
Write(flag.Item1.Comments.ToHtmlComment());
#line default
@@ -184,8 +186,8 @@ WriteLiteral(">");
WriteLiteral("</span>");
#line 24 "..\..\Views\User\Show.cshtml"
}
#line 26 "..\..\Views\User\Show.cshtml"
}
#line default
#line hidden
@@ -196,16 +198,17 @@ WriteLiteral(" class=\"added\"");
WriteLiteral(">");
#line 24 "..\..\Views\User\Show.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser));
#line 26 "..\..\Views\User\Show.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser));
#line default
#line hidden
WriteLiteral("</span>\r\n </span>\r\n </i>\r\n");
WriteLiteral("</span>\r\n </span>\r\n </i>\r\n");
#line 27 "..\..\Views\User\Show.cshtml"
#line 29 "..\..\Views\User\Show.cshtml"
}
}
@@ -251,7 +254,7 @@ WriteLiteral(@">
");
#line 60 "..\..\Views\User\Show.cshtml"
#line 63 "..\..\Views\User\Show.cshtml"
}
@@ -260,7 +263,7 @@ WriteLiteral(@">
WriteLiteral(" ");
#line 61 "..\..\Views\User\Show.cshtml"
#line 64 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Subject, Model));
@@ -300,13 +303,13 @@ WriteLiteral(" id=\"UserDetailTabItems\"");
WriteLiteral("></ul>\r\n");
#line 97 "..\..\Views\User\Show.cshtml"
#line 100 "..\..\Views\User\Show.cshtml"
#line default
#line hidden
#line 97 "..\..\Views\User\Show.cshtml"
#line 100 "..\..\Views\User\Show.cshtml"
if (Authorization.HasAny(Claims.User.ShowComments, Claims.User.ShowJobs))
{
@@ -314,14 +317,14 @@ WriteLiteral("></ul>\r\n");
#line default
#line hidden
#line 99 "..\..\Views\User\Show.cshtml"
#line 102 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._CommentsAndJobs, Model));
#line default
#line hidden
#line 99 "..\..\Views\User\Show.cshtml"
#line 102 "..\..\Views\User\Show.cshtml"
}
@@ -331,7 +334,7 @@ WriteLiteral("></ul>\r\n");
WriteLiteral(" ");
#line 101 "..\..\Views\User\Show.cshtml"
#line 104 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowAssignmentHistory))
{
@@ -339,14 +342,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 103 "..\..\Views\User\Show.cshtml"
#line 106 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._AssignmentHistory, Model));
#line default
#line hidden
#line 103 "..\..\Views\User\Show.cshtml"
#line 106 "..\..\Views\User\Show.cshtml"
}
@@ -356,7 +359,7 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 105 "..\..\Views\User\Show.cshtml"
#line 108 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowAttachments))
{
@@ -364,14 +367,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 107 "..\..\Views\User\Show.cshtml"
#line 110 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Resources, Model));
#line default
#line hidden
#line 107 "..\..\Views\User\Show.cshtml"
#line 110 "..\..\Views\User\Show.cshtml"
}
@@ -381,22 +384,22 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 109 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowFlagAssignments))
#line 112 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowFlagAssignments) || Model.User.UserFlagAssignments.CanShowAny())
{
#line default
#line hidden
#line 111 "..\..\Views\User\Show.cshtml"
#line 114 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Flags, Model));
#line default
#line hidden
#line 111 "..\..\Views\User\Show.cshtml"
#line 114 "..\..\Views\User\Show.cshtml"
}
@@ -406,7 +409,7 @@ WriteLiteral(" ");
WriteLiteral(" ");
#line 113 "..\..\Views\User\Show.cshtml"
#line 116 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowAuthorization))
{
@@ -414,14 +417,14 @@ WriteLiteral(" ");
#line default
#line hidden
#line 115 "..\..\Views\User\Show.cshtml"
#line 118 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Authorization, Model));
#line default
#line hidden
#line 115 "..\..\Views\User\Show.cshtml"
#line 118 "..\..\Views\User\Show.cshtml"
}
@@ -431,13 +434,13 @@ WriteLiteral(" ");
WriteLiteral(" </div>\r\n");
#line 118 "..\..\Views\User\Show.cshtml"
#line 121 "..\..\Views\User\Show.cshtml"
#line default
#line hidden
#line 118 "..\..\Views\User\Show.cshtml"
#line 121 "..\..\Views\User\Show.cshtml"
if (requiresLive)
{
@@ -492,7 +495,7 @@ WriteLiteral(" <script>\r\n $(function () {\r\n
" });\r\n });\r\n </script>\r\n");
#line 187 "..\..\Views\User\Show.cshtml"
#line 190 "..\..\Views\User\Show.cshtml"
}
+9 -14
View File
@@ -1,15 +1,8 @@
@model Disco.Web.Models.User.ShowModel
@using Disco.Services.Users.UserFlags;
@{
Authorization.Require(Claims.User.ShowFlagAssignments);
var hasRemove = Authorization.Has(Claims.User.Actions.RemoveFlags);
var hasEdit = Authorization.Has(Claims.User.Actions.EditFlags);
var hasUserFlagShow = Authorization.Has(Claims.Config.UserFlag.Show);
var activeAssignmentCount = Model.User.UserFlagAssignments == null ? 0 : Model.User.UserFlagAssignments.Count(a => !a.RemovedDate.HasValue);
var flagAssignments = Model.User.UserFlagAssignments.Select(a => Tuple.Create(a, UserFlagService.GetUserFlag(a.UserFlagId))).ToList();
var flagAssignments = Model.User.UserFlagAssignments.Select(a => Tuple.Create(a, UserFlagService.GetUserFlag(a.UserFlagId))).Where(g => g.Item2.permission.CanShow()).ToList();
var activeAssignmentCount = flagAssignments.Count(a => !a.Item1.RemovedDate.HasValue);
}
<div id="UserDetailTab-Flags" class="UserPart">
@if (flagAssignments.Count > 0)
@@ -25,14 +18,14 @@
{
<tr data-userflagassignmentid="@fa.Item1.Id" data-flagassignmentaddeddate="@(fa.Item1.AddedDate.ToString("s"))" class="@(!fa.Item1.RemovedDate.HasValue ? "added" : "removed")">
<td class="name">
<i class="fa fa-@(fa.Item2.Icon) fa-fw fa-lg d-@(fa.Item2.IconColour)"></i>
@if (hasUserFlagShow)
<i class="fa fa-@(fa.Item2.flag.Icon) fa-fw fa-lg d-@(fa.Item2.flag.IconColour)"></i>
@if (Authorization.Has(Claims.Config.UserFlag.Show))
{
@Html.ActionLink(fa.Item2.Name, MVC.Config.UserFlag.Index(fa.Item2.Id))
@Html.ActionLink(fa.Item2.flag.Name, MVC.Config.UserFlag.Index(fa.Item2.flag.Id))
}
else
{
@fa.Item2.Name
@fa.Item2.flag.Name
}
</td>
<td class="added">
@@ -43,7 +36,7 @@
}
</td>
<td class="comments">
@if (hasEdit)
@if (fa.Item2.permission.CanEdit())
{
<div class="editable"><i class="fa fa-fw fa-edit" title="Edit Comments"></i></div>
}
@@ -77,6 +70,7 @@
<div id="User_Show_Flags_Actions_Remove_Dialog" class="dialog" title="Remove this flag from the user?">
@using (Html.BeginForm(MVC.API.UserFlagAssignment.RemoveUser()))
{
@Html.AntiForgeryToken()
<input id="User_Show_Flags_Actions_Remove_Dialog_Id" type="hidden" name="id" value="" />
<p>
<i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?
@@ -86,6 +80,7 @@
<div id="User_Show_Flags_Actions_EditComments_Dialog" class="dialog" title="Edit the Comments">
@using (Html.BeginForm(MVC.API.UserFlagAssignment.UpdateComments()))
{
@Html.AntiForgeryToken()
<input id="User_Show_Flags_Actions_EditComments_Dialog_Id" type="hidden" name="id" value="" />
<input type="hidden" name="redirect" value="true" />
<h4>Comments:</h4>
@@ -52,15 +52,8 @@ namespace Disco.Web.Views.User.UserParts
#line 3 "..\..\Views\User\UserParts\_Flags.cshtml"
Authorization.Require(Claims.User.ShowFlagAssignments);
var hasRemove = Authorization.Has(Claims.User.Actions.RemoveFlags);
var hasEdit = Authorization.Has(Claims.User.Actions.EditFlags);
var hasUserFlagShow = Authorization.Has(Claims.Config.UserFlag.Show);
var activeAssignmentCount = Model.User.UserFlagAssignments == null ? 0 : Model.User.UserFlagAssignments.Count(a => !a.RemovedDate.HasValue);
var flagAssignments = Model.User.UserFlagAssignments.Select(a => Tuple.Create(a, UserFlagService.GetUserFlag(a.UserFlagId))).ToList();
var flagAssignments = Model.User.UserFlagAssignments.Select(a => Tuple.Create(a, UserFlagService.GetUserFlag(a.UserFlagId))).Where(g => g.Item2.permission.CanShow()).ToList();
var activeAssignmentCount = flagAssignments.Count(a => !a.Item1.RemovedDate.HasValue);
#line default
@@ -74,13 +67,13 @@ WriteLiteral(" class=\"UserPart\"");
WriteLiteral(">\r\n");
#line 15 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 8 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 15 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 8 "..\..\Views\User\UserParts\_Flags.cshtml"
if (flagAssignments.Count > 0)
{
@@ -110,13 +103,13 @@ WriteLiteral(" class=\"removed\"");
WriteLiteral(">Removed</th>\r\n </tr>\r\n");
#line 24 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 17 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 24 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 17 "..\..\Views\User\UserParts\_Flags.cshtml"
foreach (var fa in flagAssignments.OrderByDescending(a => a.Item1.AddedDate))
{
@@ -128,7 +121,7 @@ WriteLiteral(" <tr");
WriteLiteral(" data-userflagassignmentid=\"");
#line 26 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 19 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item1.Id);
@@ -139,7 +132,7 @@ WriteLiteral("\"");
WriteLiteral(" data-flagassignmentaddeddate=\"");
#line 26 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 19 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item1.AddedDate.ToString("s"));
@@ -147,14 +140,14 @@ WriteLiteral(" data-flagassignmentaddeddate=\"");
#line hidden
WriteLiteral("\"");
WriteAttribute("class", Tuple.Create(" class=\"", 1240), Tuple.Create("\"", 1303)
WriteAttribute("class", Tuple.Create(" class=\"", 943), Tuple.Create("\"", 1006)
#line 26 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1248), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? "added" : "removed"
#line 19 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 951), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? "added" : "removed"
#line default
#line hidden
, 1248), false)
, 951), false)
);
WriteLiteral(">\r\n <td");
@@ -163,53 +156,53 @@ WriteLiteral(" class=\"name\"");
WriteLiteral(">\r\n <i");
WriteAttribute("class", Tuple.Create(" class=\"", 1372), Tuple.Create("\"", 1439)
, Tuple.Create(Tuple.Create("", 1380), Tuple.Create("fa", 1380), true)
, Tuple.Create(Tuple.Create(" ", 1382), Tuple.Create("fa-", 1383), true)
WriteAttribute("class", Tuple.Create(" class=\"", 1075), Tuple.Create("\"", 1152)
, Tuple.Create(Tuple.Create("", 1083), Tuple.Create("fa", 1083), true)
, Tuple.Create(Tuple.Create(" ", 1085), Tuple.Create("fa-", 1086), true)
#line 28 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1386), Tuple.Create<System.Object, System.Int32>(fa.Item2.Icon
#line 21 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1089), Tuple.Create<System.Object, System.Int32>(fa.Item2.flag.Icon
#line default
#line hidden
, 1386), false)
, Tuple.Create(Tuple.Create(" ", 1402), Tuple.Create("fa-fw", 1403), true)
, Tuple.Create(Tuple.Create(" ", 1408), Tuple.Create("fa-lg", 1409), true)
, Tuple.Create(Tuple.Create(" ", 1414), Tuple.Create("d-", 1415), true)
, 1089), false)
, Tuple.Create(Tuple.Create(" ", 1110), Tuple.Create("fa-fw", 1111), true)
, Tuple.Create(Tuple.Create(" ", 1116), Tuple.Create("fa-lg", 1117), true)
, Tuple.Create(Tuple.Create(" ", 1122), Tuple.Create("d-", 1123), true)
#line 28 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1417), Tuple.Create<System.Object, System.Int32>(fa.Item2.IconColour
#line 21 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 1125), Tuple.Create<System.Object, System.Int32>(fa.Item2.flag.IconColour
#line default
#line hidden
, 1417), false)
, 1125), false)
);
WriteLiteral("></i>\r\n");
#line 29 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 22 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 29 "..\..\Views\User\UserParts\_Flags.cshtml"
if (hasUserFlagShow)
#line 22 "..\..\Views\User\UserParts\_Flags.cshtml"
if (Authorization.Has(Claims.Config.UserFlag.Show))
{
#line default
#line hidden
#line 31 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(Html.ActionLink(fa.Item2.Name, MVC.Config.UserFlag.Index(fa.Item2.Id)));
#line 24 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(Html.ActionLink(fa.Item2.flag.Name, MVC.Config.UserFlag.Index(fa.Item2.flag.Id)));
#line default
#line hidden
#line 31 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 24 "..\..\Views\User\UserParts\_Flags.cshtml"
}
else
@@ -219,14 +212,14 @@ WriteLiteral("></i>\r\n");
#line default
#line hidden
#line 35 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item2.Name);
#line 28 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item2.flag.Name);
#line default
#line hidden
#line 35 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 28 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -242,7 +235,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 39 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 32 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(fa.Item1.AddedDate, fa.Item1.AddedUser));
@@ -251,13 +244,13 @@ WriteLiteral(" ");
WriteLiteral("\r\n");
#line 40 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 33 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 40 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 33 "..\..\Views\User\UserParts\_Flags.cshtml"
if (fa.Item1.OnAssignmentExpressionResult != null)
{
@@ -271,7 +264,7 @@ WriteLiteral(" class=\"expressionResult\"");
WriteLiteral(">");
#line 42 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 35 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item1.OnAssignmentExpressionResult);
@@ -280,7 +273,7 @@ WriteLiteral(">");
WriteLiteral("</div>\r\n");
#line 43 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 36 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -293,14 +286,14 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">\r\n");
#line 46 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 39 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 46 "..\..\Views\User\UserParts\_Flags.cshtml"
if (hasEdit)
#line 39 "..\..\Views\User\UserParts\_Flags.cshtml"
if (fa.Item2.permission.CanEdit())
{
@@ -319,7 +312,7 @@ WriteLiteral(" title=\"Edit Comments\"");
WriteLiteral("></i></div>\r\n");
#line 49 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 42 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -328,7 +321,7 @@ WriteLiteral("></i></div>\r\n");
WriteLiteral(" ");
#line 50 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 43 "..\..\Views\User\UserParts\_Flags.cshtml"
if (fa.Item1.Comments == null)
{
@@ -342,7 +335,7 @@ WriteLiteral(" class=\"comments smallMessage\"");
WriteLiteral(">[no comments]</div>\r\n");
#line 53 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 46 "..\..\Views\User\UserParts\_Flags.cshtml"
}
else
{
@@ -357,7 +350,7 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">");
#line 56 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 49 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item1.Comments.ToHtmlComment());
@@ -372,7 +365,7 @@ WriteLiteral(" class=\"commentsRaw\"");
WriteLiteral(">");
#line 57 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 50 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item1.Comments);
@@ -381,7 +374,7 @@ WriteLiteral(">");
WriteLiteral("</div>\r\n");
#line 58 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 51 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -389,27 +382,27 @@ WriteLiteral("</div>\r\n");
#line hidden
WriteLiteral(" </td>\r\n <td");
WriteAttribute("class", Tuple.Create(" class=\"", 2954), Tuple.Create("\"", 3017)
, Tuple.Create(Tuple.Create("", 2962), Tuple.Create("removed", 2962), true)
WriteAttribute("class", Tuple.Create(" class=\"", 2735), Tuple.Create("\"", 2798)
, Tuple.Create(Tuple.Create("", 2743), Tuple.Create("removed", 2743), true)
#line 60 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 2969), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? " na" : null
#line 53 "..\..\Views\User\UserParts\_Flags.cshtml"
, Tuple.Create(Tuple.Create("", 2750), Tuple.Create<System.Object, System.Int32>(!fa.Item1.RemovedDate.HasValue ? " na" : null
#line default
#line hidden
, 2969), false)
, 2750), false)
);
WriteLiteral(">\r\n");
#line 61 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 54 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 61 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 54 "..\..\Views\User\UserParts\_Flags.cshtml"
if (fa.Item1.RemovedDate.HasValue)
{
@@ -417,14 +410,14 @@ WriteLiteral(">\r\n");
#line default
#line hidden
#line 63 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 56 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(fa.Item1.RemovedDate.Value, fa.Item1.RemovedUser));
#line default
#line hidden
#line 63 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 56 "..\..\Views\User\UserParts\_Flags.cshtml"
if (fa.Item1.OnUnassignmentExpressionResult != null)
{
@@ -439,7 +432,7 @@ WriteLiteral(" class=\"expressionResult\"");
WriteLiteral(">");
#line 66 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 59 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(fa.Item1.OnUnassignmentExpressionResult);
@@ -448,7 +441,7 @@ WriteLiteral(">");
WriteLiteral("</div>\r\n");
#line 67 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 60 "..\..\Views\User\UserParts\_Flags.cshtml"
}
}
else if (fa.Item1.CanRemove())
@@ -466,7 +459,7 @@ WriteLiteral(" class=\"button small remove\"");
WriteLiteral(">Remove</a>\r\n");
#line 72 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 65 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -475,7 +468,7 @@ WriteLiteral(">Remove</a>\r\n");
WriteLiteral(" </td>\r\n </tr>\r\n");
#line 75 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 68 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -494,17 +487,31 @@ WriteLiteral(" title=\"Remove this flag from the user?\"");
WriteLiteral(">\r\n");
#line 78 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 71 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 78 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 71 "..\..\Views\User\UserParts\_Flags.cshtml"
using (Html.BeginForm(MVC.API.UserFlagAssignment.RemoveUser()))
{
#line default
#line hidden
#line 73 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
#line 73 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
WriteLiteral(" <input");
@@ -526,7 +533,7 @@ WriteLiteral(" class=\"fa fa-exclamation-triangle fa-lg\"");
WriteLiteral("></i>&nbsp;Are you sure?\r\n </p>\r\n");
#line 84 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 78 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -545,17 +552,31 @@ WriteLiteral(" title=\"Edit the Comments\"");
WriteLiteral(">\r\n");
#line 87 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 81 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
#line 87 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 81 "..\..\Views\User\UserParts\_Flags.cshtml"
using (Html.BeginForm(MVC.API.UserFlagAssignment.UpdateComments()))
{
#line default
#line hidden
#line 83 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
#line 83 "..\..\Views\User\UserParts\_Flags.cshtml"
#line default
#line hidden
WriteLiteral(" <input");
@@ -593,7 +614,7 @@ WriteLiteral(" class=\"block\"");
WriteLiteral("></textarea>\r\n </p>\r\n");
#line 95 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 90 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -651,7 +672,7 @@ WriteLiteral(">\r\n $(function () {\r\n var userFlags
";\r\n });\r\n </script>\r\n");
#line 174 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 169 "..\..\Views\User\UserParts\_Flags.cshtml"
}
else
{
@@ -666,7 +687,7 @@ WriteLiteral(" class=\"none\"");
WriteLiteral(">This user has no associated flags</div>\r\n");
#line 178 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 173 "..\..\Views\User\UserParts\_Flags.cshtml"
}
@@ -676,7 +697,7 @@ WriteLiteral(" <script>\r\n $(\'#UserDetailTabItems\').append(\'<li><a
"b-Flags\">Flags [");
#line 180 "..\..\Views\User\UserParts\_Flags.cshtml"
#line 175 "..\..\Views\User\UserParts\_Flags.cshtml"
Write(activeAssignmentCount);
+17 -16
View File
@@ -236,12 +236,13 @@
</script>
}
}
@if (Model.User.CanAddUserFlags() && Model.AvailableUserFlags != null && Model.AvailableUserFlags.Count > 0)
@if (Model.AvailableUserFlags != null && Model.AvailableUserFlags.Count > 0)
{
@Html.ActionLinkSmallButton("Add Flag", MVC.API.UserFlagAssignment.AddUser(), "User_Show_Details_Actions_AddFlag_Button")
<button id="User_Show_Details_Actions_AddFlag_Button" type="button" class="button small">Add Flag</button>
<div id="User_Show_Details_Actions_AddFlag_Dialog" class="dialog" title="Add User Flag">
@using (Html.BeginForm(MVC.API.UserFlagAssignment.AddUser()))
{
@Html.AntiForgeryToken()
<input id="User_Show_Details_Actions_AddFlag_Dialog_Id" type="hidden" name="id" />
<input id="User_Show_Details_Actions_AddFlag_Dialog_UserId" type="hidden" name="UserId" value="@Model.User.UserId" />
<div class="flagPicker">
@@ -265,7 +266,6 @@
$(function () {
const button = $('#User_Show_Details_Actions_AddFlag_Button');
let buttonDialog = null;
const buttonLink = button.attr('href');
let flagPicker = null;
let flagAddId = null;
@@ -285,7 +285,7 @@
flagAddComments.focus().select();
}
button.attr('href', '#').click(function (e) {
button.click(function (e) {
e.preventDefault();
if (!buttonDialog) {
@@ -302,10 +302,9 @@
},
"Add Flag": function () {
if (!!flagAddId.val()) {
const $this = $(this);
$this.dialog("disable");
$this.dialog("option", "buttons", null);
buttonDialog.find('form').submit();
buttonDialog
.dialog("option", "buttons", null)
.find('form').submit();
} else {
alert('Select a User Flag');
}
@@ -437,20 +436,22 @@
<span class="User_Show_AssignedDevices_CurrentAssignment_Assigned">@CommonHelpers.FriendlyDate(assignment.AssignedDate)</span>
</td>
</tr>
@if (Authorization.Has(Claims.Device.ShowFlagAssignments) &&
assignment.Device.DeviceFlagAssignments.Any(a => a.RemovedDate.HasValue))
@if (assignment.Device.DeviceFlagAssignments.CanShowAny())
{
<tr>
<td colspan="2">
<div class="User_Show_Assigned_Devices_CurrentAssignment_Flags">
@foreach (var flag in assignment.Device.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw d-@(flag.Item2.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
}
}
<script type="text/javascript">
$(function () {
@@ -893,26 +893,22 @@ WriteLiteral(" ");
#line 239 "..\..\Views\User\UserParts\_Subject.cshtml"
if (Model.User.CanAddUserFlags() && Model.AvailableUserFlags != null && Model.AvailableUserFlags.Count > 0)
if (Model.AvailableUserFlags != null && Model.AvailableUserFlags.Count > 0)
{
#line default
#line hidden
WriteLiteral(" <button");
#line 241 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(Html.ActionLinkSmallButton("Add Flag", MVC.API.UserFlagAssignment.AddUser(), "User_Show_Details_Actions_AddFlag_Button"));
WriteLiteral(" id=\"User_Show_Details_Actions_AddFlag_Button\"");
WriteLiteral(" type=\"button\"");
#line default
#line hidden
WriteLiteral(" class=\"button small\"");
#line 241 "..\..\Views\User\UserParts\_Subject.cshtml"
WriteLiteral(">Add Flag</button>\r\n");
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" id=\"User_Show_Details_Actions_AddFlag_Dialog\"");
@@ -935,6 +931,20 @@ WriteLiteral(">\r\n");
{
#line default
#line hidden
#line 245 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
#line 245 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
WriteLiteral(" <input");
@@ -955,14 +965,14 @@ WriteLiteral(" type=\"hidden\"");
WriteLiteral(" name=\"UserId\"");
WriteAttribute("value", Tuple.Create(" value=\"", 16008), Tuple.Create("\"", 16034)
WriteAttribute("value", Tuple.Create(" value=\"", 16023), Tuple.Create("\"", 16049)
#line 246 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 16016), Tuple.Create<System.Object, System.Int32>(Model.User.UserId
#line 247 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 16031), Tuple.Create<System.Object, System.Int32>(Model.User.UserId
#line default
#line hidden
, 16016), false)
, 16031), false)
);
WriteLiteral(" />\r\n");
@@ -984,13 +994,13 @@ WriteLiteral(" autocomplete=\"off\"");
WriteLiteral(" />\r\n");
#line 249 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 250 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 249 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 250 "..\..\Views\User\UserParts\_Subject.cshtml"
foreach (var userFlag in Model.AvailableUserFlags.OrderBy(jq => jq.Name))
{
@@ -1004,7 +1014,7 @@ WriteLiteral(" class=\"flag\"");
WriteLiteral(" data-userflagid=\"");
#line 251 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 252 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(userFlag.Id);
@@ -1015,7 +1025,7 @@ WriteLiteral("\"");
WriteLiteral(" data-userflagname=\"");
#line 251 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 252 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(userFlag.Name);
@@ -1025,32 +1035,32 @@ WriteLiteral("\"");
WriteLiteral(">\r\n <i");
WriteAttribute("class", Tuple.Create(" class=\"", 16599), Tuple.Create("\"", 16666)
, Tuple.Create(Tuple.Create("", 16607), Tuple.Create("fa", 16607), true)
, Tuple.Create(Tuple.Create(" ", 16609), Tuple.Create("fa-", 16610), true)
WriteAttribute("class", Tuple.Create(" class=\"", 16614), Tuple.Create("\"", 16681)
, Tuple.Create(Tuple.Create("", 16622), Tuple.Create("fa", 16622), true)
, Tuple.Create(Tuple.Create(" ", 16624), Tuple.Create("fa-", 16625), true)
#line 252 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 16613), Tuple.Create<System.Object, System.Int32>(userFlag.Icon
#line 253 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 16628), Tuple.Create<System.Object, System.Int32>(userFlag.Icon
#line default
#line hidden
, 16613), false)
, Tuple.Create(Tuple.Create(" ", 16629), Tuple.Create("fa-fw", 16630), true)
, Tuple.Create(Tuple.Create(" ", 16635), Tuple.Create("fa-lg", 16636), true)
, Tuple.Create(Tuple.Create(" ", 16641), Tuple.Create("d-", 16642), true)
, 16628), false)
, Tuple.Create(Tuple.Create(" ", 16644), Tuple.Create("fa-fw", 16645), true)
, Tuple.Create(Tuple.Create(" ", 16650), Tuple.Create("fa-lg", 16651), true)
, Tuple.Create(Tuple.Create(" ", 16656), Tuple.Create("d-", 16657), true)
#line 252 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 16644), Tuple.Create<System.Object, System.Int32>(userFlag.IconColour
#line 253 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 16659), Tuple.Create<System.Object, System.Int32>(userFlag.IconColour
#line default
#line hidden
, 16644), false)
, 16659), false)
);
WriteLiteral("></i>");
#line 252 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 253 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(userFlag.Name);
@@ -1059,7 +1069,7 @@ WriteLiteral("></i>");
WriteLiteral("\r\n </div>\r\n");
#line 254 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 255 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1083,7 +1093,7 @@ WriteLiteral("></textarea>\r\n </div>\r\n
" </div>\r\n");
#line 262 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 263 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1097,72 +1107,69 @@ WriteLiteral(" type=\"text/javascript\"");
WriteLiteral(">\r\n $(function () {\r\n " +
" const button = $(\'#User_Show_Details_Actions_AddFlag_Button\');\r\n " +
" let buttonDialog = null;\r\n " +
" const buttonLink = button.attr(\'href\');\r\n\r\n " +
" let flagPicker = null;\r\n let flagAddI" +
"d = null;\r\n let flagAddComments = null;\r\n " +
" let details = null;\r\n\r\n " +
" function flagSelected() {\r\n co" +
"nst flag = $(this);\r\n\r\n flagPicker.childr" +
"en().removeClass(\'selected\');\r\n flag.addC" +
"lass(\'selected\');\r\n\r\n flagAddId.val(flag." +
"attr(\'data-userflagid\'));\r\n\r\n details.sho" +
"w();\r\n\r\n flagAddComments.focus().select()" +
";\r\n }\r\n\r\n " +
"button.attr(\'href\', \'#\').click(function (e) {\r\n " +
" e.preventDefault();\r\n\r\n if (!butto" +
"nDialog) {\r\n buttonDialog = $(\'#User_" +
"Show_Details_Actions_AddFlag_Dialog\');\r\n " +
" buttonDialog.dialog({\r\n width" +
": 600,\r\n height: 410,\r\n " +
" resizable: false,\r\n " +
" modal: true,\r\n " +
" autoOpen: false,\r\n buttons" +
": {\r\n Cancel: function () {\r\n" +
" $(this).dialog(\"close\");" +
"\r\n },\r\n " +
" \"Add Flag\": function () {\r\n " +
" if (!!flagAddId.val()) {\r\n " +
" const $this = $(this);\r\n " +
" $this.dialog(\"disable\");\r\n " +
" $this.dialog(\"option\", \"buttons" +
"\", null);\r\n buttonDia" +
"log.find(\'form\').submit();\r\n " +
" } else {\r\n alert(" +
"\'Select a User Flag\');\r\n " +
"}\r\n }\r\n " +
" }\r\n });\r\n\r\n" +
" flagAddId = $(\'#User_Show_Details_Ac" +
"tions_AddFlag_Dialog_Id\');\r\n flagAddC" +
"omments = buttonDialog.find(\'#User_Show_Details_Actions_AddFlag_Dialog_Comments\'" +
");\r\n flagPicker = buttonDialog.find(\'" +
".flagPicker\');\r\n details = buttonDial" +
"og.find(\'.details\');\r\n\r\n $(\'#User_Sho" +
"w_Details_Actions_AddFlag_Dialog_Filter\').on(\'keyup\', function (e) {\r\n " +
" const filter = $(e.currentTarget).val().to" +
"LowerCase();\r\n if (filter) {\r\n " +
" flagPicker.children(\'div.flag\')" +
".each(function () {\r\n con" +
"st $this = $(this);\r\n if " +
"($this.attr(\'data-userflagname\').toLowerCase().indexOf(filter) >= 0) {\r\n " +
" $this.css(\'display\', \'block\'" +
");\r\n } else {\r\n " +
" $this.css(\'display\', \'none\');\r" +
"\n }\r\n " +
" });\r\n " +
" } else {\r\n flagPicker.ch" +
"ildren(\'div.flag\').each(function () { $(this).css(\'display\', \'block\'); });\r\n " +
" }\r\n " +
" });\r\n\r\n flagPicker.on(\'cli" +
"ck\', \'div.flag\', flagSelected);\r\n }\r\n\r\n " +
" $(\'#User_Show_Details_Actions_AddFlag_Dial" +
"og_Filter\').val(\'\');\r\n buttonDialog.dialo" +
"g(\'open\');\r\n return false;\r\n " +
" });\r\n });\r\n " +
" </script>\r\n");
" let buttonDialog = null;\r\n\r\n " +
" let flagPicker = null;\r\n let flagA" +
"ddId = null;\r\n let flagAddComments = null;\r\n " +
" let details = null;\r\n\r\n " +
" function flagSelected() {\r\n " +
" const flag = $(this);\r\n\r\n flagPicker.chi" +
"ldren().removeClass(\'selected\');\r\n flag.a" +
"ddClass(\'selected\');\r\n\r\n flagAddId.val(fl" +
"ag.attr(\'data-userflagid\'));\r\n\r\n details." +
"show();\r\n\r\n flagAddComments.focus().selec" +
"t();\r\n }\r\n\r\n " +
" button.click(function (e) {\r\n e.preven" +
"tDefault();\r\n\r\n if (!buttonDialog) {\r\n " +
" buttonDialog = $(\'#User_Show_Details_Ac" +
"tions_AddFlag_Dialog\');\r\n buttonDialo" +
"g.dialog({\r\n width: 600,\r\n " +
" height: 410,\r\n " +
" resizable: false,\r\n " +
" modal: true,\r\n autoOpen" +
": false,\r\n buttons: {\r\n " +
" Cancel: function () {\r\n " +
" $(this).dialog(\"close\");\r\n " +
" },\r\n " +
" \"Add Flag\": function () {\r\n " +
" if (!!flagAddId.val()) {\r\n " +
" buttonDialog\r\n " +
" .dialog(\"option\", \"buttons\", null)\r\n " +
" .find(\'form\').submit();\r\n " +
" } else {\r\n " +
" alert(\'Select a User Flag\');\r\n " +
" }\r\n " +
" }\r\n }\r\n " +
" });\r\n\r\n " +
" flagAddId = $(\'#User_Show_Details_Actions_AddFlag_Dialog_Id\');\r\n " +
" flagAddComments = buttonDialog.find(\'#User_Show_D" +
"etails_Actions_AddFlag_Dialog_Comments\');\r\n " +
" flagPicker = buttonDialog.find(\'.flagPicker\');\r\n " +
" details = buttonDialog.find(\'.details\');\r\n\r\n " +
" $(\'#User_Show_Details_Actions_AddFlag_Dialog_Filter\')" +
".on(\'keyup\', function (e) {\r\n con" +
"st filter = $(e.currentTarget).val().toLowerCase();\r\n " +
" if (filter) {\r\n " +
" flagPicker.children(\'div.flag\').each(function () {\r\n " +
" const $this = $(this);\r\n " +
" if ($this.attr(\'data-userflagname\').toLowerC" +
"ase().indexOf(filter) >= 0) {\r\n " +
" $this.css(\'display\', \'block\');\r\n " +
" } else {\r\n " +
" $this.css(\'display\', \'none\');\r\n " +
" }\r\n });\r\n " +
" } else {\r\n " +
" flagPicker.children(\'div.flag\').each(function () { $(t" +
"his).css(\'display\', \'block\'); });\r\n " +
" }\r\n });\r\n\r\n " +
" flagPicker.on(\'click\', \'div.flag\', flagSelected);\r\n " +
" }\r\n\r\n $(\'" +
"#User_Show_Details_Actions_AddFlag_Dialog_Filter\').val(\'\');\r\n " +
" buttonDialog.dialog(\'open\');\r\n " +
" return false;\r\n });\r\n " +
" });\r\n </script>\r\n");
#line 346 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 345 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1171,13 +1178,13 @@ WriteLiteral(">\r\n $(function () {\r\n
WriteLiteral(" </div>\r\n </div>\r\n </td>\r\n");
#line 350 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 349 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 350 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 349 "..\..\Views\User\UserParts\_Subject.cshtml"
if (Authorization.Has(Claims.User.ShowAssignments))
{
@@ -1195,13 +1202,13 @@ WriteLiteral(" id=\"User_Show_AssignedDevices_Active\"");
WriteLiteral(">\r\n <h3>Current Device Assignments</h3>\r\n");
#line 356 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 355 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 356 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 355 "..\..\Views\User\UserParts\_Subject.cshtml"
if (currentDeviceAssignments.Count > 0)
{
foreach (var assignment in currentDeviceAssignments)
@@ -1217,7 +1224,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment clearfix\"");
WriteLiteral(" data-deviceserialnumber=\"");
#line 360 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 359 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.DeviceSerialNumber);
@@ -1228,13 +1235,13 @@ WriteLiteral("\"");
WriteLiteral(">\r\n");
#line 361 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 360 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 361 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 360 "..\..\Views\User\UserParts\_Subject.cshtml"
if (Authorization.Has(Claims.Device.Show))
{
@@ -1243,14 +1250,14 @@ WriteLiteral(">\r\n");
#line hidden
WriteLiteral(" <a");
WriteAttribute("href", Tuple.Create(" href=\"", 23450), Tuple.Create("\"", 23517)
WriteAttribute("href", Tuple.Create(" href=\"", 23264), Tuple.Create("\"", 23331)
#line 363 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 23457), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.Device.Show(assignment.Device.SerialNumber))
#line 362 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 23271), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.Device.Show(assignment.Device.SerialNumber))
#line default
#line hidden
, 23457), false)
, 23271), false)
);
WriteLiteral(">\r\n <img");
@@ -1259,20 +1266,20 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Image\"");
WriteLiteral(" alt=\"Model Image\"");
WriteAttribute("src", Tuple.Create(" src=\"", 23649), Tuple.Create("\"", 23770)
WriteAttribute("src", Tuple.Create(" src=\"", 23463), Tuple.Create("\"", 23584)
#line 364 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 23655), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.DeviceModel.Image(assignment.Device.DeviceModel.Id, assignment.Device.DeviceModel.ImageHash()))
#line 363 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 23469), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.DeviceModel.Image(assignment.Device.DeviceModel.Id, assignment.Device.DeviceModel.ImageHash()))
#line default
#line hidden
, 23655), false)
, 23469), false)
);
WriteLiteral(" />\r\n </a>\r\n");
#line 366 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 365 "..\..\Views\User\UserParts\_Subject.cshtml"
}
else
{
@@ -1286,20 +1293,20 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Image\"");
WriteLiteral(" alt=\"Model Image\"");
WriteAttribute("src", Tuple.Create(" src=\"", 24082), Tuple.Create("\"", 24203)
WriteAttribute("src", Tuple.Create(" src=\"", 23896), Tuple.Create("\"", 24017)
#line 369 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 24088), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.DeviceModel.Image(assignment.Device.DeviceModel.Id, assignment.Device.DeviceModel.ImageHash()))
#line 368 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 23902), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.DeviceModel.Image(assignment.Device.DeviceModel.Id, assignment.Device.DeviceModel.ImageHash()))
#line default
#line hidden
, 24088), false)
, 23902), false)
);
WriteLiteral(" />\r\n");
#line 370 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 369 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1327,13 +1334,13 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_SerialNumber\
WriteLiteral(" data-clipboard>\r\n");
#line 380 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 379 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 380 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 379 "..\..\Views\User\UserParts\_Subject.cshtml"
if (Authorization.Has(Claims.Device.Show))
{
@@ -1341,14 +1348,14 @@ WriteLiteral(" data-clipboard>\r\n");
#line default
#line hidden
#line 382 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 381 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(Html.ActionLink(assignment.Device.SerialNumber, MVC.Device.Show(assignment.Device.SerialNumber)));
#line default
#line hidden
#line 382 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 381 "..\..\Views\User\UserParts\_Subject.cshtml"
}
else
@@ -1358,14 +1365,14 @@ WriteLiteral(" data-clipboard>\r\n");
#line default
#line hidden
#line 386 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 385 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.Device.SerialNumber);
#line default
#line hidden
#line 386 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 385 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1375,13 +1382,13 @@ WriteLiteral(" data-clipboard>\r\n");
WriteLiteral(" </span>\r\n");
#line 389 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 388 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 389 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 388 "..\..\Views\User\UserParts\_Subject.cshtml"
if (!string.IsNullOrWhiteSpace(assignment.Device.ComputerName))
{
@@ -1397,7 +1404,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_ComputerName\
WriteLiteral(" data-clipboard>");
#line 391 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 390 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.Device.ComputerName);
@@ -1408,7 +1415,7 @@ WriteLiteral("</span>)");
WriteLiteral("\r\n");
#line 392 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 391 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1418,13 +1425,13 @@ WriteLiteral(" </td>\r\n
" </tr>\r\n");
#line 395 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 394 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 395 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 394 "..\..\Views\User\UserParts\_Subject.cshtml"
if (!string.IsNullOrEmpty(assignment.Device.AssetNumber))
{
@@ -1441,7 +1448,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Asset\"");
WriteLiteral(" data-clipboard>");
#line 400 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 399 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.Device.AssetNumber);
@@ -1451,7 +1458,7 @@ WriteLiteral("</span>\r\n
" </tr>\r\n");
#line 403 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 402 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1460,7 +1467,7 @@ WriteLiteral("</span>\r\n
WriteLiteral(" ");
#line 404 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 403 "..\..\Views\User\UserParts\_Subject.cshtml"
if (assignment.Device.DeviceModelId.HasValue)
{
@@ -1479,7 +1486,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Model\"");
WriteLiteral(">");
#line 411 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 410 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.Device.DeviceModel.ToString());
@@ -1489,7 +1496,7 @@ WriteLiteral("</span>\r\n
" </tr>\r\n");
#line 414 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 413 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1507,7 +1514,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Profile\"");
WriteLiteral(">");
#line 420 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 419 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.Device.DeviceProfile.ToString());
@@ -1517,13 +1524,13 @@ WriteLiteral("</span>\r\n
" </tr>\r\n");
#line 423 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 422 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 423 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 422 "..\..\Views\User\UserParts\_Subject.cshtml"
if (assignment.Device.DeviceBatchId.HasValue)
{
@@ -1542,7 +1549,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Batch\"");
WriteLiteral(">");
#line 430 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 429 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(assignment.Device.DeviceBatch.ToString());
@@ -1552,7 +1559,7 @@ WriteLiteral("</span>\r\n
" </tr>\r\n");
#line 433 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 432 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1568,7 +1575,7 @@ WriteLiteral(" class=\"User_Show_AssignedDevices_CurrentAssignment_Assigned\"");
WriteLiteral(">");
#line 437 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 436 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(CommonHelpers.FriendlyDate(assignment.AssignedDate));
@@ -1578,15 +1585,14 @@ WriteLiteral("</span>\r\n
" </tr>\r\n");
#line 440 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 439 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 440 "..\..\Views\User\UserParts\_Subject.cshtml"
if (Authorization.Has(Claims.Device.ShowFlagAssignments) &&
assignment.Device.DeviceFlagAssignments.Any(a => a.RemovedDate.HasValue))
#line 439 "..\..\Views\User\UserParts\_Subject.cshtml"
if (assignment.Device.DeviceFlagAssignments.CanShowAny())
{
@@ -1604,50 +1610,52 @@ WriteLiteral(" class=\"User_Show_Assigned_Devices_CurrentAssignment_Flags\"");
WriteLiteral(">\r\n");
#line 446 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 444 "..\..\Views\User\UserParts\_Subject.cshtml"
#line default
#line hidden
#line 446 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 444 "..\..\Views\User\UserParts\_Subject.cshtml"
foreach (var flag in assignment.Device.DeviceFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, DeviceFlagService.GetDeviceFlag(f.DeviceFlagId))))
{
if (flag.Item2.permission.CanShow())
{
#line default
#line hidden
WriteLiteral(" <i");
WriteLiteral(" <i");
WriteAttribute("class", Tuple.Create(" class=\"", 30837), Tuple.Create("\"", 30907)
, Tuple.Create(Tuple.Create("", 30845), Tuple.Create("flag", 30845), true)
, Tuple.Create(Tuple.Create(" ", 30849), Tuple.Create("fa", 30850), true)
, Tuple.Create(Tuple.Create(" ", 30852), Tuple.Create("fa-", 30853), true)
WriteAttribute("class", Tuple.Create(" class=\"", 30707), Tuple.Create("\"", 30787)
, Tuple.Create(Tuple.Create("", 30715), Tuple.Create("flag", 30715), true)
, Tuple.Create(Tuple.Create(" ", 30719), Tuple.Create("fa", 30720), true)
, Tuple.Create(Tuple.Create(" ", 30722), Tuple.Create("fa-", 30723), true)
#line 448 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 30856), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon
, Tuple.Create(Tuple.Create("", 30726), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.Icon
#line default
#line hidden
, 30856), false)
, Tuple.Create(Tuple.Create(" ", 30874), Tuple.Create("fa-fw", 30875), true)
, Tuple.Create(Tuple.Create(" ", 30880), Tuple.Create("d-", 30881), true)
, 30726), false)
, Tuple.Create(Tuple.Create(" ", 30749), Tuple.Create("fa-fw", 30750), true)
, Tuple.Create(Tuple.Create(" ", 30755), Tuple.Create("d-", 30756), true)
#line 448 "..\..\Views\User\UserParts\_Subject.cshtml"
, Tuple.Create(Tuple.Create("", 30883), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour
, Tuple.Create(Tuple.Create("", 30758), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.IconColour
#line default
#line hidden
, 30883), false)
, 30758), false)
);
WriteLiteral(">\r\n <s" +
"pan");
WriteLiteral(">\r\n " +
" <span");
WriteLiteral(" class=\"details\"");
WriteLiteral(">\r\n " +
" <span");
" <span");
WriteLiteral(" class=\"name\"");
@@ -1655,7 +1663,7 @@ WriteLiteral(">");
#line 450 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(flag.Item2.Name);
Write(flag.Item2.flag.Name);
#line default
@@ -1664,8 +1672,8 @@ WriteLiteral("</span>");
#line 450 "..\..\Views\User\UserParts\_Subject.cshtml"
if (flag.Item1.Comments != null)
{
if (flag.Item1.Comments != null)
{
#line default
#line hidden
@@ -1677,7 +1685,7 @@ WriteLiteral(">");
#line 451 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(flag.Item1.Comments.ToHtmlComment());
Write(flag.Item1.Comments.ToHtmlComment());
#line default
@@ -1686,7 +1694,7 @@ WriteLiteral("</span>");
#line 451 "..\..\Views\User\UserParts\_Subject.cshtml"
}
}
#line default
#line hidden
@@ -1698,17 +1706,18 @@ WriteLiteral(">");
#line 451 "..\..\Views\User\UserParts\_Subject.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId));
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId));
#line default
#line hidden
WriteLiteral("</span>\r\n " +
" </span>\r\n " +
" </i>\r\n");
" </span>\r\n " +
" </i>\r\n");
#line 454 "..\..\Views\User\UserParts\_Subject.cshtml"
}
}
@@ -1761,7 +1770,7 @@ WriteLiteral(">\r\n
" </tr>\r\n");
#line 488 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 489 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1772,7 +1781,7 @@ WriteLiteral(" </tbody>\r\n
" </div>\r\n");
#line 493 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 494 "..\..\Views\User\UserParts\_Subject.cshtml"
}
}
else
@@ -1788,7 +1797,7 @@ WriteLiteral(" class=\"smallMessage\"");
WriteLiteral(">No Current Device Assignments</span>\r\n");
#line 498 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 499 "..\..\Views\User\UserParts\_Subject.cshtml"
}
@@ -1798,7 +1807,7 @@ WriteLiteral(" </div>\r\n </div>\r\n
"\r\n");
#line 502 "..\..\Views\User\UserParts\_Subject.cshtml"
#line 503 "..\..\Views\User\UserParts\_Subject.cshtml"
}
+9 -9
View File
@@ -42,22 +42,22 @@
{
@item.FriendlyId
}
@if (Authorization.Has(Claims.User.ShowFlagAssignments))
@if (item.UserFlagAssignments.CanShowAny())
{
@if (item.UserFlagAssignments != null && item.UserFlagAssignments.Count > 0)
{
<div class="flags">
@foreach (var flag in item.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
<div class="flags">
@foreach (var flag in item.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{
if (flag.Item2.permission.CanShow())
{
<i class="flag fa fa-@(flag.Item2.Icon) fa-fw d-@(flag.Item2.IconColour)">
<i class="flag fa fa-@(flag.Item2.flag.Icon) fa-fw d-@(flag.Item2.flag.IconColour)">
<span class="details">
<span class="name">@flag.Item2.Name</span>@if (flag.Item1.Comments != null)
<span class="name">@flag.Item2.flag.Name</span>@if (flag.Item1.Comments != null)
{<span class="comments">@flag.Item1.Comments.ToHtmlComment()</span>}<span class="added">@CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUserId)</span>
</span>
</i>
}
</div>
}
}
</div>
}
</td>
<td>
+23 -34
View File
@@ -173,35 +173,29 @@ WriteLiteral(" ");
#line 45 "..\..\Views\User\_UserTable.cshtml"
if (Authorization.Has(Claims.User.ShowFlagAssignments))
if (item.UserFlagAssignments.CanShowAny())
{
#line default
#line hidden
#line 47 "..\..\Views\User\_UserTable.cshtml"
if (item.UserFlagAssignments != null && item.UserFlagAssignments.Count > 0)
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" <div");
WriteLiteral(" class=\"flags\"");
WriteLiteral(">\r\n");
#line 50 "..\..\Views\User\_UserTable.cshtml"
#line 48 "..\..\Views\User\_UserTable.cshtml"
#line default
#line hidden
#line 50 "..\..\Views\User\_UserTable.cshtml"
foreach (var flag in item.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
#line 48 "..\..\Views\User\_UserTable.cshtml"
foreach (var flag in item.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{
if (flag.Item2.permission.CanShow())
{
@@ -209,26 +203,26 @@ WriteLiteral(">\r\n");
#line hidden
WriteLiteral(" <i");
WriteAttribute("class", Tuple.Create(" class=\"", 2064), Tuple.Create("\"", 2134)
, Tuple.Create(Tuple.Create("", 2072), Tuple.Create("flag", 2072), true)
, Tuple.Create(Tuple.Create(" ", 2076), Tuple.Create("fa", 2077), true)
, Tuple.Create(Tuple.Create(" ", 2079), Tuple.Create("fa-", 2080), true)
WriteAttribute("class", Tuple.Create(" class=\"", 2015), Tuple.Create("\"", 2095)
, Tuple.Create(Tuple.Create("", 2023), Tuple.Create("flag", 2023), true)
, Tuple.Create(Tuple.Create(" ", 2027), Tuple.Create("fa", 2028), true)
, Tuple.Create(Tuple.Create(" ", 2030), Tuple.Create("fa-", 2031), true)
#line 52 "..\..\Views\User\_UserTable.cshtml"
, Tuple.Create(Tuple.Create("", 2083), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon
, Tuple.Create(Tuple.Create("", 2034), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.Icon
#line default
#line hidden
, 2083), false)
, Tuple.Create(Tuple.Create(" ", 2101), Tuple.Create("fa-fw", 2102), true)
, Tuple.Create(Tuple.Create(" ", 2107), Tuple.Create("d-", 2108), true)
, 2034), false)
, Tuple.Create(Tuple.Create(" ", 2057), Tuple.Create("fa-fw", 2058), true)
, Tuple.Create(Tuple.Create(" ", 2063), Tuple.Create("d-", 2064), true)
#line 52 "..\..\Views\User\_UserTable.cshtml"
, Tuple.Create(Tuple.Create("", 2110), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour
, Tuple.Create(Tuple.Create("", 2066), Tuple.Create<System.Object, System.Int32>(flag.Item2.flag.IconColour
#line default
#line hidden
, 2110), false)
, 2066), false)
);
WriteLiteral(">\r\n <span");
@@ -243,7 +237,7 @@ WriteLiteral(">");
#line 54 "..\..\Views\User\_UserTable.cshtml"
Write(flag.Item2.Name);
Write(flag.Item2.flag.Name);
#line default
@@ -252,7 +246,7 @@ WriteLiteral("</span>");
#line 54 "..\..\Views\User\_UserTable.cshtml"
if (flag.Item1.Comments != null)
if (flag.Item1.Comments != null)
{
#line default
@@ -297,20 +291,15 @@ WriteLiteral("</span>\r\n </span>
#line 58 "..\..\Views\User\_UserTable.cshtml"
}
}
#line default
#line hidden
WriteLiteral("\r\n </div>\r\n");
WriteLiteral(" </div>\r\n");
#line 60 "..\..\Views\User\_UserTable.cshtml"
}
#line default
#line hidden
#line 60 "..\..\Views\User\_UserTable.cshtml"
#line 61 "..\..\Views\User\_UserTable.cshtml"
}