add comments for users [#145]

This commit is contained in:
Gary Sharp
2025-07-12 19:55:58 +10:00
parent 42e9045d5e
commit 2184c9e22e
35 changed files with 2201 additions and 498 deletions
+7
View File
@@ -193,6 +193,10 @@
<Compile Include="Migrations\202503140520548_DBv26.Designer.cs"> <Compile Include="Migrations\202503140520548_DBv26.Designer.cs">
<DependentUpon>202503140520548_DBv26.cs</DependentUpon> <DependentUpon>202503140520548_DBv26.cs</DependentUpon>
</Compile> </Compile>
<Compile Include="Migrations\202507110430252_DBv27.cs" />
<Compile Include="Migrations\202507110430252_DBv27.Designer.cs">
<DependentUpon>202507110430252_DBv27.cs</DependentUpon>
</Compile>
<Compile Include="Migrations\Configuration.cs" /> <Compile Include="Migrations\Configuration.cs" />
<Compile Include="Migrations\DiscoDataMigrator.cs" /> <Compile Include="Migrations\DiscoDataMigrator.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
@@ -286,6 +290,9 @@
<EmbeddedResource Include="Migrations\202503140520548_DBv26.resx"> <EmbeddedResource Include="Migrations\202503140520548_DBv26.resx">
<DependentUpon>202503140520548_DBv26.cs</DependentUpon> <DependentUpon>202503140520548_DBv26.cs</DependentUpon>
</EmbeddedResource> </EmbeddedResource>
<EmbeddedResource Include="Migrations\202507110430252_DBv27.resx">
<DependentUpon>202507110430252_DBv27.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx"> <EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <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 DBv27 : IMigrationMetadata
{
private readonly ResourceManager Resources = new ResourceManager(typeof(DBv27));
string IMigrationMetadata.Id
{
get { return "202507110430252_DBv27"; }
}
string IMigrationMetadata.Source
{
get { return null; }
}
string IMigrationMetadata.Target
{
get { return Resources.GetString("Target"); }
}
}
}
@@ -0,0 +1,58 @@
namespace Disco.Data.Migrations
{
using System;
using System.Data.Entity.Migrations;
public partial class DBv27 : DbMigration
{
public override void Up()
{
CreateTable(
"dbo.UserComments",
c => new
{
Id = c.Int(nullable: false, identity: true),
UserId = c.String(maxLength: 50),
TechUserId = c.String(nullable: false, maxLength: 50),
Timestamp = c.DateTime(nullable: false),
Comments = c.String(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Users", t => t.TechUserId)
.ForeignKey("dbo.Users", t => t.UserId)
.Index(t => t.TechUserId)
.Index(t => t.UserId);
CreateTable(
"dbo.DeviceComments",
c => new
{
Id = c.Int(nullable: false, identity: true),
DeviceSerialNumber = c.String(maxLength: 60),
TechUserId = c.String(nullable: false, maxLength: 50),
Timestamp = c.DateTime(nullable: false),
Comments = c.String(nullable: false),
})
.PrimaryKey(t => t.Id)
.ForeignKey("dbo.Users", t => t.TechUserId)
.ForeignKey("dbo.Devices", t => t.DeviceSerialNumber)
.Index(t => t.TechUserId)
.Index(t => t.DeviceSerialNumber);
}
public override void Down()
{
DropIndex("dbo.DeviceComments", new[] { "DeviceSerialNumber" });
DropIndex("dbo.DeviceComments", new[] { "TechUserId" });
DropIndex("dbo.UserComments", new[] { "UserId" });
DropIndex("dbo.UserComments", new[] { "TechUserId" });
DropForeignKey("dbo.DeviceComments", "DeviceSerialNumber", "dbo.Devices");
DropForeignKey("dbo.DeviceComments", "TechUserId", "dbo.Users");
DropForeignKey("dbo.UserComments", "UserId", "dbo.Users");
DropForeignKey("dbo.UserComments", "TechUserId", "dbo.Users");
DropTable("dbo.DeviceComments");
DropTable("dbo.UserComments");
}
}
}
File diff suppressed because one or more lines are too long
@@ -19,6 +19,7 @@ namespace Disco.Data.Repository
public virtual DbSet<DocumentTemplate> DocumentTemplates { get; set; } public virtual DbSet<DocumentTemplate> DocumentTemplates { get; set; }
public virtual DbSet<User> Users { get; set; } public virtual DbSet<User> Users { get; set; }
public virtual DbSet<UserComment> UserComments { get; set; }
public virtual DbSet<UserDetail> UserDetails { get; set; } public virtual DbSet<UserDetail> UserDetails { get; set; }
public virtual DbSet<UserAttachment> UserAttachments { get; set; } public virtual DbSet<UserAttachment> UserAttachments { get; set; }
public virtual DbSet<UserFlag> UserFlags { get; set; } public virtual DbSet<UserFlag> UserFlags { get; set; }
@@ -28,6 +29,7 @@ namespace Disco.Data.Repository
public virtual DbSet<DeviceUserAssignment> DeviceUserAssignments { get; set; } public virtual DbSet<DeviceUserAssignment> DeviceUserAssignments { get; set; }
public virtual DbSet<Device> Devices { get; set; } public virtual DbSet<Device> Devices { get; set; }
public virtual DbSet<DeviceComment> DeviceComments { get; set; }
public virtual DbSet<DeviceDetail> DeviceDetails { get; set; } public virtual DbSet<DeviceDetail> DeviceDetails { get; set; }
public virtual DbSet<DeviceModel> DeviceModels { get; set; } public virtual DbSet<DeviceModel> DeviceModels { get; set; }
public virtual DbSet<DeviceProfile> DeviceProfiles { get; set; } public virtual DbSet<DeviceProfile> DeviceProfiles { get; set; }
+2
View File
@@ -58,6 +58,8 @@
<Compile Include="Exporting\IExportRecord.cs" /> <Compile Include="Exporting\IExportRecord.cs" />
<Compile Include="Repository\Device\Flag\DeviceFlag.cs" /> <Compile Include="Repository\Device\Flag\DeviceFlag.cs" />
<Compile Include="Repository\Device\Flag\DeviceFlagAssignment.cs" /> <Compile Include="Repository\Device\Flag\DeviceFlagAssignment.cs" />
<Compile Include="Repository\Device\DeviceComment.cs" />
<Compile Include="Repository\User\UserComment.cs" />
<Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportOptions.cs" /> <Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportOptions.cs" />
<Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportRecord.cs" /> <Compile Include="Services\Devices\DeviceFlags\DeviceFlagExportRecord.cs" />
<Compile Include="Services\Documents\DocumentExportOptions.cs" /> <Compile Include="Services\Documents\DocumentExportOptions.cs" />
+4 -1
View File
@@ -48,9 +48,12 @@ namespace Disco.Models.Repository
public virtual IList<DeviceAttachment> DeviceAttachments { get; set; } public virtual IList<DeviceAttachment> DeviceAttachments { get; set; }
public virtual IList<DeviceCertificate> DeviceCertificates { get; set; } public virtual IList<DeviceCertificate> DeviceCertificates { get; set; }
[InverseProperty("DeviceSerialNumber")] [InverseProperty(nameof(Job.Device))]
public virtual IList<Job> Jobs { get; set; } public virtual IList<Job> Jobs { get; set; }
public virtual IList<DeviceFlagAssignment> DeviceFlagAssignments { get; set; } public virtual IList<DeviceFlagAssignment> DeviceFlagAssignments { get; set; }
[InverseProperty(nameof(DeviceComment.Device))]
public virtual IList<DeviceComment> DeviceComments { get; set; }
/// <summary> /// <summary>
/// A list of the current device assignments, ordered by the most recent assignment date. /// A list of the current device assignments, ordered by the most recent assignment date.
@@ -0,0 +1,25 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Models.Repository
{
public class DeviceComment
{
[Key]
public int Id { get; set; }
public string DeviceSerialNumber { get; set; }
[Required]
public string TechUserId { get; set; }
public DateTime Timestamp { get; set; }
[Required]
public string Comments { get; set; }
[ForeignKey(nameof(DeviceSerialNumber))]
public Device Device { get; set; }
[ForeignKey(nameof(TechUserId))]
public User TechUser { get; set; }
}
}
+3 -1
View File
@@ -25,9 +25,11 @@ namespace Disco.Models.Repository
public virtual IList<UserDetail> UserDetails { get; set; } public virtual IList<UserDetail> UserDetails { get; set; }
public virtual IList<UserAttachment> UserAttachments { get; set; } public virtual IList<UserAttachment> UserAttachments { get; set; }
public virtual IList<DeviceUserAssignment> DeviceUserAssignments { get; set; } public virtual IList<DeviceUserAssignment> DeviceUserAssignments { get; set; }
[InverseProperty("UserId")] [InverseProperty(nameof(Job.User))]
public virtual IList<Job> Jobs { get; set; } public virtual IList<Job> Jobs { get; set; }
public virtual IList<UserFlagAssignment> UserFlagAssignments { get; set; } public virtual IList<UserFlagAssignment> UserFlagAssignments { get; set; }
[InverseProperty(nameof(UserComment.User))]
public virtual IList<UserComment> UserComments { get; set; }
[NotMapped, Obsolete("Should be using Combined Domain\\User format - UserId")] [NotMapped, Obsolete("Should be using Combined Domain\\User format - UserId")]
public string Id public string Id
@@ -0,0 +1,25 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Disco.Models.Repository
{
public class UserComment
{
[Key]
public int Id { get; set; }
public string UserId { get; set; }
[Required]
public string TechUserId { get; set; }
public DateTime Timestamp { get; set; }
[Required]
public string Comments { get; set; }
[ForeignKey(nameof(UserId))]
public User User { get; set; }
[ForeignKey(nameof(TechUserId))]
public User TechUser { get; set; }
}
}
+32
View File
@@ -216,14 +216,18 @@ namespace Disco.Services.Authorization
{ "Device.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Device.Show, (c, v) => c.Device.Show = v, "Show Devices", "Can show devices", false) }, { "Device.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Device.Show, (c, v) => c.Device.Show = v, "Show Devices", "Can show devices", false) },
{ "Device.ShowJobs", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Device.ShowJobs, (c, v) => c.Device.ShowJobs = v, "Show Devices Jobs", "Can show jobs associated with devices", false) }, { "Device.ShowJobs", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.Device.ShowJobs, (c, v) => c.Device.ShowJobs = v, "Show Devices Jobs", "Can show jobs associated with devices", false) },
{ "User.Actions.AddAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.AddAttachments, (c, v) => c.User.Actions.AddAttachments = v, "Add Attachments", "Can add attachments to users", false) }, { "User.Actions.AddAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.AddAttachments, (c, v) => c.User.Actions.AddAttachments = v, "Add Attachments", "Can add attachments to users", false) },
{ "User.Actions.AddComments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.AddComments, (c, v) => c.User.Actions.AddComments = v, "Add Comments", "Can add user comments", false) },
{ "User.Actions.AddFlags", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.AddFlags, (c, v) => c.User.Actions.AddFlags = v, "Add User Flags", "Can add user flags", false) }, { "User.Actions.AddFlags", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.AddFlags, (c, v) => c.User.Actions.AddFlags = v, "Add User Flags", "Can add user flags", false) },
{ "User.Actions.EditFlags", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.EditFlags, (c, v) => c.User.Actions.EditFlags = v, "Edit User Flags", "Can edit user flags", false) }, { "User.Actions.EditFlags", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.EditFlags, (c, v) => c.User.Actions.EditFlags = v, "Edit User Flags", "Can edit user flags", false) },
{ "User.Actions.GenerateDocuments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.GenerateDocuments, (c, v) => c.User.Actions.GenerateDocuments = v, "Generate Documents", "Can generate documents for users", false) }, { "User.Actions.GenerateDocuments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.GenerateDocuments, (c, v) => c.User.Actions.GenerateDocuments = v, "Generate Documents", "Can generate documents for users", false) },
{ "User.Actions.RemoveAnyAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveAnyAttachments, (c, v) => c.User.Actions.RemoveAnyAttachments = v, "Remove Any Attachments", "Can remove any attachments from users", false) }, { "User.Actions.RemoveAnyAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveAnyAttachments, (c, v) => c.User.Actions.RemoveAnyAttachments = v, "Remove Any Attachments", "Can remove any attachments from users", false) },
{ "User.Actions.RemoveAnyComments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveAnyComments, (c, v) => c.User.Actions.RemoveAnyComments = v, "Remove Any Comments", "Can remove any user comments", false) },
{ "User.Actions.RemoveOwnAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveOwnAttachments, (c, v) => c.User.Actions.RemoveOwnAttachments = v, "Remove Own Attachments", "Can remove own attachments from users", false) }, { "User.Actions.RemoveOwnAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveOwnAttachments, (c, v) => c.User.Actions.RemoveOwnAttachments = v, "Remove Own Attachments", "Can remove own attachments from users", false) },
{ "User.Actions.RemoveOwnComments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveOwnComments, (c, v) => c.User.Actions.RemoveOwnComments = v, "Remove Own Comments", "Can remove own user comments", false) },
{ "User.Actions.RemoveFlags", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveFlags, (c, v) => c.User.Actions.RemoveFlags = v, "Remove User Flags", "Can remove user flags", false) }, { "User.Actions.RemoveFlags", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Actions.RemoveFlags, (c, v) => c.User.Actions.RemoveFlags = v, "Remove User Flags", "Can remove user flags", false) },
{ "User.Search", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Search, (c, v) => c.User.Search = v, "Search Users", "Can search users", false) }, { "User.Search", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Search, (c, v) => c.User.Search = v, "Search Users", "Can search users", false) },
{ "User.ShowAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowAttachments, (c, v) => c.User.ShowAttachments = v, "Show Attachments", "Can show user attachments", false) }, { "User.ShowAttachments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowAttachments, (c, v) => c.User.ShowAttachments = v, "Show Attachments", "Can show user attachments", false) },
{ "User.ShowComments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowComments, (c, v) => c.User.ShowComments = v, "Show Comments", "Can show user comments", false) },
{ "User.ShowAssignmentHistory", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowAssignmentHistory, (c, v) => c.User.ShowAssignmentHistory = v, "Show Device Assignment History", "Can show the device assignment history for users", false) }, { "User.ShowAssignmentHistory", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowAssignmentHistory, (c, v) => c.User.ShowAssignmentHistory = v, "Show Device Assignment History", "Can show the device assignment history for users", false) },
{ "User.ShowAssignments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowAssignments, (c, v) => c.User.ShowAssignments = v, "Show Device Assignments", "Can show the current device assignments users", false) }, { "User.ShowAssignments", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.ShowAssignments, (c, v) => c.User.ShowAssignments = v, "Show Device Assignments", "Can show the current device assignments users", false) },
{ "User.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Show, (c, v) => c.User.Show = v, "Show Users", "Can show users", false) }, { "User.Show", new Tuple<Func<RoleClaims, bool>, Action<RoleClaims, bool>, string, string, bool>(c => c.User.Show, (c, v) => c.User.Show = v, "Show Users", "Can show users", false) },
@@ -488,15 +492,19 @@ namespace Disco.Services.Authorization
new ClaimNavigatorItem("User", "User", "Permissions related to Users", false, new List<IClaimNavigatorItem>() { new ClaimNavigatorItem("User", "User", "Permissions related to Users", false, new List<IClaimNavigatorItem>() {
new ClaimNavigatorItem("User.Actions", "Actions", "Permissions related to User Actions", false, new List<IClaimNavigatorItem>() { new ClaimNavigatorItem("User.Actions", "Actions", "Permissions related to User Actions", false, new List<IClaimNavigatorItem>() {
new ClaimNavigatorItem("User.Actions.AddAttachments", false), new ClaimNavigatorItem("User.Actions.AddAttachments", false),
new ClaimNavigatorItem("User.Actions.AddComments", false),
new ClaimNavigatorItem("User.Actions.AddFlags", false), new ClaimNavigatorItem("User.Actions.AddFlags", false),
new ClaimNavigatorItem("User.Actions.EditFlags", false), new ClaimNavigatorItem("User.Actions.EditFlags", false),
new ClaimNavigatorItem("User.Actions.GenerateDocuments", false), new ClaimNavigatorItem("User.Actions.GenerateDocuments", false),
new ClaimNavigatorItem("User.Actions.RemoveAnyAttachments", false), new ClaimNavigatorItem("User.Actions.RemoveAnyAttachments", false),
new ClaimNavigatorItem("User.Actions.RemoveAnyComments", false),
new ClaimNavigatorItem("User.Actions.RemoveOwnAttachments", false), new ClaimNavigatorItem("User.Actions.RemoveOwnAttachments", false),
new ClaimNavigatorItem("User.Actions.RemoveOwnComments", false),
new ClaimNavigatorItem("User.Actions.RemoveFlags", false) new ClaimNavigatorItem("User.Actions.RemoveFlags", false)
}), }),
new ClaimNavigatorItem("User.Search", false), new ClaimNavigatorItem("User.Search", false),
new ClaimNavigatorItem("User.ShowAttachments", false), new ClaimNavigatorItem("User.ShowAttachments", false),
new ClaimNavigatorItem("User.ShowComments", false),
new ClaimNavigatorItem("User.ShowAssignmentHistory", false), new ClaimNavigatorItem("User.ShowAssignmentHistory", false),
new ClaimNavigatorItem("User.ShowAssignments", false), new ClaimNavigatorItem("User.ShowAssignments", false),
new ClaimNavigatorItem("User.Show", false), new ClaimNavigatorItem("User.Show", false),
@@ -764,14 +772,18 @@ namespace Disco.Services.Authorization
c.Device.Show = true; c.Device.Show = true;
c.Device.ShowJobs = true; c.Device.ShowJobs = true;
c.User.Actions.AddAttachments = true; c.User.Actions.AddAttachments = true;
c.User.Actions.AddComments = true;
c.User.Actions.AddFlags = true; c.User.Actions.AddFlags = true;
c.User.Actions.EditFlags = true; c.User.Actions.EditFlags = true;
c.User.Actions.GenerateDocuments = true; c.User.Actions.GenerateDocuments = true;
c.User.Actions.RemoveAnyAttachments = true; c.User.Actions.RemoveAnyAttachments = true;
c.User.Actions.RemoveAnyComments = true;
c.User.Actions.RemoveOwnAttachments = true; c.User.Actions.RemoveOwnAttachments = true;
c.User.Actions.RemoveOwnComments = true;
c.User.Actions.RemoveFlags = true; c.User.Actions.RemoveFlags = true;
c.User.Search = true; c.User.Search = true;
c.User.ShowAttachments = true; c.User.ShowAttachments = true;
c.User.ShowComments = true;
c.User.ShowAssignmentHistory = true; c.User.ShowAssignmentHistory = true;
c.User.ShowAssignments = true; c.User.ShowAssignments = true;
c.User.Show = true; c.User.Show = true;
@@ -1961,6 +1973,11 @@ namespace Disco.Services.Authorization
/// </summary> /// </summary>
public const string AddAttachments = "User.Actions.AddAttachments"; public const string AddAttachments = "User.Actions.AddAttachments";
/// <summary>Add Comments
/// <para>Can add user comments</para>
/// </summary>
public const string AddComments = "User.Actions.AddComments";
/// <summary>Add User Flags /// <summary>Add User Flags
/// <para>Can add user flags</para> /// <para>Can add user flags</para>
/// </summary> /// </summary>
@@ -1981,11 +1998,21 @@ namespace Disco.Services.Authorization
/// </summary> /// </summary>
public const string RemoveAnyAttachments = "User.Actions.RemoveAnyAttachments"; public const string RemoveAnyAttachments = "User.Actions.RemoveAnyAttachments";
/// <summary>Remove Any Comments
/// <para>Can remove any user comments</para>
/// </summary>
public const string RemoveAnyComments = "User.Actions.RemoveAnyComments";
/// <summary>Remove Own Attachments /// <summary>Remove Own Attachments
/// <para>Can remove own attachments from users</para> /// <para>Can remove own attachments from users</para>
/// </summary> /// </summary>
public const string RemoveOwnAttachments = "User.Actions.RemoveOwnAttachments"; public const string RemoveOwnAttachments = "User.Actions.RemoveOwnAttachments";
/// <summary>Remove Own Comments
/// <para>Can remove own user comments</para>
/// </summary>
public const string RemoveOwnComments = "User.Actions.RemoveOwnComments";
/// <summary>Remove User Flags /// <summary>Remove User Flags
/// <para>Can remove user flags</para> /// <para>Can remove user flags</para>
/// </summary> /// </summary>
@@ -2002,6 +2029,11 @@ namespace Disco.Services.Authorization
/// </summary> /// </summary>
public const string ShowAttachments = "User.ShowAttachments"; public const string ShowAttachments = "User.ShowAttachments";
/// <summary>Show Comments
/// <para>Can show user comments</para>
/// </summary>
public const string ShowComments = "User.ShowComments";
/// <summary>Show Device Assignment History /// <summary>Show Device Assignment History
/// <para>Can show the device assignment history for users</para> /// <para>Can show the device assignment history for users</para>
/// </summary> /// </summary>
@@ -3,6 +3,13 @@
[ClaimDetails("Actions", "Permissions related to User Actions")] [ClaimDetails("Actions", "Permissions related to User Actions")]
public class UserActionsClaims : BaseRoleClaimGroup public class UserActionsClaims : BaseRoleClaimGroup
{ {
[ClaimDetails("Add Comments", "Can add user comments")]
public bool AddComments { get; set; }
[ClaimDetails("Remove Any Comments", "Can remove any user comments")]
public bool RemoveAnyComments { get; set; }
[ClaimDetails("Remove Own Comments", "Can remove own user comments")]
public bool RemoveOwnComments { get; set; }
[ClaimDetails("Add Attachments", "Can add attachments to users")] [ClaimDetails("Add Attachments", "Can add attachments to users")]
public bool AddAttachments { get; set; } public bool AddAttachments { get; set; }
[ClaimDetails("Remove Any Attachments", "Can remove any attachments from users")] [ClaimDetails("Remove Any Attachments", "Can remove any attachments from users")]
@@ -17,6 +17,9 @@
[ClaimDetails("Show Users Details", "Can show users contact and personal details")] [ClaimDetails("Show Users Details", "Can show users contact and personal details")]
public bool ShowDetails { get; set; } public bool ShowDetails { get; set; }
[ClaimDetails("Show Comments", "Can show user comments")]
public bool ShowComments { get; set; }
[ClaimDetails("Show Attachments", "Can show user attachments")] [ClaimDetails("Show Attachments", "Can show user attachments")]
public bool ShowAttachments { get; set; } public bool ShowAttachments { get; set; }
+60 -32
View File
@@ -1,44 +1,75 @@
using Disco.Data.Repository.Monitor; using Disco.Data.Repository.Monitor;
using Disco.Models.Repository;
using Disco.Services.Authorization; using Disco.Services.Authorization;
using Disco.Services.Web.Signalling; using Disco.Services.Web.Signalling;
using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs; using Microsoft.AspNet.SignalR.Hubs;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Reactive.Linq; using System.Reactive.Linq;
using Disco.Models.Repository; using System.Threading.Tasks;
using Disco.Data.Repository;
namespace Disco.Services.Users namespace Disco.Services.Users
{ {
[HubName("userUpdates"), DiscoHubAuthorizeAll(Claims.User.Show, Claims.User.ShowAttachments)] [HubName("userUpdates"), DiscoHubAuthorize(Claims.User.Show)]
public class UserUpdatesHub : Hub public class UserUpdatesHub : Hub
{ {
private const string UserPrefix = "User_";
public static IHubContext HubContext { get; private set; } public static IHubContext HubContext { get; private set; }
private static IDisposable RepositoryBeforeSubscription; private static readonly IDisposable repositoryBeforeSubscription;
private static IDisposable RepositoryAfterSubscription; private static readonly IDisposable repositoryAfterSubscription;
static UserUpdatesHub() static UserUpdatesHub()
{ {
HubContext = GlobalHost.ConnectionManager.GetHubContext<UserUpdatesHub>(); HubContext = GlobalHost.ConnectionManager.GetHubContext<UserUpdatesHub>();
// Subscribe to Repository Monitor for Changes // Subscribe to Repository Monitor for Changes
RepositoryBeforeSubscription = RepositoryMonitor.StreamBeforeCommit repositoryBeforeSubscription = RepositoryMonitor.StreamBeforeCommit
.Where(e => e.EntityType == typeof(UserAttachment) && e.EventType == RepositoryMonitorEventType.Deleted) .Where(e =>
.Subscribe(RepositoryEventBefore); e.EventType == RepositoryMonitorEventType.Deleted && (
RepositoryAfterSubscription = RepositoryMonitor.StreamAfterCommit e.EntityType == typeof(UserComment) ||
.Where(e => e.EntityType == typeof(UserAttachment) && e.EventType == RepositoryMonitorEventType.Added) e.EntityType == typeof(UserAttachment)
.Subscribe(RepositoryAfterEvent); )
).Subscribe(RepositoryEventBefore);
repositoryAfterSubscription = RepositoryMonitor.StreamAfterCommit
.Where(e =>
e.EventType == RepositoryMonitorEventType.Added && (
e.EntityType == typeof(UserComment) ||
e.EntityType == typeof(UserAttachment)
)
).Subscribe(RepositoryAfterEvent);
} }
private static string GroupName(string UserId) private static bool TryAttachmentGroupName(RepositoryMonitorEvent e, out string groupName)
{ {
return UserPrefix + UserId; var userId = e.GetPreviousPropertyValue<string>(nameof(UserAttachment.UserId));
if (userId == null)
{
groupName = null;
return false;
}
groupName = AttachmentGroupName(userId);
return true;
} }
private static string AttachmentGroupName(string UserId)
=> $"User_Attachment_{UserId.ToLowerInvariant()}";
private static bool TryCommentGroupName(RepositoryMonitorEvent e, out string groupName)
{
var userId = e.GetPreviousPropertyValue<string>(nameof(UserComment.UserId));
if (userId == null)
{
groupName = null;
return false;
}
groupName = CommentGroupName(userId);
return true;
}
private static string CommentGroupName(string UserId)
=> $"User_Comment_{UserId.ToLowerInvariant()}";
public override Task OnConnected() public override Task OnConnected()
{ {
var userId = Context.QueryString["UserId"]; var userId = Context.QueryString["UserId"];
@@ -46,7 +77,12 @@ namespace Disco.Services.Users
if (string.IsNullOrWhiteSpace(userId)) if (string.IsNullOrWhiteSpace(userId))
throw new ArgumentNullException("UserId"); throw new ArgumentNullException("UserId");
Groups.Add(Context.ConnectionId, GroupName(userId)); var authorization = UserService.GetAuthorization(Context.User.Identity.Name);
if (authorization.Has(Claims.User.ShowComments))
Groups.Add(Context.ConnectionId, CommentGroupName(userId));
if (authorization.Has(Claims.User.ShowAttachments))
Groups.Add(Context.ConnectionId, AttachmentGroupName(userId));
return base.OnConnected(); return base.OnConnected();
} }
@@ -55,16 +91,10 @@ namespace Disco.Services.Users
{ {
if (e.EventType == RepositoryMonitorEventType.Deleted) if (e.EventType == RepositoryMonitorEventType.Deleted)
{ {
if (e.EntityType == typeof(UserAttachment)) if (e.Entity is UserComment comment && TryCommentGroupName(e, out var commentGroupName))
{ HubContext.Clients.Group(commentGroupName).commentRemoved(comment.Id);
var repositoryAttachment = (UserAttachment)e.Entity; else if (e.Entity is UserAttachment attachment && TryAttachmentGroupName(e, out var attachmentGroupName))
string attachmentUserId; HubContext.Clients.Group(attachmentGroupName).attachmentRemoved(attachment.Id);
using (DiscoDataContext Database = new DiscoDataContext())
attachmentUserId = Database.UserAttachments.Where(a => a.Id == repositoryAttachment.Id).Select(a => a.UserId).First();
HubContext.Clients.Group(GroupName(attachmentUserId)).removeAttachment(repositoryAttachment.Id);
}
} }
} }
@@ -72,12 +102,10 @@ namespace Disco.Services.Users
{ {
if (e.EventType == RepositoryMonitorEventType.Added) if (e.EventType == RepositoryMonitorEventType.Added)
{ {
if (e.EntityType == typeof(UserAttachment)) if (e.Entity is UserComment comment)
{ HubContext.Clients.Group(CommentGroupName(comment.UserId)).commentAdded(comment.Id);
var a = (UserAttachment)e.Entity; else if (e.Entity is UserAttachment attachment)
HubContext.Clients.Group(AttachmentGroupName(attachment.UserId)).attachmentAdded(attachment.Id);
HubContext.Clients.Group(GroupName(a.UserId)).addAttachment(a.Id);
}
} }
} }
} }
@@ -1830,7 +1830,7 @@ namespace Disco.Web.Areas.API.Controllers
if (job == null) if (job == null)
return BadRequest("Invalid Job Number"); return BadRequest("Invalid Job Number");
var results = job.JobLogs.OrderByDescending(m => m.Timestamp).Select(jl => Models.Shared.CommentModel.FromJobLog(jl)).ToList(); var results = job.JobLogs.OrderByDescending(m => m.Timestamp).Select(jl => Models.Shared.CommentModel.FromEntity(jl)).ToList();
return Json(results); return Json(results);
} }
@@ -1846,7 +1846,7 @@ namespace Disco.Web.Areas.API.Controllers
if (jobLog == null) if (jobLog == null)
return BadRequest("Invalid JobLog Id"); return BadRequest("Invalid JobLog Id");
var c = Models.Shared.CommentModel.FromJobLog(jobLog); var c = Models.Shared.CommentModel.FromEntity(jobLog);
return Json(c); return Json(c);
} }
@@ -1,4 +1,5 @@
using Disco.Services; using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization; using Disco.Services.Authorization;
using Disco.Services.Interop; using Disco.Services.Interop;
using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Interop.ActiveDirectory;
@@ -8,7 +9,6 @@ using Disco.Services.Users;
using Disco.Services.Web; using Disco.Services.Web;
using System; using System;
using System.Data.Entity; using System.Data.Entity;
using System.DirectoryServices.ActiveDirectory;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
@@ -17,6 +17,91 @@ namespace Disco.Web.Areas.API.Controllers
{ {
public partial class UserController : AuthorizedDatabaseController public partial class UserController : AuthorizedDatabaseController
{ {
#region User Comments
[DiscoAuthorize(Claims.User.ShowComments)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Comments(string id, string domain)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException(nameof(id));
var userId = ActiveDirectory.ParseDomainAccountId(id, domain);
var user = Database.Users
.Include(u => u.UserComments.Select(l => l.TechUser))
.Where(u => u.UserId == userId).FirstOrDefault();
if (user == null)
return BadRequest("Invalid User Id");
var results = user.UserComments.OrderByDescending(c => c.Timestamp).Select(c => Models.Shared.CommentModel.FromEntity(c)).ToList();
return Json(results);
}
[DiscoAuthorize(Claims.User.ShowComments)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult Comment(int id)
{
var entity = Database.UserComments
.Include(c => c.TechUser)
.FirstOrDefault(c => c.Id == id);
if (entity == null)
return BadRequest("Invalid User Comment Id");
var comment = Models.Shared.CommentModel.FromEntity(entity);
return Json(comment);
}
[DiscoAuthorize(Claims.User.Actions.AddComments)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult CommentAdd(string id, string domain, string comment = null)
{
if (string.IsNullOrEmpty(id))
throw new ArgumentNullException(nameof(id));
var userId = ActiveDirectory.ParseDomainAccountId(id, domain);
if (string.IsNullOrWhiteSpace(comment))
return BadRequest("Comment is required");
var user = Database.Users.Find(userId);
if (user == null)
return BadRequest("Invalid User Id");
var entity = new UserComment()
{
UserId = user.UserId,
TechUserId = CurrentUser.UserId,
Timestamp = DateTime.Now,
Comments = comment
};
Database.UserComments.Add(entity);
Database.SaveChanges();
return Json(entity.Id);
}
[DiscoAuthorizeAny(Claims.User.Actions.RemoveAnyComments, Claims.User.Actions.RemoveOwnComments)]
[HttpPost, ValidateAntiForgeryToken]
public virtual ActionResult CommentRemove(int id)
{
var entity = Database.UserComments.Find(id);
if (entity != null)
{
if (entity.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))
Authorization.RequireAny(Claims.User.Actions.RemoveAnyComments, Claims.User.Actions.RemoveOwnComments);
else
Authorization.Require(Claims.User.Actions.RemoveAnyComments);
Database.UserComments.Remove(entity);
Database.SaveChanges();
}
// Doesn't Exist/Already Deleted - OK
return Ok();
}
#endregion
#region User Attachments #region User Attachments
[DiscoAuthorize(Claims.User.ShowAttachments)] [DiscoAuthorize(Claims.User.ShowAttachments)]
@@ -74,7 +159,7 @@ namespace Disco.Web.Areas.API.Controllers
if (string.IsNullOrWhiteSpace(comments)) if (string.IsNullOrWhiteSpace(comments))
comments = null; comments = null;
var ua = new Disco.Models.Repository.UserAttachment() var ua = new UserAttachment()
{ {
UserId = u.UserId, UserId = u.UserId,
TechUserId = CurrentUser.UserId, TechUserId = CurrentUser.UserId,
@@ -16,18 +16,33 @@ namespace Disco.Web.Areas.API.Models.Shared
public long TimestampUnixEpoc => Timestamp.ToUnixEpoc(); public long TimestampUnixEpoc => Timestamp.ToUnixEpoc();
public string TimestampFull => Timestamp.ToFullDateTime(); public string TimestampFull => Timestamp.ToFullDateTime();
public static CommentModel FromJobLog(JobLog jl) public static CommentModel FromEntity(JobLog log)
{ {
return new CommentModel return new CommentModel
{ {
Id = jl.Id, Id = log.Id,
TargetType = AttachmentTypes.Job, TargetType = AttachmentTypes.Job,
TargetId = jl.JobId.ToString(), TargetId = log.JobId.ToString(),
AuthorId = jl.TechUserId, AuthorId = log.TechUserId,
Author = jl.TechUser.ToString(), Author = log.TechUser.ToString(),
Timestamp = jl.Timestamp, Timestamp = log.Timestamp,
Comments = jl.Comments, Comments = log.Comments,
HtmlComments = jl.Comments.ToHtmlComment().ToString() HtmlComments = log.Comments.ToHtmlComment().ToString()
};
}
public static CommentModel FromEntity(UserComment comment)
{
return new CommentModel
{
Id = comment.Id,
TargetType = AttachmentTypes.User,
TargetId = comment.UserId,
AuthorId = comment.TechUserId,
Author = comment.TechUser.ToString(),
Timestamp = comment.Timestamp,
Comments = comment.Comments,
HtmlComments = comment.Comments.ToHtmlComment().ToString()
}; };
} }
+137 -2
View File
@@ -203,9 +203,144 @@
border-top: none; border-top: none;
background-color: #eee; background-color: #eee;
} }
#UserDetailTab-CommentsAndJobs {
display: grid;
grid-template-columns: auto;
}
#UserDetailTab-CommentsAndJobs.canShowComments.canShowJobs {
grid-template-columns: 375px auto;
}
#UserDetailTab-CommentsAndJobs.canShowComments.canShowJobs > #UserDetailTab-Comments {
grid-column: 1;
}
#UserDetailTab-CommentsAndJobs.canShowComments.canShowJobs > #UserDetailTab-JobsContainer {
grid-column: 2;
}
#UserDetailTab-CommentsAndJobs.cannotShowComments div.jobTable {
border: 1px solid #ccc;
}
#Comments {
box-sizing: border-box;
height: 100%;
min-height: 373px;
padding-bottom: 51px;
border: 1px solid #ccc;
background-color: #fff;
position: relative;
}
#Comments div.commentInput {
border-top: 1px solid #ccc;
box-sizing: border-box;
width: 100%;
height: 51px;
padding: 5px;
position: absolute;
bottom: 0;
display: grid;
grid-template-columns: auto 40px;
}
#Comments div.commentInput textarea.commentInput {
grid-column: 1;
border: 0;
padding: 0;
margin: 0;
width: 100%;
height: 40px;
min-height: 40px;
overflow: auto;
resize: none;
}
#Comments div.commentInput button {
grid-column: 2;
appearance: none;
font-size: 1.5em;
display: block;
border: 1px solid #fff;
background-color: #fff;
}
#Comments div.commentInput button:not([disabled]):hover,
#Comments div.commentInput button:not([disabled]):focus {
color: #335A87;
background-color: #ededed;
border: 1px solid #ccc;
}
#Comments div.commentInput button[disabled] {
color: rgba(51, 51, 51, 0.2);
cursor: default;
}
#Comments div.commentOutput {
height: 100%;
overflow: auto;
background-color: #fafafa;
color: #000;
}
#Comments div.commentOutput > div {
padding: 3px;
margin: 4px 6px;
border-bottom: 1px solid #ccc;
}
#Comments div.commentOutput > div span.author {
color: #444;
display: block;
font-weight: 600;
font-size: 0.95em;
float: left;
}
#Comments div.commentOutput > div span.timestamp {
display: block;
float: right;
font-size: 0.9em;
font-style: italic;
}
#Comments div.commentOutput > div div.comment {
clear: both;
display: block;
margin-left: 4px;
}
#Comments div.commentOutput > div div.comment p {
line-height: 1.2em;
padding-bottom: 0.2em;
}
#Comments div.commentOutput > div div.comment h1,
#Comments div.commentOutput > div div.comment h2,
#Comments div.commentOutput > div div.comment h3,
#Comments div.commentOutput > div div.comment h4,
#Comments div.commentOutput > div div.comment h5 {
font-family: "Segoe UI", Arial, Verdana, Tahoma, sans-serif;
font-weight: 600;
font-size: 14px;
margin: 2px 0 !important;
}
#Comments div.commentOutput > div div.comment hr {
margin-top: 0.2em;
}
#Comments div.commentOutput > div div.comment code {
font-size: 0.9em;
}
#Comments div.commentOutput > div:hover span.remove {
opacity: 0.5;
}
#Comments div.commentOutput > div span.remove {
font-size: 1.2em;
color: #e51400;
margin-left: 6px;
cursor: pointer;
opacity: 0;
}
#Comments div.commentOutput > div span.remove:hover {
opacity: 1;
}
#Comments div.commentOutput > div:last-child {
border-bottom: none;
}
#Comments.cannotAddComments {
padding-bottom: 0;
}
#UserDetailTab-JobsContainer div.jobTable { #UserDetailTab-JobsContainer div.jobTable {
margin: -1px; min-height: 320px;
border: 1px solid #ddd; border-top: 1px solid #ccc;
border-right: 1px solid #ccc;
border-bottom: 1px solid #ccc;
} }
#UserDetailTab-JobsContainer .dataTables_wrapper .dataTables_filter { #UserDetailTab-JobsContainer .dataTables_wrapper .dataTables_filter {
margin-top: -24px; margin-top: -24px;
+162 -2
View File
@@ -170,10 +170,170 @@
} }
} }
#UserDetailTab-CommentsAndJobs {
display: grid;
grid-template-columns: auto;
&.canShowComments.canShowJobs {
grid-template-columns: 375px auto;
& > #UserDetailTab-Comments {
grid-column: 1;
}
& > #UserDetailTab-JobsContainer {
grid-column: 2;
}
}
&.cannotShowComments div.jobTable {
border: 1px solid @SubtleBorderColour;
}
}
#Comments {
box-sizing: border-box;
height: 100%;
min-height: 373px;
padding-bottom: 51px;
border: 1px solid @SubtleBorderColour;
background-color: @white;
position: relative;
div.commentInput {
border-top: 1px solid @SubtleBorderColour;
box-sizing: border-box;
width: 100%;
height: 51px;
padding: 5px;
position: absolute;
bottom: 0;
display: grid;
grid-template-columns: auto 40px;
textarea.commentInput {
grid-column: 1;
border: 0;
padding: 0;
margin: 0;
width: 100%;
height: 40px;
min-height: 40px;
overflow: auto;
resize: none;
}
button {
grid-column: 2;
appearance: none;
font-size: 1.5em;
display: block;
border: 1px solid @white;
background-color: @white;
&:not([disabled]) {
&:hover, &:focus {
color: @HyperLinkColour;
background-color: @SubtleColour;
border: 1px solid @SubtleBorderColour;
}
}
&[disabled] {
color: fade(@HeaderBackgroundColour, 20%);
cursor: default;
}
}
}
div.commentOutput {
height: 100%;
overflow: auto;
background-color: @BackgroundColourLight;
color: @black;
& > div {
padding: 3px;
margin: 4px 6px;
border-bottom: 1px solid @SubtleBorderColour;
span.author {
color: #444;
display: block;
font-weight: @FontWeightBodyBold;
font-size: 0.95em;
float: left;
}
span.timestamp {
display: block;
float: right;
font-size: 0.90em;
font-style: italic;
}
div.comment {
clear: both;
display: block;
margin-left: 4px;
p {
line-height: 1.2em;
padding-bottom: .2em;
}
h1, h2, h3, h4, h5 {
font-family: @FontFamilyBody;
font-weight: 600;
font-size: 14px;
margin: 2px 0 !important;
}
hr {
margin-top: .2em;
}
code {
font-size: .9em;
}
}
&:hover {
span.remove {
opacity: .5;
}
}
span.remove {
font-size: 1.2em;
color: @StatusRemove;
margin-left: 6px;
cursor: pointer;
opacity: 0;
&:hover {
opacity: 1;
}
}
&:last-child {
border-bottom: none;
}
}
}
&.cannotAddComments {
padding-bottom: 0;
}
}
#UserDetailTab-JobsContainer { #UserDetailTab-JobsContainer {
div.jobTable { div.jobTable {
margin: -1px; min-height: 320px;
border: 1px solid #ddd; border-top: 1px solid @SubtleBorderColour;
border-right: 1px solid @SubtleBorderColour;
border-bottom: 1px solid @SubtleBorderColour;
} }
.dataTables_wrapper { .dataTables_wrapper {
File diff suppressed because one or more lines are too long
+3 -2
View File
@@ -24,7 +24,7 @@ namespace Disco.Web.Controllers
var m = new Models.User.IndexModel(); var m = new Models.User.IndexModel();
// UI Extensions // UI Extensions
UIExtensions.ExecuteExtensions<UserIndexModel>(this.ControllerContext, m); UIExtensions.ExecuteExtensions<UserIndexModel>(ControllerContext, m);
return View(); return View();
} }
@@ -64,6 +64,7 @@ namespace Disco.Web.Controllers
.Include(u => u.UserFlagAssignments.Select(ufa => ufa.AddedUser)) .Include(u => u.UserFlagAssignments.Select(ufa => ufa.AddedUser))
.Include(u => u.UserFlagAssignments.Select(ufa => ufa.RemovedUser)) .Include(u => u.UserFlagAssignments.Select(ufa => ufa.RemovedUser))
.Include(u => u.UserDetails) .Include(u => u.UserDetails)
.Include(u => u.UserComments.Select(c => c.TechUser))
.FirstOrDefault(um => um.UserId == id); .FirstOrDefault(um => um.UserId == id);
if (m.User == null) if (m.User == null)
@@ -121,7 +122,7 @@ namespace Disco.Web.Controllers
} }
// UI Extensions // UI Extensions
UIExtensions.ExecuteExtensions<UserShowModel>(this.ControllerContext, m); UIExtensions.ExecuteExtensions<UserShowModel>(ControllerContext, m);
return View(m); return View(m);
} }
+13 -4
View File
@@ -1331,10 +1331,15 @@
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>_AssignmentHistory.cshtml</DependentUpon> <DependentUpon>_AssignmentHistory.cshtml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\User\UserParts\_Jobs.generated.cs"> <Compile Include="Views\User\UserParts\_CommentsAndJobs.generated.cs">
<DependentUpon>_CommentsAndJobs.cshtml</DependentUpon>
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
</Compile>
<Compile Include="Views\User\UserParts\Comments.generated.cs">
<DependentUpon>Comments.cshtml</DependentUpon>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<DependentUpon>_Jobs.cshtml</DependentUpon>
</Compile> </Compile>
<Compile Include="Views\User\UserParts\_Resources.generated.cs"> <Compile Include="Views\User\UserParts\_Resources.generated.cs">
<DependentUpon>_Resources.cshtml</DependentUpon> <DependentUpon>_Resources.cshtml</DependentUpon>
@@ -2566,9 +2571,13 @@
<Generator>RazorGenerator</Generator> <Generator>RazorGenerator</Generator>
<LastGenOutput>_AssignmentHistory.generated.cs</LastGenOutput> <LastGenOutput>_AssignmentHistory.generated.cs</LastGenOutput>
</None> </None>
<None Include="Views\User\UserParts\_Jobs.cshtml"> <None Include="Views\User\UserParts\_CommentsAndJobs.cshtml">
<Generator>RazorGenerator</Generator> <Generator>RazorGenerator</Generator>
<LastGenOutput>_Jobs.generated.cs</LastGenOutput> <LastGenOutput>_CommentsAndJobs.generated.cs</LastGenOutput>
</None>
<None Include="Views\User\UserParts\Comments.cshtml">
<Generator>RazorGenerator</Generator>
<LastGenOutput>Comments.generated.cs</LastGenOutput>
</None> </None>
<None Include="Views\User\UserParts\_Resources.cshtml"> <None Include="Views\User\UserParts\_Resources.cshtml">
<Generator>RazorGenerator</Generator> <Generator>RazorGenerator</Generator>
@@ -59,6 +59,30 @@ namespace Disco.Web.Areas.API.Controllers
return RedirectToActionPermanent(taskResult.Result); return RedirectToActionPermanent(taskResult.Result);
} }
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Comments()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Comments);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult Comment()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Comment);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult CommentAdd()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentAdd);
}
[NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult CommentRemove()
{
return new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentRemove);
}
[NonAction] [NonAction]
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public virtual System.Web.Mvc.ActionResult AttachmentDownload() public virtual System.Web.Mvc.ActionResult AttachmentDownload()
@@ -136,6 +160,10 @@ namespace Disco.Web.Areas.API.Controllers
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionNamesClass public class ActionNamesClass
{ {
public readonly string Comments = "Comments";
public readonly string Comment = "Comment";
public readonly string CommentAdd = "CommentAdd";
public readonly string CommentRemove = "CommentRemove";
public readonly string AttachmentDownload = "AttachmentDownload"; public readonly string AttachmentDownload = "AttachmentDownload";
public readonly string AttachmentThumbnail = "AttachmentThumbnail"; public readonly string AttachmentThumbnail = "AttachmentThumbnail";
public readonly string AttachmentUpload = "AttachmentUpload"; public readonly string AttachmentUpload = "AttachmentUpload";
@@ -151,6 +179,10 @@ namespace Disco.Web.Areas.API.Controllers
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionNameConstants public class ActionNameConstants
{ {
public const string Comments = "Comments";
public const string Comment = "Comment";
public const string CommentAdd = "CommentAdd";
public const string CommentRemove = "CommentRemove";
public const string AttachmentDownload = "AttachmentDownload"; public const string AttachmentDownload = "AttachmentDownload";
public const string AttachmentThumbnail = "AttachmentThumbnail"; public const string AttachmentThumbnail = "AttachmentThumbnail";
public const string AttachmentUpload = "AttachmentUpload"; public const string AttachmentUpload = "AttachmentUpload";
@@ -164,6 +196,41 @@ namespace Disco.Web.Areas.API.Controllers
} }
static readonly ActionParamsClass_Comments s_params_Comments = new ActionParamsClass_Comments();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Comments CommentsParams { get { return s_params_Comments; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Comments
{
public readonly string id = "id";
public readonly string domain = "domain";
}
static readonly ActionParamsClass_Comment s_params_Comment = new ActionParamsClass_Comment();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_Comment CommentParams { get { return s_params_Comment; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_Comment
{
public readonly string id = "id";
}
static readonly ActionParamsClass_CommentAdd s_params_CommentAdd = new ActionParamsClass_CommentAdd();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_CommentAdd CommentAddParams { get { return s_params_CommentAdd; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_CommentAdd
{
public readonly string id = "id";
public readonly string domain = "domain";
public readonly string comment = "comment";
}
static readonly ActionParamsClass_CommentRemove s_params_CommentRemove = new ActionParamsClass_CommentRemove();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_CommentRemove CommentRemoveParams { get { return s_params_CommentRemove; } }
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public class ActionParamsClass_CommentRemove
{
public readonly string id = "id";
}
static readonly ActionParamsClass_AttachmentDownload s_params_AttachmentDownload = new ActionParamsClass_AttachmentDownload(); static readonly ActionParamsClass_AttachmentDownload s_params_AttachmentDownload = new ActionParamsClass_AttachmentDownload();
[GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode] [GeneratedCode("T4MVC", "2.0"), DebuggerNonUserCode]
public ActionParamsClass_AttachmentDownload AttachmentDownloadParams { get { return s_params_AttachmentDownload; } } public ActionParamsClass_AttachmentDownload AttachmentDownloadParams { get { return s_params_AttachmentDownload; } }
@@ -271,6 +338,57 @@ namespace Disco.Web.Areas.API.Controllers
{ {
public T4MVC_UserController() : base(Dummy.Instance) { } public T4MVC_UserController() : base(Dummy.Instance) { }
[NonAction]
partial void CommentsOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string domain);
[NonAction]
public override System.Web.Mvc.ActionResult Comments(string id, string domain)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Comments);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "domain", domain);
CommentsOverride(callInfo, id, domain);
return callInfo;
}
[NonAction]
partial void CommentOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id);
[NonAction]
public override System.Web.Mvc.ActionResult Comment(int id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Comment);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
CommentOverride(callInfo, id);
return callInfo;
}
[NonAction]
partial void CommentAddOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, string id, string domain, string comment);
[NonAction]
public override System.Web.Mvc.ActionResult CommentAdd(string id, string domain, string comment)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentAdd);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "domain", domain);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "comment", comment);
CommentAddOverride(callInfo, id, domain, comment);
return callInfo;
}
[NonAction]
partial void CommentRemoveOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id);
[NonAction]
public override System.Web.Mvc.ActionResult CommentRemove(int id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.CommentRemove);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "id", id);
CommentRemoveOverride(callInfo, id);
return callInfo;
}
[NonAction] [NonAction]
partial void AttachmentDownloadOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id); partial void AttachmentDownloadOverride(T4MVC_System_Web_Mvc_ActionResult callInfo, int id);
+34 -14
View File
@@ -1,6 +1,5 @@
using Disco.Services.Interop.ActiveDirectory; using Disco.Services.Interop.ActiveDirectory;
using System; using System;
using System.Threading.Tasks;
using System.Web.Mvc; using System.Web.Mvc;
namespace Disco.Web.Controllers namespace Disco.Web.Controllers
@@ -38,13 +37,34 @@ namespace Disco.Web.Areas.API.Controllers
{ {
public partial class UserController public partial class UserController
{ {
[NonAction]
public virtual ActionResult Comments(string id)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(Comments));
Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
return callInfo;
}
[NonAction]
public virtual ActionResult CommentAdd(string id, string comment = null)
{
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(CommentAdd));
Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, nameof(comment), comment);
return callInfo;
}
[NonAction] [NonAction]
public virtual ActionResult AttachmentUpload(string id, string Comments) public virtual ActionResult AttachmentUpload(string id, string Comments)
{ {
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.AttachmentUpload); var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(AttachmentUpload));
Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "Comments", Comments); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, nameof(Comments), Comments);
return callInfo; return callInfo;
} }
@@ -53,9 +73,9 @@ namespace Disco.Web.Areas.API.Controllers
[NonAction] [NonAction]
public virtual ActionResult Attachments(string id) public virtual ActionResult Attachments(string id)
{ {
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.Attachments); var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(Attachments));
Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
return callInfo; return callInfo;
} }
@@ -63,9 +83,9 @@ namespace Disco.Web.Areas.API.Controllers
[NonAction] [NonAction]
public virtual ActionResult AttachmentOnlineUploadSession(string id) public virtual ActionResult AttachmentOnlineUploadSession(string id)
{ {
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.AttachmentOnlineUploadSession); var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(AttachmentOnlineUploadSession));
Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
return callInfo; return callInfo;
} }
@@ -73,10 +93,10 @@ namespace Disco.Web.Areas.API.Controllers
[NonAction] [NonAction]
public virtual ActionResult GeneratePdf(string id, string DocumentTemplateId) public virtual ActionResult GeneratePdf(string id, string DocumentTemplateId)
{ {
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.GeneratePdf); var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(GeneratePdf));
Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "DocumentTemplateId", DocumentTemplateId); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, nameof(DocumentTemplateId), DocumentTemplateId);
return callInfo; return callInfo;
} }
@@ -84,10 +104,10 @@ namespace Disco.Web.Areas.API.Controllers
[NonAction] [NonAction]
public virtual ActionResult GeneratePdfPackage(string id, string DocumentTemplatePackageId) public virtual ActionResult GeneratePdfPackage(string id, string DocumentTemplatePackageId)
{ {
var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, ActionNames.GeneratePdfPackage); var callInfo = new T4MVC_System_Web_Mvc_ActionResult(Area, Name, nameof(GeneratePdfPackage));
Disco.Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id); Web.Controllers.UserController.T4MVCAddUserIdRouteValues(callInfo, id);
ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, "DocumentTemplatePackageId", DocumentTemplatePackageId); ModelUnbinderHelpers.AddRouteValues(callInfo.RouteValueDictionary, nameof(DocumentTemplatePackageId), DocumentTemplatePackageId);
return callInfo; return callInfo;
} }
@@ -132,17 +132,19 @@ namespace Disco.Web.Controllers
{ {
public readonly string _AssignmentHistory = "_AssignmentHistory"; public readonly string _AssignmentHistory = "_AssignmentHistory";
public readonly string _Authorization = "_Authorization"; public readonly string _Authorization = "_Authorization";
public readonly string _CommentsAndJobs = "_CommentsAndJobs";
public readonly string _Flags = "_Flags"; public readonly string _Flags = "_Flags";
public readonly string _Jobs = "_Jobs";
public readonly string _Resources = "_Resources"; public readonly string _Resources = "_Resources";
public readonly string _Subject = "_Subject"; public readonly string _Subject = "_Subject";
public readonly string Comments = "Comments";
} }
public readonly string _AssignmentHistory = "~/Views/User/UserParts/_AssignmentHistory.cshtml"; public readonly string _AssignmentHistory = "~/Views/User/UserParts/_AssignmentHistory.cshtml";
public readonly string _Authorization = "~/Views/User/UserParts/_Authorization.cshtml"; public readonly string _Authorization = "~/Views/User/UserParts/_Authorization.cshtml";
public readonly string _CommentsAndJobs = "~/Views/User/UserParts/_CommentsAndJobs.cshtml";
public readonly string _Flags = "~/Views/User/UserParts/_Flags.cshtml"; public readonly string _Flags = "~/Views/User/UserParts/_Flags.cshtml";
public readonly string _Jobs = "~/Views/User/UserParts/_Jobs.cshtml";
public readonly string _Resources = "~/Views/User/UserParts/_Resources.cshtml"; public readonly string _Resources = "~/Views/User/UserParts/_Resources.cshtml";
public readonly string _Subject = "~/Views/User/UserParts/_Subject.cshtml"; public readonly string _Subject = "~/Views/User/UserParts/_Subject.cshtml";
public readonly string Comments = "~/Views/User/UserParts/Comments.cshtml";
} }
} }
} }
+80 -3
View File
@@ -4,8 +4,15 @@
Authorization.Require(Claims.User.Show); Authorization.Require(Claims.User.Show);
ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.FriendlyId())); ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.FriendlyId()));
var requiresLive = Authorization.HasAny(Claims.User.ShowComments, Claims.User.ShowAttachments);
if (requiresLive)
{
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
}
} }
<div id="User_Show"> <div id="User_Show" data-userid="@Model.User.UserId">
@if (Authorization.Has(Claims.User.ShowFlagAssignments)) @if (Authorization.Has(Claims.User.ShowFlagAssignments))
{ {
<div id="User_Show_Flags"> <div id="User_Show_Flags">
@@ -87,9 +94,9 @@
</script> </script>
<div id="UserDetailTabs"> <div id="UserDetailTabs">
<ul id="UserDetailTabItems"></ul> <ul id="UserDetailTabItems"></ul>
@if (Authorization.Has(Claims.User.ShowJobs)) @if (Authorization.HasAny(Claims.User.ShowComments, Claims.User.ShowJobs))
{ {
@Html.Partial(MVC.User.Views.UserParts._Jobs, Model) @Html.Partial(MVC.User.Views.UserParts._CommentsAndJobs, Model)
} }
@if (Authorization.Has(Claims.User.ShowAssignmentHistory)) @if (Authorization.Has(Claims.User.ShowAssignmentHistory))
{ {
@@ -108,4 +115,74 @@
@Html.Partial(MVC.User.Views.UserParts._Authorization, Model) @Html.Partial(MVC.User.Views.UserParts._Authorization, Model)
} }
</div> </div>
@if (requiresLive)
{
<script>
$(function () {
if (!document.DiscoFunctions)
return;
const userId = $('#User_Show').attr('data-userid');
// Connect to Hub
var hub = $.connection.userUpdates;
// Map Functions
if (document.DiscoFunctions.onCommentAdded)
hub.client.commentAdded = document.DiscoFunctions.onCommentAdded;
if (document.DiscoFunctions.onCommentRemoved)
hub.client.commentRemoved = document.DiscoFunctions.onCommentRemoved;
if (document.DiscoFunctions.onAttachmentAdded)
hub.client.attachmentAdded = document.DiscoFunctions.onAttachmentAdded;
if (document.DiscoFunctions.onAttachmentRemoved)
hub.client.attachmentRemoved = document.DiscoFunctions.onAttachmentRemoved;
$.connection.hub.qs = { UserId: userId };
$.connection.hub.error(onHubFailed);
$.connection.hub.disconnected(onHubFailed);
$.connection.hub.reconnecting(function () {
$('#AttachmentsContainer').find('span.action.enabled').addClass('disabled');
$('#Comments').find('button').prop('disabled', true);
});
$.connection.hub.reconnected(function () {
$('#AttachmentsContainer').find('span.action.enabled').removeClass('disabled');
$('#Comments').find('button').prop('disabled', false);
});
// Start Connection
$.connection.hub.start(function () {
$('#AttachmentsContainer').find('span.action.enabled').removeClass('disabled');
$('#Comments').find('button').prop('disabled', false);
}).fail(onHubFailed);
function onHubFailed(error) {
// Disable UI
$('#AttachmentsContainer').find('span.action.enabled').addClass('disabled');
$('#Comments').find('button').prop('disabled', true);
// Show Dialog Message
if ($('.disconnected-dialog').length == 0) {
$('<div>')
.addClass('dialog disconnected-dialog')
.html('<h3><span class="fa-stack fa-lg"><i class="fa fa-wifi fa-stack-1x"></i><i class="fa fa-ban fa-stack-2x error"></i></span>Disconnected from the Disco ICT Server</h3><div>This page is not receiving live updates. Please ensure you are connected to the server, then refresh this page to enable features.</div>')
.dialog({
resizable: false,
title: 'Disconnected',
width: 400,
modal: true,
buttons: {
'Refresh Now': function () {
$(this).dialog('option', 'buttons', null);
window.location.reload(true);
},
'Close': function () {
$(this).dialog('destroy');
}
}
});
}
}
});
</script>
}
</div> </div>
+133 -45
View File
@@ -56,6 +56,13 @@ namespace Disco.Web.Views.User
ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.FriendlyId())); ViewBag.Title = Html.ToBreadcrumb("Users", MVC.User.Index(), string.Format("User: {0} ({1})", Model.User.DisplayName, Model.User.FriendlyId()));
var requiresLive = Authorization.HasAny(Claims.User.ShowComments, Claims.User.ShowAttachments);
if (requiresLive)
{
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
}
#line default #line default
#line hidden #line hidden
@@ -63,16 +70,27 @@ WriteLiteral("\r\n<div");
WriteLiteral(" id=\"User_Show\""); WriteLiteral(" id=\"User_Show\"");
WriteLiteral(" data-userid=\"");
#line 15 "..\..\Views\User\Show.cshtml"
Write(Model.User.UserId);
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
#line 9 "..\..\Views\User\Show.cshtml" #line 16 "..\..\Views\User\Show.cshtml"
#line default #line default
#line hidden #line hidden
#line 9 "..\..\Views\User\Show.cshtml" #line 16 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowFlagAssignments)) if (Authorization.Has(Claims.User.ShowFlagAssignments))
{ {
@@ -86,13 +104,13 @@ WriteLiteral(" id=\"User_Show_Flags\"");
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
#line 12 "..\..\Views\User\Show.cshtml" #line 19 "..\..\Views\User\Show.cshtml"
#line default #line default
#line hidden #line hidden
#line 12 "..\..\Views\User\Show.cshtml" #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)))) foreach (var flag in Model.User.UserFlagAssignments.Where(f => !f.RemovedDate.HasValue).Select(f => Tuple.Create(f, UserFlagService.GetUserFlag(f.UserFlagId))))
{ {
@@ -101,27 +119,27 @@ WriteLiteral(">\r\n");
#line hidden #line hidden
WriteLiteral(" <i"); WriteLiteral(" <i");
WriteAttribute("class", Tuple.Create(" class=\"", 620), Tuple.Create("\"", 696) WriteAttribute("class", Tuple.Create(" class=\"", 867), Tuple.Create("\"", 943)
, Tuple.Create(Tuple.Create("", 628), Tuple.Create("flag", 628), true) , Tuple.Create(Tuple.Create("", 875), Tuple.Create("flag", 875), true)
, Tuple.Create(Tuple.Create(" ", 632), Tuple.Create("fa", 633), true) , Tuple.Create(Tuple.Create(" ", 879), Tuple.Create("fa", 880), true)
, Tuple.Create(Tuple.Create(" ", 635), Tuple.Create("fa-", 636), true) , Tuple.Create(Tuple.Create(" ", 882), Tuple.Create("fa-", 883), true)
#line 14 "..\..\Views\User\Show.cshtml" #line 21 "..\..\Views\User\Show.cshtml"
, Tuple.Create(Tuple.Create("", 639), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon , Tuple.Create(Tuple.Create("", 886), Tuple.Create<System.Object, System.Int32>(flag.Item2.Icon
#line default #line default
#line hidden #line hidden
, 639), false) , 886), false)
, Tuple.Create(Tuple.Create(" ", 657), Tuple.Create("fa-fw", 658), true) , Tuple.Create(Tuple.Create(" ", 904), Tuple.Create("fa-fw", 905), true)
, Tuple.Create(Tuple.Create(" ", 663), Tuple.Create("fa-lg", 664), true) , Tuple.Create(Tuple.Create(" ", 910), Tuple.Create("fa-lg", 911), true)
, Tuple.Create(Tuple.Create(" ", 669), Tuple.Create("d-", 670), true) , Tuple.Create(Tuple.Create(" ", 916), Tuple.Create("d-", 917), true)
#line 14 "..\..\Views\User\Show.cshtml" #line 21 "..\..\Views\User\Show.cshtml"
, Tuple.Create(Tuple.Create("", 672), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour , Tuple.Create(Tuple.Create("", 919), Tuple.Create<System.Object, System.Int32>(flag.Item2.IconColour
#line default #line default
#line hidden #line hidden
, 672), false) , 919), false)
); );
WriteLiteral(">\r\n <span"); WriteLiteral(">\r\n <span");
@@ -135,7 +153,7 @@ WriteLiteral(" class=\"name\"");
WriteLiteral(">"); WriteLiteral(">");
#line 16 "..\..\Views\User\Show.cshtml" #line 23 "..\..\Views\User\Show.cshtml"
Write(flag.Item2.Name); Write(flag.Item2.Name);
@@ -144,7 +162,7 @@ WriteLiteral(">");
WriteLiteral("</span>"); WriteLiteral("</span>");
#line 16 "..\..\Views\User\Show.cshtml" #line 23 "..\..\Views\User\Show.cshtml"
if (flag.Item1.Comments != null) if (flag.Item1.Comments != null)
{ {
@@ -157,7 +175,7 @@ WriteLiteral(" class=\"comments\"");
WriteLiteral(">"); WriteLiteral(">");
#line 17 "..\..\Views\User\Show.cshtml" #line 24 "..\..\Views\User\Show.cshtml"
Write(flag.Item1.Comments.ToHtmlComment()); Write(flag.Item1.Comments.ToHtmlComment());
@@ -166,7 +184,7 @@ WriteLiteral(">");
WriteLiteral("</span>"); WriteLiteral("</span>");
#line 17 "..\..\Views\User\Show.cshtml" #line 24 "..\..\Views\User\Show.cshtml"
} }
#line default #line default
@@ -178,7 +196,7 @@ WriteLiteral(" class=\"added\"");
WriteLiteral(">"); WriteLiteral(">");
#line 17 "..\..\Views\User\Show.cshtml" #line 24 "..\..\Views\User\Show.cshtml"
Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser)); Write(CommonHelpers.FriendlyDateAndUser(flag.Item1.AddedDate, flag.Item1.AddedUser));
@@ -187,7 +205,7 @@ WriteLiteral(">");
WriteLiteral("</span>\r\n </span>\r\n </i>\r\n"); WriteLiteral("</span>\r\n </span>\r\n </i>\r\n");
#line 20 "..\..\Views\User\Show.cshtml" #line 27 "..\..\Views\User\Show.cshtml"
} }
@@ -233,7 +251,7 @@ WriteLiteral(@">
"); ");
#line 53 "..\..\Views\User\Show.cshtml" #line 60 "..\..\Views\User\Show.cshtml"
} }
@@ -242,7 +260,7 @@ WriteLiteral(@">
WriteLiteral(" "); WriteLiteral(" ");
#line 54 "..\..\Views\User\Show.cshtml" #line 61 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Subject, Model)); Write(Html.Partial(MVC.User.Views.UserParts._Subject, Model));
@@ -282,29 +300,29 @@ WriteLiteral(" id=\"UserDetailTabItems\"");
WriteLiteral("></ul>\r\n"); WriteLiteral("></ul>\r\n");
#line 90 "..\..\Views\User\Show.cshtml" #line 97 "..\..\Views\User\Show.cshtml"
#line default #line default
#line hidden #line hidden
#line 90 "..\..\Views\User\Show.cshtml" #line 97 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowJobs)) if (Authorization.HasAny(Claims.User.ShowComments, Claims.User.ShowJobs))
{ {
#line default #line default
#line hidden #line hidden
#line 92 "..\..\Views\User\Show.cshtml" #line 99 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Jobs, Model)); Write(Html.Partial(MVC.User.Views.UserParts._CommentsAndJobs, Model));
#line default #line default
#line hidden #line hidden
#line 92 "..\..\Views\User\Show.cshtml" #line 99 "..\..\Views\User\Show.cshtml"
} }
@@ -313,7 +331,7 @@ WriteLiteral("></ul>\r\n");
WriteLiteral(" "); WriteLiteral(" ");
#line 94 "..\..\Views\User\Show.cshtml" #line 101 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowAssignmentHistory)) if (Authorization.Has(Claims.User.ShowAssignmentHistory))
{ {
@@ -321,14 +339,14 @@ WriteLiteral(" ");
#line default #line default
#line hidden #line hidden
#line 96 "..\..\Views\User\Show.cshtml" #line 103 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._AssignmentHistory, Model)); Write(Html.Partial(MVC.User.Views.UserParts._AssignmentHistory, Model));
#line default #line default
#line hidden #line hidden
#line 96 "..\..\Views\User\Show.cshtml" #line 103 "..\..\Views\User\Show.cshtml"
} }
@@ -338,7 +356,7 @@ WriteLiteral(" ");
WriteLiteral(" "); WriteLiteral(" ");
#line 98 "..\..\Views\User\Show.cshtml" #line 105 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowAttachments)) if (Authorization.Has(Claims.User.ShowAttachments))
{ {
@@ -346,14 +364,14 @@ WriteLiteral(" ");
#line default #line default
#line hidden #line hidden
#line 100 "..\..\Views\User\Show.cshtml" #line 107 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Resources, Model)); Write(Html.Partial(MVC.User.Views.UserParts._Resources, Model));
#line default #line default
#line hidden #line hidden
#line 100 "..\..\Views\User\Show.cshtml" #line 107 "..\..\Views\User\Show.cshtml"
} }
@@ -363,7 +381,7 @@ WriteLiteral(" ");
WriteLiteral(" "); WriteLiteral(" ");
#line 102 "..\..\Views\User\Show.cshtml" #line 109 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowFlagAssignments)) if (Authorization.Has(Claims.User.ShowFlagAssignments))
{ {
@@ -371,14 +389,14 @@ WriteLiteral(" ");
#line default #line default
#line hidden #line hidden
#line 104 "..\..\Views\User\Show.cshtml" #line 111 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Flags, Model)); Write(Html.Partial(MVC.User.Views.UserParts._Flags, Model));
#line default #line default
#line hidden #line hidden
#line 104 "..\..\Views\User\Show.cshtml" #line 111 "..\..\Views\User\Show.cshtml"
} }
@@ -388,7 +406,7 @@ WriteLiteral(" ");
WriteLiteral(" "); WriteLiteral(" ");
#line 106 "..\..\Views\User\Show.cshtml" #line 113 "..\..\Views\User\Show.cshtml"
if (Authorization.Has(Claims.User.ShowAuthorization)) if (Authorization.Has(Claims.User.ShowAuthorization))
{ {
@@ -396,21 +414,91 @@ WriteLiteral(" ");
#line default #line default
#line hidden #line hidden
#line 108 "..\..\Views\User\Show.cshtml" #line 115 "..\..\Views\User\Show.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts._Authorization, Model)); Write(Html.Partial(MVC.User.Views.UserParts._Authorization, Model));
#line default #line default
#line hidden #line hidden
#line 108 "..\..\Views\User\Show.cshtml" #line 115 "..\..\Views\User\Show.cshtml"
} }
#line default #line default
#line hidden #line hidden
WriteLiteral(" </div>\r\n</div>\r\n"); WriteLiteral(" </div>\r\n");
#line 118 "..\..\Views\User\Show.cshtml"
#line default
#line hidden
#line 118 "..\..\Views\User\Show.cshtml"
if (requiresLive)
{
#line default
#line hidden
WriteLiteral(" <script>\r\n $(function () {\r\n if (!document.Disc" +
"oFunctions)\r\n return;\r\n\r\n const userId = $(\'#U" +
"ser_Show\').attr(\'data-userid\');\r\n // Connect to Hub\r\n " +
" var hub = $.connection.userUpdates;\r\n\r\n // Map Functions\r\n " +
" if (document.DiscoFunctions.onCommentAdded)\r\n hu" +
"b.client.commentAdded = document.DiscoFunctions.onCommentAdded;\r\n " +
" if (document.DiscoFunctions.onCommentRemoved)\r\n hub.client.c" +
"ommentRemoved = document.DiscoFunctions.onCommentRemoved;\r\n if (d" +
"ocument.DiscoFunctions.onAttachmentAdded)\r\n hub.client.attach" +
"mentAdded = document.DiscoFunctions.onAttachmentAdded;\r\n if (docu" +
"ment.DiscoFunctions.onAttachmentRemoved)\r\n hub.client.attachm" +
"entRemoved = document.DiscoFunctions.onAttachmentRemoved;\r\n\r\n $.c" +
"onnection.hub.qs = { UserId: userId };\r\n $.connection.hub.error(o" +
"nHubFailed);\r\n $.connection.hub.disconnected(onHubFailed);\r\n\r\n " +
" $.connection.hub.reconnecting(function () {\r\n $(" +
"\'#AttachmentsContainer\').find(\'span.action.enabled\').addClass(\'disabled\');\r\n " +
" $(\'#Comments\').find(\'button\').prop(\'disabled\', true);\r\n " +
" });\r\n $.connection.hub.reconnected(function () {\r\n " +
" $(\'#AttachmentsContainer\').find(\'span.action.enabled\').removeClass(\'" +
"disabled\');\r\n $(\'#Comments\').find(\'button\').prop(\'disabled\', " +
"false);\r\n });\r\n\r\n // Start Connection\r\n " +
" $.connection.hub.start(function () {\r\n $(\'#AttachmentsCo" +
"ntainer\').find(\'span.action.enabled\').removeClass(\'disabled\');\r\n " +
" $(\'#Comments\').find(\'button\').prop(\'disabled\', false);\r\n }).f" +
"ail(onHubFailed);\r\n\r\n function onHubFailed(error) {\r\n " +
" // Disable UI\r\n $(\'#AttachmentsContainer\').find(\'span" +
".action.enabled\').addClass(\'disabled\');\r\n $(\'#Comments\').find" +
"(\'button\').prop(\'disabled\', true);\r\n\r\n // Show Dialog Message" +
"\r\n if ($(\'.disconnected-dialog\').length == 0) {\r\n " +
" $(\'<div>\')\r\n .addClass(\'dialog disconnect" +
"ed-dialog\')\r\n .html(\'<h3><span class=\"fa-stack fa-lg\"" +
"><i class=\"fa fa-wifi fa-stack-1x\"></i><i class=\"fa fa-ban fa-stack-2x error\"></" +
"i></span>Disconnected from the Disco ICT Server</h3><div>This page is not receiv" +
"ing live updates. Please ensure you are connected to the server, then refresh th" +
"is page to enable features.</div>\')\r\n .dialog({\r\n " +
" resizable: false,\r\n t" +
"itle: \'Disconnected\',\r\n width: 400,\r\n " +
" modal: true,\r\n buttons: {\r\n " +
" \'Refresh Now\': function () {\r\n " +
" $(this).dialog(\'option\', \'buttons\', null);\r\n " +
" window.location.reload(true);\r\n " +
" },\r\n \'Close\': function () {\r\n " +
" $(this).dialog(\'destroy\');\r\n " +
" }\r\n }\r\n " +
" });\r\n }\r\n }\r\n });\r\n " +
" </script>\r\n");
#line 187 "..\..\Views\User\Show.cshtml"
}
#line default
#line hidden
WriteLiteral("</div>\r\n");
} }
} }
@@ -0,0 +1,212 @@
@model Disco.Web.Models.User.ShowModel
@{
Authorization.Require(Claims.User.ShowComments);
var canAddComments = Authorization.Has(Claims.User.Actions.AddComments);
var canRemoveAnyComments = Authorization.Has(Claims.User.Actions.RemoveAnyComments);
var canRemoveOwnComments = Authorization.Has(Claims.User.Actions.RemoveOwnComments);
}
<div id="Comments" class="@(canAddComments ? "canAddComments" : "cannotAddComments") @(canRemoveAnyComments ? "canRemoveAnyComments" : "cannotRemoveAnyComments") @(canRemoveOwnComments ? "canRemoveOwnComments" : "cannotRemoveOwnComments")" data-id="@Model.User.UserId" data-userid="@CurrentUser.UserId" data-addurl="@Url.Action(MVC.API.User.CommentAdd(Model.User.UserId))" data-removeurl="@Url.Action(MVC.API.User.CommentRemove())" data-geturl="@Url.Action(MVC.API.User.Comment())">
@Html.AntiForgeryToken()
@if (canAddComments)
{
<div class="commentInput">
<textarea class="commentInput" placeholder="add comment..." accesskey="l"></textarea>
<button type="button" title="Add Comment" disabled><i class="fa fa-comment"></i></button>
</div>
}
<div class="commentOutput">
@foreach (var c in Model.User.UserComments.OrderBy(m => m.Timestamp))
{
<div class="comment" data-commentid="@c.Id">
<span class="author">@c.TechUser.ToStringFriendly()</span>@if (canRemoveAnyComments || (canRemoveOwnComments && c.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase)))
{<text><span class="remove fa fa-times-circle"></span></text>}<span class="timestamp" data-livestamp="@(c.Timestamp.ToUnixEpoc())" title="@c.Timestamp.ToFullDateTime()">@c.Timestamp.ToFullDateTime()</span>
<div class="comment">@c.Comments.ToHtmlComment()</div>
</div>
}
</div>
</div>
<script>
if (!document.DiscoFunctions) {
document.DiscoFunctions = {};
}
$(function () {
const $comments = $('#Comments');
const $commentOutput = $comments.find('.commentOutput');
window.setTimeout(function () {
$commentOutput[0].scrollTop = $commentOutput[0].scrollHeight; // Scroll to Bottom
}, 0);
$('#UserDetailTabs').on('tabsactivate', function (event, ui) {
if (ui.newPanel && ui.newPanel.is('#UserDetailTab-CommentsAndJobs')) {
$commentOutput[0].scrollTop = $commentOutput[0].scrollHeight; // Scroll to Bottom
}
});
function onCommentAdded(id) {
onCommentAddedAsync(id);
}
async function onCommentAddedAsync(id) {
const formData = new FormData();
formData.append('__RequestVerificationToken', $comments.find('input[name="__RequestVerificationToken"]').val());
formData.append('id', id);
const response = await fetch($comments.attr('data-geturl'), {
method: 'POST',
body: formData
});
if (!response.ok) {
alert('Unable to load live comment ' + id + ': ' + response.statusText);
} else {
const comment = await response.json();
if ($comments.hasClass('canRemoveAnyComments'))
renderComment(comment, false, true);
else if ($comments.hasClass('canRemoveOwnComments'))
renderComment(comment, false, (comment.AuthorId === $comments.attr('data-userid')));
else
renderComment(comment, false, false);
}
}
function onCommentRemoved(id) {
$commentOutput.children('div[data-commentid="' + id + '"]').slideUp(300).delay(300).queue(function () {
const $this = $(this);
$this.find('.timestamp').livestamp('destroy');
$this.remove();
});
}
function renderComment(c, quick, canRemove) {
let t = '<div><span class="author" />';
if (canRemove)
t += '<span class="remove fa fa-times-circle" />';
t += '<span class="timestamp" /><div class="comment" /></div>';
const e = $(t);
e.attr('data-commentid', c.Id);
e.find('.author').text(c.Author);
e.find('.timestamp').text(c.TimestampFull).attr('title', c.TimestampFull).livestamp(c.TimestampUnixEpoc);
e.find('.comment').html(c.HtmlComments);
$commentOutput.append(e);
if (!quick) {
e.animate({ backgroundColor: '#ffff99' }, 500, function () {
e.animate({ backgroundColor: '#fafafa' }, 500, function () {
e.css('background-color', '');
});
});
$commentOutput.animate({ scrollTop: $commentOutput[0].scrollHeight }, 250)
}
}
document.DiscoFunctions.onCommentAdded = onCommentAdded;
document.DiscoFunctions.onCommentRemoved = onCommentRemoved;
});
</script>
@if (canAddComments)
{
<script>
$(function () {
const $comments = $('#Comments');
const $commentInput = $comments.find('textarea.commentInput');
const $commentInputButton = $comments.find('button');
$commentInputButton.on('click', postComment);
$commentInput.on('keypress', function (e) {
if (e.which == 13 && !e.shiftKey) {
postComment();
return false;
}
});
async function postComment() {
if ($commentInputButton.prop('disabled')) {
alert('Disconnected from the Disco ICT Server, please refresh this page and try again');
return;
}
const comment = $commentInput.val();
if (comment == '') {
alert('Enter a comment to post');
$commentInput.focus();
return;
}
$commentInput.prop('disabled', true);
const formData = new FormData();
formData.append('__RequestVerificationToken', $comments.find('input[name="__RequestVerificationToken"]').val());
formData.append('comment', comment);
const response = await fetch($comments.attr('data-addurl'), {
method: 'POST',
body: formData
});
if (response.ok) {
$commentInput.val('').prop('disabled', false).focus();
} else {
alert('Unable to add comment: ' + response.statusText);
$commentInput.prop('disabled', false).focus();
}
}
});
</script>
}
@if (canRemoveAnyComments || canRemoveOwnComments)
{
<script>
$(function () {
const $comments = $('#Comments');
const $commentOutput = $comments.find('.commentOutput');
let $dialogRemove = null;
$commentOutput.on('click', 'span.remove', removeComment);
function removeComment(e) {
e.preventDefault();
const commentId = $(this).closest('div').attr('data-commentid');
if (!$dialogRemove) {
$dialogRemove = $('<div class="dialog" title="Remove this Comment?"><p><i class="fa fa-exclamation-triangle fa-lg"></i>&nbsp;Are you sure?</p></div>')
.appendTo(document.body)
.dialog({
resizable: false,
height: 140,
modal: true,
autoOpen: false
});
}
$dialogRemove.dialog("enable").dialog('option', 'buttons', {
"Remove": function () {
$dialogRemove.dialog("disable");
$dialogRemove.dialog("option", "buttons", null);
removeCommentAsync(commentId);
},
"Cancel": function () {
$dialogRemove.dialog("close");
}
}).dialog('open');
}
async function removeCommentAsync(commentId) {
const formData = new FormData();
formData.append('__RequestVerificationToken', $comments.find('input[name="__RequestVerificationToken"]').val());
formData.append('id', commentId);
const response = await fetch($comments.attr('data-removeurl'), {
method: 'POST',
body: formData
});
if (!response.ok) {
alert('Unable to remove comment: ' + response.statusText);
}
$dialogRemove.dialog("close");
}
});
</script>
}
@@ -0,0 +1,451 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Disco.Web.Views.User.UserParts
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using Disco;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
using Disco.Web.Extensions;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/User/UserParts/Comments.cshtml")]
public partial class Comments : Disco.Services.Web.WebViewPage<Disco.Web.Models.User.ShowModel>
{
public Comments()
{
}
public override void Execute()
{
#line 2 "..\..\Views\User\UserParts\Comments.cshtml"
Authorization.Require(Claims.User.ShowComments);
var canAddComments = Authorization.Has(Claims.User.Actions.AddComments);
var canRemoveAnyComments = Authorization.Has(Claims.User.Actions.RemoveAnyComments);
var canRemoveOwnComments = Authorization.Has(Claims.User.Actions.RemoveOwnComments);
#line default
#line hidden
WriteLiteral("\r\n<div");
WriteLiteral(" id=\"Comments\"");
WriteAttribute("class", Tuple.Create(" class=\"", 377), Tuple.Create("\"", 597)
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
, Tuple.Create(Tuple.Create("", 385), Tuple.Create<System.Object, System.Int32>(canAddComments ? "canAddComments" : "cannotAddComments"
#line default
#line hidden
, 385), false)
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
, Tuple.Create(Tuple.Create(" ", 443), Tuple.Create<System.Object, System.Int32>(canRemoveAnyComments ? "canRemoveAnyComments" : "cannotRemoveAnyComments"
#line default
#line hidden
, 444), false)
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
, Tuple.Create(Tuple.Create(" ", 520), Tuple.Create<System.Object, System.Int32>(canRemoveOwnComments ? "canRemoveOwnComments" : "cannotRemoveOwnComments"
#line default
#line hidden
, 521), false)
);
WriteLiteral(" data-id=\"");
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
Write(Model.User.UserId);
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" data-userid=\"");
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
Write(CurrentUser.UserId);
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" data-addurl=\"");
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
Write(Url.Action(MVC.API.User.CommentAdd(Model.User.UserId)));
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" data-removeurl=\"");
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
Write(Url.Action(MVC.API.User.CommentRemove()));
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" data-geturl=\"");
#line 8 "..\..\Views\User\UserParts\Comments.cshtml"
Write(Url.Action(MVC.API.User.Comment()));
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 9 "..\..\Views\User\UserParts\Comments.cshtml"
Write(Html.AntiForgeryToken());
#line default
#line hidden
WriteLiteral("\r\n");
#line 10 "..\..\Views\User\UserParts\Comments.cshtml"
#line default
#line hidden
#line 10 "..\..\Views\User\UserParts\Comments.cshtml"
if (canAddComments)
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" class=\"commentInput\"");
WriteLiteral(">\r\n <textarea");
WriteLiteral(" class=\"commentInput\"");
WriteLiteral(" placeholder=\"add comment...\"");
WriteLiteral(" accesskey=\"l\"");
WriteLiteral("></textarea>\r\n <button");
WriteLiteral(" type=\"button\"");
WriteLiteral(" title=\"Add Comment\"");
WriteLiteral(" disabled><i");
WriteLiteral(" class=\"fa fa-comment\"");
WriteLiteral("></i></button>\r\n </div>\r\n");
#line 16 "..\..\Views\User\UserParts\Comments.cshtml"
}
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" class=\"commentOutput\"");
WriteLiteral(">\r\n");
#line 18 "..\..\Views\User\UserParts\Comments.cshtml"
#line default
#line hidden
#line 18 "..\..\Views\User\UserParts\Comments.cshtml"
foreach (var c in Model.User.UserComments.OrderBy(m => m.Timestamp))
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" class=\"comment\"");
WriteLiteral(" data-commentid=\"");
#line 20 "..\..\Views\User\UserParts\Comments.cshtml"
Write(c.Id);
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(">\r\n <span");
WriteLiteral(" class=\"author\"");
WriteLiteral(">");
#line 21 "..\..\Views\User\UserParts\Comments.cshtml"
Write(c.TechUser.ToStringFriendly());
#line default
#line hidden
WriteLiteral("</span>");
#line 21 "..\..\Views\User\UserParts\Comments.cshtml"
if (canRemoveAnyComments || (canRemoveOwnComments && c.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase)))
{
#line default
#line hidden
WriteLiteral("<span");
WriteLiteral(" class=\"remove fa fa-times-circle\"");
WriteLiteral("></span>");
#line 22 "..\..\Views\User\UserParts\Comments.cshtml"
}
#line default
#line hidden
WriteLiteral("<span");
WriteLiteral(" class=\"timestamp\"");
WriteLiteral(" data-livestamp=\"");
#line 22 "..\..\Views\User\UserParts\Comments.cshtml"
Write(c.Timestamp.ToUnixEpoc());
#line default
#line hidden
WriteLiteral("\"");
WriteAttribute("title", Tuple.Create(" title=\"", 1701), Tuple.Create("\"", 1738)
#line 22 "..\..\Views\User\UserParts\Comments.cshtml"
, Tuple.Create(Tuple.Create("", 1709), Tuple.Create<System.Object, System.Int32>(c.Timestamp.ToFullDateTime()
#line default
#line hidden
, 1709), false)
);
WriteLiteral(">");
#line 22 "..\..\Views\User\UserParts\Comments.cshtml"
Write(c.Timestamp.ToFullDateTime());
#line default
#line hidden
WriteLiteral("</span>\r\n <div");
WriteLiteral(" class=\"comment\"");
WriteLiteral(">");
#line 23 "..\..\Views\User\UserParts\Comments.cshtml"
Write(c.Comments.ToHtmlComment());
#line default
#line hidden
WriteLiteral("</div>\r\n </div>\r\n");
#line 25 "..\..\Views\User\UserParts\Comments.cshtml"
}
#line default
#line hidden
WriteLiteral(" </div>\r\n</div>\r\n<script>\r\n if (!document.DiscoFunctions) {\r\n docume" +
"nt.DiscoFunctions = {};\r\n }\r\n\r\n $(function () {\r\n const $comments =" +
" $(\'#Comments\');\r\n const $commentOutput = $comments.find(\'.commentOutput\'" +
");\r\n\r\n window.setTimeout(function () {\r\n $commentOutput[0].scr" +
"ollTop = $commentOutput[0].scrollHeight; // Scroll to Bottom\r\n }, 0);\r\n " +
" $(\'#UserDetailTabs\').on(\'tabsactivate\', function (event, ui) {\r\n " +
" if (ui.newPanel && ui.newPanel.is(\'#UserDetailTab-CommentsAndJobs\')) {\r\n " +
" $commentOutput[0].scrollTop = $commentOutput[0].scrollHeight; // Scrol" +
"l to Bottom\r\n }\r\n });\r\n\r\n function onCommentAdded(id) {" +
"\r\n onCommentAddedAsync(id);\r\n }\r\n async function onComm" +
"entAddedAsync(id) {\r\n const formData = new FormData();\r\n f" +
"ormData.append(\'__RequestVerificationToken\', $comments.find(\'input[name=\"__Reque" +
"stVerificationToken\"]\').val());\r\n formData.append(\'id\', id);\r\n\r\n " +
" const response = await fetch($comments.attr(\'data-geturl\'), {\r\n " +
" method: \'POST\',\r\n body: formData\r\n });\r\n\r\n " +
" if (!response.ok) {\r\n alert(\'Unable to load live comment \' " +
"+ id + \': \' + response.statusText);\r\n } else {\r\n const" +
" comment = await response.json();\r\n\r\n if ($comments.hasClass(\'can" +
"RemoveAnyComments\'))\r\n renderComment(comment, false, true);\r\n" +
" else if ($comments.hasClass(\'canRemoveOwnComments\'))\r\n " +
" renderComment(comment, false, (comment.AuthorId === $comments.attr(\'da" +
"ta-userid\')));\r\n else\r\n renderComment(comment," +
" false, false);\r\n }\r\n }\r\n function onCommentRemoved(id)" +
" {\r\n $commentOutput.children(\'div[data-commentid=\"\' + id + \'\"]\').slid" +
"eUp(300).delay(300).queue(function () {\r\n const $this = $(this);\r" +
"\n $this.find(\'.timestamp\').livestamp(\'destroy\');\r\n " +
" $this.remove();\r\n });\r\n }\r\n function renderComment(c, " +
"quick, canRemove) {\r\n let t = \'<div><span class=\"author\" />\';\r\n " +
" if (canRemove)\r\n t += \'<span class=\"remove fa fa-times-circ" +
"le\" />\';\r\n t += \'<span class=\"timestamp\" /><div class=\"comment\" /></d" +
"iv>\';\r\n\r\n const e = $(t);\r\n e.attr(\'data-commentid\', c.Id)" +
";\r\n e.find(\'.author\').text(c.Author);\r\n e.find(\'.timestamp" +
"\').text(c.TimestampFull).attr(\'title\', c.TimestampFull).livestamp(c.TimestampUni" +
"xEpoc);\r\n e.find(\'.comment\').html(c.HtmlComments);\r\n\r\n $co" +
"mmentOutput.append(e);\r\n\r\n if (!quick) {\r\n e.animate({" +
" backgroundColor: \'#ffff99\' }, 500, function () {\r\n e.animate" +
"({ backgroundColor: \'#fafafa\' }, 500, function () {\r\n e.c" +
"ss(\'background-color\', \'\');\r\n });\r\n });\r\n " +
" $commentOutput.animate({ scrollTop: $commentOutput[0].scrollHeight }," +
" 250)\r\n }\r\n }\r\n\r\n document.DiscoFunctions.onCommentAdde" +
"d = onCommentAdded;\r\n document.DiscoFunctions.onCommentRemoved = onCommen" +
"tRemoved;\r\n });\r\n</script>\r\n");
#line 107 "..\..\Views\User\UserParts\Comments.cshtml"
if (canAddComments)
{
#line default
#line hidden
WriteLiteral(" <script>\r\n $(function () {\r\n const $comments = $(\'#Comments" +
"\');\r\n const $commentInput = $comments.find(\'textarea.commentInput\');\r" +
"\n const $commentInputButton = $comments.find(\'button\');\r\n " +
"$commentInputButton.on(\'click\', postComment);\r\n $commentInput.on(\'key" +
"press\', function (e) {\r\n if (e.which == 13 && !e.shiftKey) {\r\n " +
" postComment();\r\n return false;\r\n " +
" }\r\n });\r\n\r\n async function postComment() {\r\n " +
" if ($commentInputButton.prop(\'disabled\')) {\r\n alert(\'Di" +
"sconnected from the Disco ICT Server, please refresh this page and try again\');\r" +
"\n return;\r\n }\r\n\r\n const comment" +
" = $commentInput.val();\r\n\r\n if (comment == \'\') {\r\n " +
" alert(\'Enter a comment to post\');\r\n $commentInput.focus(" +
");\r\n return;\r\n }\r\n\r\n $commentIn" +
"put.prop(\'disabled\', true);\r\n\r\n const formData = new FormData();\r" +
"\n formData.append(\'__RequestVerificationToken\', $comments.find(\'i" +
"nput[name=\"__RequestVerificationToken\"]\').val());\r\n formData.appe" +
"nd(\'comment\', comment);\r\n\r\n const response = await fetch($comment" +
"s.attr(\'data-addurl\'), {\r\n method: \'POST\',\r\n " +
" body: formData\r\n });\r\n\r\n if (response.ok) {\r\n " +
" $commentInput.val(\'\').prop(\'disabled\', false).focus();\r\n " +
" } else {\r\n alert(\'Unable to add comment: \' + respon" +
"se.statusText);\r\n $commentInput.prop(\'disabled\', false).focus" +
"();\r\n }\r\n }\r\n });\r\n </script>\r\n");
#line 156 "..\..\Views\User\UserParts\Comments.cshtml"
}
#line default
#line hidden
#line 157 "..\..\Views\User\UserParts\Comments.cshtml"
if (canRemoveAnyComments || canRemoveOwnComments)
{
#line default
#line hidden
WriteLiteral(" <script>\r\n $(function () {\r\n const $comments = $(\'#Comments" +
"\');\r\n const $commentOutput = $comments.find(\'.commentOutput\');\r\n " +
" let $dialogRemove = null;\r\n\r\n $commentOutput.on(\'click\', \'span" +
".remove\', removeComment);\r\n\r\n function removeComment(e) {\r\n " +
" e.preventDefault();\r\n\r\n const commentId = $(this).closest(\'" +
"div\').attr(\'data-commentid\');\r\n\r\n if (!$dialogRemove) {\r\n " +
" $dialogRemove = $(\'<div class=\"dialog\" title=\"Remove this Comment?\">" +
"<p><i class=\"fa fa-exclamation-triangle fa-lg\"></i>&nbsp;Are you sure?</p></div>" +
"\')\r\n .appendTo(document.body)\r\n .d" +
"ialog({\r\n resizable: false,\r\n " +
" height: 140,\r\n modal: true,\r\n " +
" autoOpen: false\r\n });\r\n }\r\n\r\n " +
" $dialogRemove.dialog(\"enable\").dialog(\'option\', \'buttons\', {\r\n " +
" \"Remove\": function () {\r\n $dialogRemove.dial" +
"og(\"disable\");\r\n $dialogRemove.dialog(\"option\", \"buttons\"" +
", null);\r\n\r\n removeCommentAsync(commentId);\r\n " +
" },\r\n \"Cancel\": function () {\r\n " +
" $dialogRemove.dialog(\"close\");\r\n }\r\n }).dialo" +
"g(\'open\');\r\n }\r\n async function removeCommentAsync(comment" +
"Id) {\r\n const formData = new FormData();\r\n formDat" +
"a.append(\'__RequestVerificationToken\', $comments.find(\'input[name=\"__RequestVeri" +
"ficationToken\"]\').val());\r\n formData.append(\'id\', commentId);\r\n\r\n" +
" const response = await fetch($comments.attr(\'data-removeurl\'), {" +
"\r\n method: \'POST\',\r\n body: formData\r\n " +
" });\r\n\r\n if (!response.ok) {\r\n alert" +
"(\'Unable to remove comment: \' + response.statusText);\r\n }\r\n " +
" $dialogRemove.dialog(\"close\");\r\n }\r\n });\r\n </scri" +
"pt>\r\n");
#line 212 "..\..\Views\User\UserParts\Comments.cshtml"
}
#line default
#line hidden
}
}
}
#pragma warning restore 1591
@@ -0,0 +1,41 @@
@model Disco.Web.Models.User.ShowModel
@{
var canShowComments = Authorization.Has(Claims.User.ShowComments);
var canShowJobs = Authorization.Has(Claims.User.ShowJobs);
var jobCount = (Model.User.Jobs == null ? 0 : Model.User.Jobs.Count).ToString();
string label;
if (canShowComments & canShowJobs)
{
label = "Comments and Jobs [" + jobCount + "]";
}
else if (canShowComments)
{
label = "Comments";
}
else if (canShowJobs)
{
label = "Jobs [" + jobCount + "]";
}
else
{
return;
}
}
<div id="UserDetailTab-CommentsAndJobs" class="UserPart @(canShowComments ? "canShowComments" : "cannotShowComments") @(canShowJobs ? "canShowJobs" : "cannotShowJobs")">
@if (canShowComments)
{
<div id="UserDetailTab-CommentsContainer">
@Html.Partial(MVC.User.Views.UserParts.Comments, Model)
</div>
}
@if (canShowJobs)
{
<div id="UserDetailTab-JobsContainer">
@Html.Partial(MVC.Shared.Views._JobTable, Model.Jobs)
</div>
}
<script>
$('#UserDetailTabItems').append('<li><a href="#UserDetailTab-CommentsAndJobs">@label</a></li>');
</script>
</div>
@@ -0,0 +1,185 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Disco.Web.Views.User.UserParts
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using Disco;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
using Disco.Web.Extensions;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/User/UserParts/_CommentsAndJobs.cshtml")]
public partial class _CommentsAndJobs : Disco.Services.Web.WebViewPage<Disco.Web.Models.User.ShowModel>
{
public _CommentsAndJobs()
{
}
public override void Execute()
{
#line 2 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
var canShowComments = Authorization.Has(Claims.User.ShowComments);
var canShowJobs = Authorization.Has(Claims.User.ShowJobs);
var jobCount = (Model.User.Jobs == null ? 0 : Model.User.Jobs.Count).ToString();
string label;
if (canShowComments & canShowJobs)
{
label = "Comments and Jobs [" + jobCount + "]";
}
else if (canShowComments)
{
label = "Comments";
}
else if (canShowJobs)
{
label = "Jobs [" + jobCount + "]";
}
else
{
return;
}
#line default
#line hidden
WriteLiteral("\r\n<div");
WriteLiteral(" id=\"UserDetailTab-CommentsAndJobs\"");
WriteAttribute("class", Tuple.Create(" class=\"", 640), Tuple.Create("\"", 768)
, Tuple.Create(Tuple.Create("", 648), Tuple.Create("UserPart", 648), true)
#line 25 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
, Tuple.Create(Tuple.Create(" ", 656), Tuple.Create<System.Object, System.Int32>(canShowComments ? "canShowComments" : "cannotShowComments"
#line default
#line hidden
, 657), false)
#line 25 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
, Tuple.Create(Tuple.Create(" ", 718), Tuple.Create<System.Object, System.Int32>(canShowJobs ? "canShowJobs" : "cannotShowJobs"
#line default
#line hidden
, 719), false)
);
WriteLiteral(">\r\n");
#line 26 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
#line default
#line hidden
#line 26 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
if (canShowComments)
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" id=\"UserDetailTab-CommentsContainer\"");
WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 29 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
Write(Html.Partial(MVC.User.Views.UserParts.Comments, Model));
#line default
#line hidden
WriteLiteral("\r\n </div>\r\n");
#line 31 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
}
#line default
#line hidden
WriteLiteral(" ");
#line 32 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
if (canShowJobs)
{
#line default
#line hidden
WriteLiteral(" <div");
WriteLiteral(" id=\"UserDetailTab-JobsContainer\"");
WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 35 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
Write(Html.Partial(MVC.Shared.Views._JobTable, Model.Jobs));
#line default
#line hidden
WriteLiteral("\r\n </div>\r\n");
#line 37 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
}
#line default
#line hidden
WriteLiteral(" <script>\r\n $(\'#UserDetailTabItems\').append(\'<li><a href=\"#UserDetailTa" +
"b-CommentsAndJobs\">");
#line 39 "..\..\Views\User\UserParts\_CommentsAndJobs.cshtml"
Write(label);
#line default
#line hidden
WriteLiteral("</a></li>\');\r\n </script>\r\n</div>\r\n");
}
}
}
#pragma warning restore 1591
@@ -1,12 +0,0 @@
@model Disco.Web.Models.User.ShowModel
@{
Authorization.Require(Claims.User.ShowJobs);
}
<div id="UserDetailTab-Jobs" class="UserPart">
<div id="UserDetailTab-JobsContainer">
@Html.Partial(MVC.Shared.Views._JobTable, Model.Jobs)
</div>
<script>
$('#UserDetailTabItems').append('<li><a href="#UserDetailTab-Jobs">Jobs [@(Model.User.Jobs == null ? 0 : Model.User.Jobs.Count)]</a></li>');
</script>
</div>
@@ -1,90 +0,0 @@
#pragma warning disable 1591
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Disco.Web.Views.User.UserParts
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Web;
using System.Web.Helpers;
using System.Web.Mvc;
using System.Web.Mvc.Ajax;
using System.Web.Mvc.Html;
using System.Web.Routing;
using System.Web.Security;
using System.Web.UI;
using System.Web.WebPages;
using Disco;
using Disco.Models.Repository;
using Disco.Services;
using Disco.Services.Authorization;
using Disco.Services.Web;
using Disco.Web;
using Disco.Web.Extensions;
[System.CodeDom.Compiler.GeneratedCodeAttribute("RazorGenerator", "2.0.0.0")]
[System.Web.WebPages.PageVirtualPathAttribute("~/Views/User/UserParts/_Jobs.cshtml")]
public partial class _Jobs : Disco.Services.Web.WebViewPage<Disco.Web.Models.User.ShowModel>
{
public _Jobs()
{
}
public override void Execute()
{
#line 2 "..\..\Views\User\UserParts\_Jobs.cshtml"
Authorization.Require(Claims.User.ShowJobs);
#line default
#line hidden
WriteLiteral("\r\n<div");
WriteLiteral(" id=\"UserDetailTab-Jobs\"");
WriteLiteral(" class=\"UserPart\"");
WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"UserDetailTab-JobsContainer\"");
WriteLiteral(">\r\n");
WriteLiteral(" ");
#line 7 "..\..\Views\User\UserParts\_Jobs.cshtml"
Write(Html.Partial(MVC.Shared.Views._JobTable, Model.Jobs));
#line default
#line hidden
WriteLiteral("\r\n </div>\r\n <script>\r\n $(\'#UserDetailTabItems\').append(\'<li><a href=" +
"\"#UserDetailTab-Jobs\">Jobs [");
#line 10 "..\..\Views\User\UserParts\_Jobs.cshtml"
Write(Model.User.Jobs == null ? 0 : Model.User.Jobs.Count);
#line default
#line hidden
WriteLiteral("]</a></li>\');\r\n </script>\r\n</div>");
}
}
}
#pragma warning restore 1591
@@ -8,7 +8,6 @@
Html.BundleDeferred("~/Style/Shadowbox"); Html.BundleDeferred("~/Style/Shadowbox");
Html.BundleDeferred("~/ClientScripts/Modules/Shadowbox"); Html.BundleDeferred("~/ClientScripts/Modules/Shadowbox");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
if (canAddAttachments) if (canAddAttachments)
{ {
@@ -61,57 +60,7 @@
var $attachmentOutput = $Attachments.find('.attachmentOutput'); var $attachmentOutput = $Attachments.find('.attachmentOutput');
var $dialogRemoveAttachment = null; var $dialogRemoveAttachment = null;
// Connect to Hub function onAttachmentAdded(id, quick) {
var hub = $.connection.userUpdates;
// Map Functions
hub.client.addAttachment = onAddAttachment;
hub.client.removeAttachment = onRemoveAttachment;
$.connection.hub.qs = { UserId: '@(Model.User.UserId.Replace(@"\", @"\\"))' };
$.connection.hub.error(onHubFailed);
$.connection.hub.disconnected(onHubFailed);
$.connection.hub.reconnecting(function () {
$('#AttachmentsContainer').find('span.action.enabled').addClass('disabled');
});
$.connection.hub.reconnected(function () {
$('#AttachmentsContainer').find('span.action.enabled').removeClass('disabled');
});
// Start Connection
$.connection.hub.start(function () {
$('#AttachmentsContainer').find('span.action.enabled').removeClass('disabled');
}).fail(onHubFailed);
function onHubFailed(error) {
// Disable UI
$('#AttachmentsContainer').find('span.action.enabled').addClass('disabled');
// Show Dialog Message
if ($('.disconnected-dialog').length == 0) {
$('<div>')
.addClass('dialog disconnected-dialog')
.html('<h3><span class="fa-stack fa-lg"><i class="fa fa-wifi fa-stack-1x"></i><i class="fa fa-ban fa-stack-2x error"></i></span>Disconnected from the Disco ICT Server</h3><div>This page is not receiving live updates. Please ensure you are connected to the server, then refresh this page to enable features.</div>')
.dialog({
resizable: false,
title: 'Disconnected',
width: 400,
modal: true,
buttons: {
'Refresh Now': function () {
$(this).dialog('option', 'buttons', null);
window.location.reload(true);
},
'Close': function () {
$(this).dialog('destroy');
}
}
});
}
}
function onAddAttachment(id, quick) {
var data = { id: id }; var data = { id: id };
$.ajax({ $.ajax({
url: '@Url.Action(MVC.API.User.Attachment())', url: '@Url.Action(MVC.API.User.Attachment())',
@@ -207,7 +156,7 @@
return false; return false;
} }
function onRemoveAttachment(id) { function onAttachmentRemoved(id) {
var a = $attachmentOutput.find('a[data-attachmentid=' + id + ']'); var a = $attachmentOutput.find('a[data-attachmentid=' + id + ']');
a.hide(300).delay(300).queue(function () { a.hide(300).delay(300).queue(function () {
@@ -226,6 +175,9 @@
$('#UserDetailTab-ResourcesLink').text(tabHeading); $('#UserDetailTab-ResourcesLink').text(tabHeading);
} }
document.DiscoFunctions.onAttachmentAdded = onAttachmentAdded;
document.DiscoFunctions.onAttachmentRemoved = onAttachmentRemoved;
@if (canAddAttachments) @if (canAddAttachments)
{<text> {<text>
//#region Add Attachments //#region Add Attachments
@@ -54,7 +54,6 @@ namespace Disco.Web.Views.User.UserParts
Html.BundleDeferred("~/Style/Shadowbox"); Html.BundleDeferred("~/Style/Shadowbox");
Html.BundleDeferred("~/ClientScripts/Modules/Shadowbox"); Html.BundleDeferred("~/ClientScripts/Modules/Shadowbox");
Html.BundleDeferred("~/ClientScripts/Modules/jQuery-SignalR");
if (canAddAttachments) if (canAddAttachments)
{ {
@@ -82,21 +81,46 @@ WriteLiteral(">\r\n <div");
WriteLiteral(" id=\"Attachments\""); WriteLiteral(" id=\"Attachments\"");
WriteAttribute("class", Tuple.Create(" class=\"", 872), Tuple.Create("\"", 947) WriteAttribute("class", Tuple.Create(" class=\"", 804), Tuple.Create("\"", 1051)
#line 22 "..\..\Views\User\UserParts\_Resources.cshtml" #line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create("", 880), Tuple.Create<System.Object, System.Int32>(canAddAttachments ? "canAddAttachments" : "cannotAddAttachments" , Tuple.Create(Tuple.Create("", 812), Tuple.Create<System.Object, System.Int32>(canAddAttachments ? "canAddAttachments" : "cannotAddAttachments"
#line default
#line hidden
, 812), false)
#line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create(" ", 879), Tuple.Create<System.Object, System.Int32>(canRemoveAnyAttachments ? "canRemoveAnyAttachments" : "cannotRemoveAnyAttachments"
#line default #line default
#line hidden #line hidden
, 880), false) , 880), false)
#line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create(" ", 965), Tuple.Create<System.Object, System.Int32>(canRemoveOwnAttachments ? "canRemoveOwnAttachments" : "cannotRemoveOwnAttachments"
#line default
#line hidden
, 966), false)
); );
WriteLiteral(" data-userid=\"");
#line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(CurrentUser.UserId);
#line default
#line hidden
WriteLiteral("\"");
WriteLiteral(" data-uploadurl=\""); WriteLiteral(" data-uploadurl=\"");
#line 22 "..\..\Views\User\UserParts\_Resources.cshtml" #line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Action(MVC.API.User.AttachmentUpload(Model.User.UserId, null))); Write(Url.Action(MVC.API.User.AttachmentUpload(Model.User.UserId, null)));
#line default #line default
@@ -106,8 +130,8 @@ WriteLiteral("\"");
WriteLiteral(" data-onlineuploadurl=\""); WriteLiteral(" data-onlineuploadurl=\"");
#line 22 "..\..\Views\User\UserParts\_Resources.cshtml" #line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Action(MVC.API.User.AttachmentOnlineUploadSession(Model.User.UserId))); Write(Url.Action(MVC.API.User.AttachmentOnlineUploadSession(Model.User.UserId)));
#line default #line default
@@ -117,8 +141,8 @@ WriteLiteral("\"");
WriteLiteral(" data-qrcodeurl=\""); WriteLiteral(" data-qrcodeurl=\"");
#line 22 "..\..\Views\User\UserParts\_Resources.cshtml" #line 21 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Content("~/ClientSource/Scripts/Modules/qrcode.min.js")); Write(Url.Content("~/ClientSource/Scripts/Modules/qrcode.min.js"));
#line default #line default
@@ -130,7 +154,7 @@ WriteLiteral(">\r\n");
WriteLiteral(" "); WriteLiteral(" ");
#line 23 "..\..\Views\User\UserParts\_Resources.cshtml" #line 22 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Html.AntiForgeryToken()); Write(Html.AntiForgeryToken());
@@ -148,13 +172,13 @@ WriteLiteral(" class=\"attachmentOutput\"");
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
#line 28 "..\..\Views\User\UserParts\_Resources.cshtml" #line 27 "..\..\Views\User\UserParts\_Resources.cshtml"
#line default #line default
#line hidden #line hidden
#line 28 "..\..\Views\User\UserParts\_Resources.cshtml" #line 27 "..\..\Views\User\UserParts\_Resources.cshtml"
if (Model.User.UserAttachments != null) if (Model.User.UserAttachments != null)
{ {
foreach (var ua in Model.User.UserAttachments.OrderByDescending(a => a.Id)) foreach (var ua in Model.User.UserAttachments.OrderByDescending(a => a.Id))
@@ -165,20 +189,20 @@ WriteLiteral(">\r\n");
#line hidden #line hidden
WriteLiteral(" <a"); WriteLiteral(" <a");
WriteAttribute("href", Tuple.Create(" href=\"", 1730), Tuple.Create("\"", 1788) WriteAttribute("href", Tuple.Create(" href=\"", 1868), Tuple.Create("\"", 1926)
#line 32 "..\..\Views\User\UserParts\_Resources.cshtml" #line 31 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create("", 1737), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.User.AttachmentDownload(ua.Id)) , Tuple.Create(Tuple.Create("", 1875), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.User.AttachmentDownload(ua.Id))
#line default #line default
#line hidden #line hidden
, 1737), false) , 1875), false)
); );
WriteLiteral(" data-attachmentid=\""); WriteLiteral(" data-attachmentid=\"");
#line 32 "..\..\Views\User\UserParts\_Resources.cshtml" #line 31 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.Id); Write(ua.Id);
@@ -189,7 +213,7 @@ WriteLiteral("\"");
WriteLiteral(" data-mimetype=\""); WriteLiteral(" data-mimetype=\"");
#line 32 "..\..\Views\User\UserParts\_Resources.cshtml" #line 31 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.MimeType); Write(ua.MimeType);
@@ -201,28 +225,28 @@ WriteLiteral(">\r\n <span");
WriteLiteral(" class=\"icon\""); WriteLiteral(" class=\"icon\"");
WriteAttribute("title", Tuple.Create(" title=\"", 1902), Tuple.Create("\"", 1922) WriteAttribute("title", Tuple.Create(" title=\"", 2040), Tuple.Create("\"", 2060)
#line 33 "..\..\Views\User\UserParts\_Resources.cshtml" #line 32 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create("", 1910), Tuple.Create<System.Object, System.Int32>(ua.Filename , Tuple.Create(Tuple.Create("", 2048), Tuple.Create<System.Object, System.Int32>(ua.Filename
#line default #line default
#line hidden #line hidden
, 1910), false) , 2048), false)
); );
WriteLiteral(">\r\n <img"); WriteLiteral(">\r\n <img");
WriteLiteral(" alt=\"Attachment Thumbnail\""); WriteLiteral(" alt=\"Attachment Thumbnail\"");
WriteAttribute("src", Tuple.Create(" src=\"", 1997), Tuple.Create("\"", 2057) WriteAttribute("src", Tuple.Create(" src=\"", 2135), Tuple.Create("\"", 2195)
#line 34 "..\..\Views\User\UserParts\_Resources.cshtml" #line 33 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create("", 2003), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.User.AttachmentThumbnail(ua.Id)) , Tuple.Create(Tuple.Create("", 2141), Tuple.Create<System.Object, System.Int32>(Url.Action(MVC.API.User.AttachmentThumbnail(ua.Id))
#line default #line default
#line hidden #line hidden
, 2003), false) , 2141), false)
); );
WriteLiteral(" />\r\n </span>\r\n " + WriteLiteral(" />\r\n </span>\r\n " +
@@ -230,40 +254,40 @@ WriteLiteral(" />\r\n </span>\r\n
WriteLiteral(" class=\"comments\""); WriteLiteral(" class=\"comments\"");
WriteAttribute("title", Tuple.Create(" title=\"", 2166), Tuple.Create("\"", 2186) WriteAttribute("title", Tuple.Create(" title=\"", 2304), Tuple.Create("\"", 2324)
#line 36 "..\..\Views\User\UserParts\_Resources.cshtml" #line 35 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create("", 2174), Tuple.Create<System.Object, System.Int32>(ua.Comments , Tuple.Create(Tuple.Create("", 2312), Tuple.Create<System.Object, System.Int32>(ua.Comments
#line default #line default
#line hidden #line hidden
, 2174), false) , 2312), false)
); );
WriteLiteral(">\r\n"); WriteLiteral(">\r\n");
#line 37 "..\..\Views\User\UserParts\_Resources.cshtml" #line 36 "..\..\Views\User\UserParts\_Resources.cshtml"
#line default #line default
#line hidden #line hidden
#line 37 "..\..\Views\User\UserParts\_Resources.cshtml" #line 36 "..\..\Views\User\UserParts\_Resources.cshtml"
if (!string.IsNullOrEmpty(ua.DocumentTemplateId)) if (!string.IsNullOrEmpty(ua.DocumentTemplateId))
{ {
#line default #line default
#line hidden #line hidden
#line 38 "..\..\Views\User\UserParts\_Resources.cshtml" #line 37 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.DocumentTemplate.Description); Write(ua.DocumentTemplate.Description);
#line default #line default
#line hidden #line hidden
#line 38 "..\..\Views\User\UserParts\_Resources.cshtml" #line 37 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
else else
{ {
@@ -271,14 +295,14 @@ WriteLiteral(">\r\n");
#line default #line default
#line hidden #line hidden
#line 40 "..\..\Views\User\UserParts\_Resources.cshtml" #line 39 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.Comments ?? ua.Filename); Write(ua.Comments ?? ua.Filename);
#line default #line default
#line hidden #line hidden
#line 40 "..\..\Views\User\UserParts\_Resources.cshtml" #line 39 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
#line default #line default
@@ -290,7 +314,7 @@ WriteLiteral(" class=\"author\"");
WriteLiteral(">"); WriteLiteral(">");
#line 41 "..\..\Views\User\UserParts\_Resources.cshtml" #line 40 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.TechUser.ToStringFriendly()); Write(ua.TechUser.ToStringFriendly());
@@ -299,7 +323,7 @@ WriteLiteral(">");
WriteLiteral("</span>"); WriteLiteral("</span>");
#line 41 "..\..\Views\User\UserParts\_Resources.cshtml" #line 40 "..\..\Views\User\UserParts\_Resources.cshtml"
if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase))) if (canRemoveAnyAttachments || (canRemoveOwnAttachments && ua.TechUserId.Equals(CurrentUser.UserId, StringComparison.OrdinalIgnoreCase)))
{ {
@@ -312,7 +336,7 @@ WriteLiteral(" class=\"remove fa fa-times-circle\"");
WriteLiteral("></span>"); WriteLiteral("></span>");
#line 42 "..\..\Views\User\UserParts\_Resources.cshtml" #line 41 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
#line default #line default
@@ -324,7 +348,7 @@ WriteLiteral(" class=\"timestamp\"");
WriteLiteral(" data-livestamp=\""); WriteLiteral(" data-livestamp=\"");
#line 42 "..\..\Views\User\UserParts\_Resources.cshtml" #line 41 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.Timestamp.ToUnixEpoc()); Write(ua.Timestamp.ToUnixEpoc());
@@ -332,20 +356,20 @@ WriteLiteral(" data-livestamp=\"");
#line hidden #line hidden
WriteLiteral("\""); WriteLiteral("\"");
WriteAttribute("title", Tuple.Create(" title=\"", 2895), Tuple.Create("\"", 2933) WriteAttribute("title", Tuple.Create(" title=\"", 3033), Tuple.Create("\"", 3071)
#line 42 "..\..\Views\User\UserParts\_Resources.cshtml" #line 41 "..\..\Views\User\UserParts\_Resources.cshtml"
, Tuple.Create(Tuple.Create("", 2903), Tuple.Create<System.Object, System.Int32>(ua.Timestamp.ToFullDateTime() , Tuple.Create(Tuple.Create("", 3041), Tuple.Create<System.Object, System.Int32>(ua.Timestamp.ToFullDateTime()
#line default #line default
#line hidden #line hidden
, 2903), false) , 3041), false)
); );
WriteLiteral(">"); WriteLiteral(">");
#line 42 "..\..\Views\User\UserParts\_Resources.cshtml" #line 41 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(ua.Timestamp.ToFullDateTime()); Write(ua.Timestamp.ToFullDateTime());
@@ -354,7 +378,7 @@ WriteLiteral(">");
WriteLiteral("</span>\r\n </a>\r\n"); WriteLiteral("</span>\r\n </a>\r\n");
#line 44 "..\..\Views\User\UserParts\_Resources.cshtml" #line 43 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
} }
@@ -364,13 +388,13 @@ WriteLiteral("</span>\r\n </a>\r\n");
WriteLiteral(" </div>\r\n"); WriteLiteral(" </div>\r\n");
#line 47 "..\..\Views\User\UserParts\_Resources.cshtml" #line 46 "..\..\Views\User\UserParts\_Resources.cshtml"
#line default #line default
#line hidden #line hidden
#line 47 "..\..\Views\User\UserParts\_Resources.cshtml" #line 46 "..\..\Views\User\UserParts\_Resources.cshtml"
if (canAddAttachments) if (canAddAttachments)
{ {
@@ -408,7 +432,7 @@ WriteLiteral(" title=\"Upload with Online Services\"");
WriteLiteral("></span>\r\n </div>\r\n"); WriteLiteral("></span>\r\n </div>\r\n");
#line 53 "..\..\Views\User\UserParts\_Resources.cshtml" #line 52 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
@@ -428,162 +452,46 @@ WriteLiteral(@">
var $attachmentOutput = $Attachments.find('.attachmentOutput'); var $attachmentOutput = $Attachments.find('.attachmentOutput');
var $dialogRemoveAttachment = null; var $dialogRemoveAttachment = null;
// Connect to Hub function onAttachmentAdded(id, quick) {
var hub = $.connection.userUpdates; var data = { id: id };
$.ajax({
// Map Functions url: '");
hub.client.addAttachment = onAddAttachment;
hub.client.removeAttachment = onRemoveAttachment;
$.connection.hub.qs = { UserId: '");
#line 71 "..\..\Views\User\UserParts\_Resources.cshtml" #line 66 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Model.User.UserId.Replace(@"\", @"\\"));
#line default
#line hidden
WriteLiteral("\' };\r\n $.connection.hub.error(onHubFailed);\r\n " +
" $.connection.hub.disconnected(onHubFailed);\r\n\r\n " +
" $.connection.hub.reconnecting(function () {\r\n " +
" $(\'#AttachmentsContainer\').find(\'span.action.enabled\').addClass(\'disa" +
"bled\');\r\n });\r\n $.connecti" +
"on.hub.reconnected(function () {\r\n $(\'#Attachment" +
"sContainer\').find(\'span.action.enabled\').removeClass(\'disabled\');\r\n " +
" });\r\n\r\n // Start Connection\r\n " +
" $.connection.hub.start(function () {\r\n " +
" $(\'#AttachmentsContainer\').find(\'span.action.enabled\').removeClass(\'dis" +
"abled\');\r\n }).fail(onHubFailed);\r\n\r\n " +
" function onHubFailed(error) {\r\n // Dis" +
"able UI\r\n $(\'#AttachmentsContainer\').find(\'span.a" +
"ction.enabled\').addClass(\'disabled\');\r\n\r\n // Show" +
" Dialog Message\r\n if ($(\'.disconnected-dialog\').l" +
"ength == 0) {\r\n $(\'<div>\')\r\n " +
" .addClass(\'dialog disconnected-dialog\')\r\n " +
" .html(\'<h3><span class=\"fa-stack fa-lg\"><i class=\"fa fa-" +
"wifi fa-stack-1x\"></i><i class=\"fa fa-ban fa-stack-2x error\"></i></span>Disconne" +
"cted from the Disco ICT Server</h3><div>This page is not receiving live updates." +
" Please ensure you are connected to the server, then refresh this page to enable" +
" features.</div>\')\r\n .dialog({\r\n " +
" resizable: false,\r\n " +
" title: \'Disconnected\',\r\n " +
" width: 400,\r\n modal: true,\r\n " +
" buttons: {\r\n " +
" \'Refresh Now\': function () {\r\n " +
" $(this).dialog(\'option\', \'buttons\', null);\r\n " +
" window.location.reload(true);\r\n " +
" },\r\n " +
" \'Close\': function () {\r\n " +
" $(this).dialog(\'destroy\');\r\n " +
" }\r\n }\r\n " +
" });\r\n }\r\n " +
"}\r\n\r\n function onAddAttachment(id, quick) {\r\n " +
" var data = { id: id };\r\n " +
"$.ajax({\r\n url: \'");
#line 117 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Action(MVC.API.User.Attachment())); Write(Url.Action(MVC.API.User.Attachment()));
#line default #line default
#line hidden #line hidden
WriteLiteral(@"', WriteLiteral("\',\r\n dataType: \'json\',\r\n " +
dataType: 'json', " data: data,\r\n success: function" +
data: data, " (d) {\r\n if (d.Result == \'OK\') {\r\n " +
success: function (d) { " var a = d.Attachment;\r\n\r\n " +
if (d.Result == 'OK') { " if ($Attachments.hasClass(\'canRemoveAnyAttachments\'))\r" +
var a = d.Attachment; "\n buildAttachment(a, true, quick)" +
"); ";\r\n else if ($Attachments.hasClass(\'c" +
"anRemoveOwnAttachments\'))\r\n build" +
"Attachment(a, (a.AuthorId === $Attachments.attr(\'data-userid\')), quick);\r\n " +
" else\r\n " +
" buildAttachment(a, false, quick);\r\n " +
" } else {\r\n alert(\'Unable to ad" +
"d attachment: \' + d.Result);\r\n }\r\n " +
" },\r\n error: func" +
"tion (jqXHR, textStatus, errorThrown) {\r\n " +
" alert(\'Unable to add attachment: \' + textStatus);\r\n " +
" }\r\n });\r\n }\r\n " +
" function buildAttachment(a, canRemove, quick) {\r\n " +
" var t = \'<a><span class=\"icon\"><img alt=\"Attachment " +
"Thumbnail\" /></span><span class=\"comments\"></span><span class=\"author\"></span>\';" +
"\r\n if (canRemove)\r\n " +
" t += \'<span class=\"remove fa fa-times-circle\"></span>\';\r\n " +
" t += \'<span class=\"timestamp\"></span></a>\';\r\n\r\n " +
" var e = $(t);\r\n\r\n e.attr(\'data-atta" +
"chmentid\', a.Id).attr(\'data-mimetype\', a.MimeType).attr(\'href\', \'");
#line 123 "..\..\Views\User\UserParts\_Resources.cshtml" #line 96 "..\..\Views\User\UserParts\_Resources.cshtml"
#line default
#line hidden
#line 123 "..\..\Views\User\UserParts\_Resources.cshtml"
if (canRemoveAnyAttachments)
{
#line default
#line hidden
WriteLiteral(" ");
WriteLiteral("buildAttachment(a, true, quick);");
WriteLiteral("\r\n");
#line 126 "..\..\Views\User\UserParts\_Resources.cshtml"
}
else if (canRemoveOwnAttachments)
{
#line default
#line hidden
WriteLiteral(" ");
WriteLiteral("buildAttachment(a, (a.AuthorId === \'");
#line 129 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(CurrentUser.UserId);
#line default
#line hidden
WriteLiteral("\'), quick);");
WriteLiteral("\r\n");
#line 130 "..\..\Views\User\UserParts\_Resources.cshtml"
}
else
{
#line default
#line hidden
WriteLiteral(" ");
WriteLiteral("buildAttachment(a, false, quick);");
WriteLiteral("\r\n");
#line 134 "..\..\Views\User\UserParts\_Resources.cshtml"
}
#line default
#line hidden
WriteLiteral(@" } else {
alert('Unable to add attachment: ' + d.Result);
}
},
error: function (jqXHR, textStatus, errorThrown) {
alert('Unable to add attachment: ' + textStatus);
}
});
}
function buildAttachment(a, canRemove, quick) {
var t = '<a><span class=""icon""><img alt=""Attachment Thumbnail"" /></span><span class=""comments""></span><span class=""author""></span>';
if (canRemove)
t += '<span class=""remove fa fa-times-circle""></span>';
t += '<span class=""timestamp""></span></a>';
var e = $(t);
e.attr('data-attachmentid', a.Id).attr('data-mimetype', a.MimeType).attr('href', '");
#line 152 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Action(MVC.API.User.AttachmentDownload())); Write(Url.Action(MVC.API.User.AttachmentDownload()));
@@ -615,7 +523,7 @@ WriteLiteral(@"/' + a.Id);
img.attr('src', '"); img.attr('src', '");
#line 175 "..\..\Views\User\UserParts\_Resources.cshtml" #line 119 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Action(MVC.API.User.AttachmentThumbnail())); Write(Url.Action(MVC.API.User.AttachmentThumbnail()));
@@ -650,29 +558,31 @@ WriteLiteral("/\' + a.Id + \'?v=\' + retryCount);\r\n
" $attachmentDownloadHost[0].location.href = url;\r\n " + " $attachmentDownloadHost[0].location.href = url;\r\n " +
" }\r\n }\r\n\r\n " + " }\r\n }\r\n\r\n " +
" return false;\r\n }\r\n\r\n " + " return false;\r\n }\r\n\r\n " +
" function onRemoveAttachment(id) {\r\n va" + " function onAttachmentRemoved(id) {\r\n v" +
"r a = $attachmentOutput.find(\'a[data-attachmentid=\' + id + \']\');\r\n\r\n " + "ar a = $attachmentOutput.find(\'a[data-attachmentid=\' + id + \']\');\r\n\r\n " +
" a.hide(300).delay(300).queue(function () {\r\n " + " a.hide(300).delay(300).queue(function () {\r\n " +
" var $this = $(this);\r\n if" + " var $this = $(this);\r\n i" +
" ($this.attr(\'data-mimetype\').toLowerCase().indexOf(\'image/\') == 0)\r\n " + "f ($this.attr(\'data-mimetype\').toLowerCase().indexOf(\'image/\') == 0)\r\n " +
" Shadowbox.removeCache(this);\r\n " + " Shadowbox.removeCache(this);\r\n " +
" $this.find(\'.timestamp\').livestamp(\'destroy\');\r\n " + " $this.find(\'.timestamp\').livestamp(\'destroy\');\r\n " +
" $this.remove();\r\n onUpdate" + " $this.remove();\r\n onUpdat" +
"();\r\n });\r\n }\r\n\r\n " + "e();\r\n });\r\n }\r\n\r\n " +
" function onUpdate() {\r\n va" + " function onUpdate() {\r\n v" +
"r attachmentCount = $attachmentOutput.children(\'a\').length;\r\n " + "ar attachmentCount = $attachmentOutput.children(\'a\').length;\r\n " +
" var tabHeading = \'Attachments [\' + attachmentCount + \']\';\r\n " + " var tabHeading = \'Attachments [\' + attachmentCount + \']\';\r\n " +
" $(\'#UserDetailTab-ResourcesLink\').text(tabHeading);\r\n " + " $(\'#UserDetailTab-ResourcesLink\').text(tabHeading);\r\n " +
" }\r\n\r\n"); " }\r\n\r\n document.DiscoFunctio" +
"ns.onAttachmentAdded = onAttachmentAdded;\r\n document." +
"DiscoFunctions.onAttachmentRemoved = onAttachmentRemoved;\r\n\r\n");
#line 234 "..\..\Views\User\UserParts\_Resources.cshtml" #line 181 "..\..\Views\User\UserParts\_Resources.cshtml"
#line default #line default
#line hidden #line hidden
#line 234 "..\..\Views\User\UserParts\_Resources.cshtml" #line 181 "..\..\Views\User\UserParts\_Resources.cshtml"
if (canAddAttachments) if (canAddAttachments)
{ {
@@ -719,7 +629,7 @@ WriteLiteral("\r\n //#region Add Attachments\r\n
" //#endregion\r\n "); " //#endregion\r\n ");
#line 281 "..\..\Views\User\UserParts\_Resources.cshtml" #line 228 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
@@ -728,7 +638,7 @@ WriteLiteral("\r\n //#region Add Attachments\r\n
WriteLiteral(" "); WriteLiteral(" ");
#line 282 "..\..\Views\User\UserParts\_Resources.cshtml" #line 229 "..\..\Views\User\UserParts\_Resources.cshtml"
if (canRemoveAnyAttachments || canRemoveOwnAttachments) if (canRemoveAnyAttachments || canRemoveOwnAttachments)
{ {
@@ -762,7 +672,7 @@ WriteLiteral(@"
url: '"); url: '");
#line 308 "..\..\Views\User\UserParts\_Resources.cshtml" #line 255 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Url.Action(MVC.API.User.AttachmentRemove())); Write(Url.Action(MVC.API.User.AttachmentRemove()));
@@ -790,7 +700,7 @@ WriteLiteral("\',\r\n dataType: \'jso
"/#endregion\r\n "); "/#endregion\r\n ");
#line 336 "..\..\Views\User\UserParts\_Resources.cshtml" #line 283 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
@@ -814,7 +724,7 @@ WriteLiteral(@"
$('#UserDetailTabItems').append('<li><a href=""#UserDetailTab-Resources"" id=""UserDetailTab-ResourcesLink"">Attachments ["); $('#UserDetailTabItems').append('<li><a href=""#UserDetailTab-Resources"" id=""UserDetailTab-ResourcesLink"">Attachments [");
#line 352 "..\..\Views\User\UserParts\_Resources.cshtml" #line 299 "..\..\Views\User\UserParts\_Resources.cshtml"
Write(Model.User.UserAttachments == null ? 0 : Model.User.UserAttachments.Count); Write(Model.User.UserAttachments == null ? 0 : Model.User.UserAttachments.Count);
@@ -823,7 +733,7 @@ WriteLiteral(@"
WriteLiteral("]</a></li>\');\r\n </script>\r\n</div>\r\n"); WriteLiteral("]</a></li>\');\r\n </script>\r\n</div>\r\n");
#line 355 "..\..\Views\User\UserParts\_Resources.cshtml" #line 302 "..\..\Views\User\UserParts\_Resources.cshtml"
if (canRemoveAnyAttachments || canRemoveOwnAttachments) if (canRemoveAnyAttachments || canRemoveOwnAttachments)
{ {
@@ -845,7 +755,7 @@ WriteLiteral(" class=\"fa fa-exclamation-triangle fa-lg\"");
WriteLiteral("></i>&nbsp;Are you sure?\r\n </p>\r\n </div>\r\n"); WriteLiteral("></i>&nbsp;Are you sure?\r\n </p>\r\n </div>\r\n");
#line 362 "..\..\Views\User\UserParts\_Resources.cshtml" #line 309 "..\..\Views\User\UserParts\_Resources.cshtml"
} }
#line default #line default