diff --git a/Server/API/OrganizationManagementController.cs b/Server/API/OrganizationManagementController.cs index 49d3604a..d58dc90f 100644 --- a/Server/API/OrganizationManagementController.cs +++ b/Server/API/OrganizationManagementController.cs @@ -133,6 +133,54 @@ namespace Remotely.Server.API return Ok(deviceGroupID); } + [HttpDelete("DeviceGroup/{groupID}/Users/")] + [ServiceFilter(typeof(ApiAuthorizationFilter))] + public async Task DeviceGroupRemoveUser([FromBody]string userID, string groupID) + { + if (User.Identity.IsAuthenticated && + !DataService.GetUserByName(User.Identity.Name).IsAdministrator) + { + return Unauthorized(); + } + + if (!ModelState.IsValid) + { + return BadRequest(); + } + + Request.Headers.TryGetValue("OrganizationID", out var orgID); + if (!await DataService.RemoveUserFromDeviceGroup(orgID, groupID, userID)) + { + return BadRequest("Failed to remove user from group."); + } + return Ok(); + } + + [HttpPost("DeviceGroup/{groupID}/Users/")] + [ServiceFilter(typeof(ApiAuthorizationFilter))] + public IActionResult DeviceGroupAddUser([FromBody]string userID, string groupID) + { + if (User.Identity.IsAuthenticated && + !DataService.GetUserByName(User.Identity.Name).IsAdministrator) + { + return Unauthorized(); + } + + if (!ModelState.IsValid) + { + return BadRequest(); + } + + Request.Headers.TryGetValue("OrganizationID", out var orgID); + var result = DataService.AddUserToDeviceGroup(orgID, groupID, userID, out var resultMessage); + if (!result) + { + return BadRequest(resultMessage); + } + + return Ok(resultMessage); + } + [HttpGet("GenerateResetUrl/{userID}")] [ServiceFilter(typeof(ApiAuthorizationFilter))] public async Task GenerateResetUrl(string userID) diff --git a/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml b/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml index 77687aa7..cb491ac2 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml +++ b/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml @@ -45,24 +45,29 @@
+
@* Device Groups *@ -
- - - +
+
+ + + -
- -
+
+ + +
-
- - - - +
+ + + + +
-
+
+
@@ -150,7 +155,7 @@
- +
Admin?
@@ -169,6 +174,58 @@
+ + @* Device Permission Modals *@ + @for (var i = 0; i < Model.DeviceGroups.Count; i++) + { + + + } + diff --git a/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs b/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs index fa11f304..c11e7c34 100644 --- a/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs +++ b/Server/Areas/Identity/Pages/Account/Manage/Organization.cshtml.cs @@ -24,7 +24,8 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage UserManager = userManager; EmailSender = emailSender; } - public List DeviceGroups { get; } = new List(); + public List DeviceGroupSelectItems { get; } = new List(); + public List DeviceGroups { get; } = new List(); [BindProperty] public InputModel Input { get; set; } = new InputModel(); @@ -117,12 +118,41 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage return Page(); } + public async Task OnPostCreateDeviceGroupAsync() + { + var currentUser = await UserManager.FindByEmailAsync(User.Identity.Name); + if (!currentUser.IsAdministrator) + { + return RedirectToPage("Index"); + } + + if (ModelState.IsValid) + { + var deviceGroup = new DeviceGroup() + { + Name = Input.DeviceGroupName + }; + + var result = DataService.AddDeviceGroup(currentUser.OrganizationID, deviceGroup, out _, out var errorMessage); + if (!result) + { + PopulateViewModel(); + ModelState.AddModelError("AddDeviceGroup", errorMessage); + return Page(); + } + StatusMessage = "Device group created."; + return RedirectToPage(); + } + PopulateViewModel(); + return Page(); + } + private void PopulateViewModel() { OrganizationName = DataService.GetOrganizationName(User.Identity.Name); - - var groups = DataService.GetDeviceGroupsForUserName(User.Identity.Name); - DeviceGroups.AddRange(groups.Select(x => new SelectListItem(x.Name, x.ID))); + var deviceGroups = DataService.GetDeviceGroups(User.Identity.Name).OrderBy(x => x.Name); + DeviceGroups.AddRange(deviceGroups); + DeviceGroupSelectItems.AddRange(DeviceGroups.Select(x => new SelectListItem(x.Name, x.ID))); Users = DataService.GetAllUsers(User.Identity.Name) .Select(x => new OrganizationUser() @@ -147,6 +177,9 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage [EmailAddress] public string UserEmail { get; set; } + + [StringLength(200)] + public string DeviceGroupName { get; set; } } } diff --git a/Server/Data/ApplicationDbContext.cs b/Server/Data/ApplicationDbContext.cs index 14e0f647..4e9665be 100644 --- a/Server/Data/ApplicationDbContext.cs +++ b/Server/Data/ApplicationDbContext.cs @@ -34,7 +34,9 @@ namespace Remotely.Server.Data public DbSet DeviceGroups { get; set; } - protected override void OnModelCreating(ModelBuilder builder) + public DbSet PermissionLinks { get; set; } + + protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); @@ -55,6 +57,8 @@ namespace Remotely.Server.Data builder.Entity() .HasMany(x => x.Devices) .WithOne(x => x.DeviceGroup); + builder.Entity() + .HasMany(x => x.PermissionLinks); builder.Entity() .HasMany(x => x.DeviceGroups) .WithOne(x => x.Organization); @@ -90,6 +94,9 @@ namespace Remotely.Server.Data .HasOne(x => x.Organization) .WithMany(x => x.RemotelyUsers); + builder.Entity() + .HasMany(x => x.PermissionLinks); + builder.Entity() .Property(x => x.UserOptions) .HasConversion( diff --git a/Server/Migrations/20191211163438_Initial.Designer.cs b/Server/Migrations/20191211163438_Initial.Designer.cs deleted file mode 100644 index dc038a98..00000000 --- a/Server/Migrations/20191211163438_Initial.Designer.cs +++ /dev/null @@ -1,575 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Remotely.Server.Data; - -namespace Remotely.Server.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20191211163438_Initial")] - partial class Initial - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.0"); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("NormalizedName") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasName("RoleNameIndex"); - - b.ToTable("AspNetRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("AccessFailedCount") - .HasColumnType("INTEGER"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Email") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("EmailConfirmed") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnabled") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnd") - .HasColumnType("TEXT"); - - b.Property("NormalizedEmail") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("NormalizedUserName") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("PasswordHash") - .HasColumnType("TEXT"); - - b.Property("PhoneNumber") - .HasColumnType("TEXT"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("INTEGER"); - - b.Property("SecurityStamp") - .HasColumnType("TEXT"); - - b.Property("TwoFactorEnabled") - .HasColumnType("INTEGER"); - - b.Property("UserName") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex"); - - b.ToTable("RemotelyUsers"); - - b.HasDiscriminator("Discriminator").HasValue("IdentityUser"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("ProviderKey") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("ProviderDisplayName") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("LoginProvider") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("Name") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("CommandMode") - .HasColumnType("TEXT"); - - b.Property("CommandResults") - .HasColumnType("TEXT"); - - b.Property("CommandText") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("PSCoreResults") - .HasColumnType("TEXT"); - - b.Property("SenderConnectionID") - .HasColumnType("TEXT"); - - b.Property("SenderUserID") - .HasColumnType("TEXT"); - - b.Property("TargetDeviceIDs") - .HasColumnType("TEXT"); - - b.Property("TimeStamp") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("CommandContexts"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.Device", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("AgentVersion") - .HasColumnType("TEXT"); - - b.Property("CurrentUser") - .HasColumnType("TEXT"); - - b.Property("DeviceGroupID") - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .HasColumnType("TEXT"); - - b.Property("Drives") - .HasColumnType("TEXT"); - - b.Property("FreeMemory") - .HasColumnType("REAL"); - - b.Property("FreeStorage") - .HasColumnType("REAL"); - - b.Property("Is64Bit") - .HasColumnType("INTEGER"); - - b.Property("IsOnline") - .HasColumnType("INTEGER"); - - b.Property("LastOnline") - .HasColumnType("TEXT"); - - b.Property("OSArchitecture") - .HasColumnType("INTEGER"); - - b.Property("OSDescription") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("Platform") - .HasColumnType("TEXT"); - - b.Property("ProcessorCount") - .HasColumnType("INTEGER"); - - b.Property("ServerVerificationToken") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT") - .HasMaxLength(200); - - b.Property("TotalMemory") - .HasColumnType("REAL"); - - b.Property("TotalStorage") - .HasColumnType("REAL"); - - b.HasKey("ID"); - - b.HasIndex("DeviceGroupID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT") - .HasMaxLength(200); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("DeviceGroups"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.EventLog", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("EventType") - .HasColumnType("INTEGER"); - - b.Property("Message") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("Source") - .HasColumnType("TEXT"); - - b.Property("StackTrace") - .HasColumnType("TEXT"); - - b.Property("TimeStamp") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("EventLogs"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("DateSent") - .HasColumnType("TEXT"); - - b.Property("InvitedUser") - .HasColumnType("TEXT"); - - b.Property("IsAdmin") - .HasColumnType("INTEGER"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("ResetUrl") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("InviteLinks"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.Organization", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("OrganizationName") - .HasColumnType("TEXT") - .HasMaxLength(25); - - b.HasKey("ID"); - - b.ToTable("Organizations"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("ContentType") - .HasColumnType("TEXT"); - - b.Property("FileContents") - .HasColumnType("BLOB"); - - b.Property("FileName") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("SharedFiles"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => - { - b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); - - b.Property("IsAdministrator") - .HasColumnType("INTEGER"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("UserOptions") - .HasColumnType("TEXT"); - - b.HasIndex("OrganizationID"); - - b.HasDiscriminator().HasValue("RemotelyUser"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("CommandContexts") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.Device", b => - { - b.HasOne("Remotely.Shared.Models.DeviceGroup", "DeviceGroup") - .WithMany("Devices") - .HasForeignKey("DeviceGroupID"); - - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("Devices") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("DeviceGroups") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.EventLog", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("EventLogs") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("InviteLinks") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("SharedFiles") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("RemotelyUsers") - .HasForeignKey("OrganizationID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Server/Migrations/20191212152649_Device alias.Designer.cs b/Server/Migrations/20191212152649_Device alias.Designer.cs deleted file mode 100644 index f1630eca..00000000 --- a/Server/Migrations/20191212152649_Device alias.Designer.cs +++ /dev/null @@ -1,579 +0,0 @@ -// -using System; -using Microsoft.EntityFrameworkCore; -using Microsoft.EntityFrameworkCore.Infrastructure; -using Microsoft.EntityFrameworkCore.Migrations; -using Microsoft.EntityFrameworkCore.Storage.ValueConversion; -using Remotely.Server.Data; - -namespace Remotely.Server.Migrations -{ - [DbContext(typeof(ApplicationDbContext))] - [Migration("20191212152649_Device alias")] - partial class Devicealias - { - protected override void BuildTargetModel(ModelBuilder modelBuilder) - { -#pragma warning disable 612, 618 - modelBuilder - .HasAnnotation("ProductVersion", "3.1.0"); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("NormalizedName") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedName") - .IsUnique() - .HasName("RoleNameIndex"); - - b.ToTable("AspNetRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetRoleClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => - { - b.Property("Id") - .HasColumnType("TEXT"); - - b.Property("AccessFailedCount") - .HasColumnType("INTEGER"); - - b.Property("ConcurrencyStamp") - .IsConcurrencyToken() - .HasColumnType("TEXT"); - - b.Property("Discriminator") - .IsRequired() - .HasColumnType("TEXT"); - - b.Property("Email") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("EmailConfirmed") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnabled") - .HasColumnType("INTEGER"); - - b.Property("LockoutEnd") - .HasColumnType("TEXT"); - - b.Property("NormalizedEmail") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("NormalizedUserName") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.Property("PasswordHash") - .HasColumnType("TEXT"); - - b.Property("PhoneNumber") - .HasColumnType("TEXT"); - - b.Property("PhoneNumberConfirmed") - .HasColumnType("INTEGER"); - - b.Property("SecurityStamp") - .HasColumnType("TEXT"); - - b.Property("TwoFactorEnabled") - .HasColumnType("INTEGER"); - - b.Property("UserName") - .HasColumnType("TEXT") - .HasMaxLength(256); - - b.HasKey("Id"); - - b.HasIndex("NormalizedEmail") - .HasName("EmailIndex"); - - b.HasIndex("NormalizedUserName") - .IsUnique() - .HasName("UserNameIndex"); - - b.ToTable("RemotelyUsers"); - - b.HasDiscriminator("Discriminator").HasValue("IdentityUser"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.Property("Id") - .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); - - b.Property("ClaimType") - .HasColumnType("TEXT"); - - b.Property("ClaimValue") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("Id"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserClaims"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.Property("LoginProvider") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("ProviderKey") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("ProviderDisplayName") - .HasColumnType("TEXT"); - - b.Property("UserId") - .IsRequired() - .HasColumnType("TEXT"); - - b.HasKey("LoginProvider", "ProviderKey"); - - b.HasIndex("UserId"); - - b.ToTable("AspNetUserLogins"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("RoleId") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "RoleId"); - - b.HasIndex("RoleId"); - - b.ToTable("AspNetUserRoles"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.Property("UserId") - .HasColumnType("TEXT"); - - b.Property("LoginProvider") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("Name") - .HasColumnType("TEXT") - .HasMaxLength(128); - - b.Property("Value") - .HasColumnType("TEXT"); - - b.HasKey("UserId", "LoginProvider", "Name"); - - b.ToTable("AspNetUserTokens"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("CommandMode") - .HasColumnType("TEXT"); - - b.Property("CommandResults") - .HasColumnType("TEXT"); - - b.Property("CommandText") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("PSCoreResults") - .HasColumnType("TEXT"); - - b.Property("SenderConnectionID") - .HasColumnType("TEXT"); - - b.Property("SenderUserID") - .HasColumnType("TEXT"); - - b.Property("TargetDeviceIDs") - .HasColumnType("TEXT"); - - b.Property("TimeStamp") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("CommandContexts"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.Device", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("AgentVersion") - .HasColumnType("TEXT"); - - b.Property("Alias") - .HasColumnType("TEXT") - .HasMaxLength(100); - - b.Property("CurrentUser") - .HasColumnType("TEXT"); - - b.Property("DeviceGroupID") - .HasColumnType("TEXT"); - - b.Property("DeviceName") - .HasColumnType("TEXT"); - - b.Property("Drives") - .HasColumnType("TEXT"); - - b.Property("FreeMemory") - .HasColumnType("REAL"); - - b.Property("FreeStorage") - .HasColumnType("REAL"); - - b.Property("Is64Bit") - .HasColumnType("INTEGER"); - - b.Property("IsOnline") - .HasColumnType("INTEGER"); - - b.Property("LastOnline") - .HasColumnType("TEXT"); - - b.Property("OSArchitecture") - .HasColumnType("INTEGER"); - - b.Property("OSDescription") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("Platform") - .HasColumnType("TEXT"); - - b.Property("ProcessorCount") - .HasColumnType("INTEGER"); - - b.Property("ServerVerificationToken") - .HasColumnType("TEXT"); - - b.Property("Tags") - .HasColumnType("TEXT") - .HasMaxLength(200); - - b.Property("TotalMemory") - .HasColumnType("REAL"); - - b.Property("TotalStorage") - .HasColumnType("REAL"); - - b.HasKey("ID"); - - b.HasIndex("DeviceGroupID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("Devices"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("Name") - .HasColumnType("TEXT") - .HasMaxLength(200); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("DeviceGroups"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.EventLog", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("EventType") - .HasColumnType("INTEGER"); - - b.Property("Message") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("Source") - .HasColumnType("TEXT"); - - b.Property("StackTrace") - .HasColumnType("TEXT"); - - b.Property("TimeStamp") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("EventLogs"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("DateSent") - .HasColumnType("TEXT"); - - b.Property("InvitedUser") - .HasColumnType("TEXT"); - - b.Property("IsAdmin") - .HasColumnType("INTEGER"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("ResetUrl") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("InviteLinks"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.Organization", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("OrganizationName") - .HasColumnType("TEXT") - .HasMaxLength(25); - - b.HasKey("ID"); - - b.ToTable("Organizations"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b => - { - b.Property("ID") - .HasColumnType("TEXT"); - - b.Property("ContentType") - .HasColumnType("TEXT"); - - b.Property("FileContents") - .HasColumnType("BLOB"); - - b.Property("FileName") - .HasColumnType("TEXT"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("Timestamp") - .HasColumnType("TEXT"); - - b.HasKey("ID"); - - b.HasIndex("OrganizationID"); - - b.ToTable("SharedFiles"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => - { - b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); - - b.Property("IsAdministrator") - .HasColumnType("INTEGER"); - - b.Property("OrganizationID") - .HasColumnType("TEXT"); - - b.Property("UserOptions") - .HasColumnType("TEXT"); - - b.HasIndex("OrganizationID"); - - b.HasDiscriminator().HasValue("RemotelyUser"); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole", null) - .WithMany() - .HasForeignKey("RoleId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => - { - b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser", null) - .WithMany() - .HasForeignKey("UserId") - .OnDelete(DeleteBehavior.Cascade) - .IsRequired(); - }); - - modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("CommandContexts") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.Device", b => - { - b.HasOne("Remotely.Shared.Models.DeviceGroup", "DeviceGroup") - .WithMany("Devices") - .HasForeignKey("DeviceGroupID"); - - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("Devices") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("DeviceGroups") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.EventLog", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("EventLogs") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("InviteLinks") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("SharedFiles") - .HasForeignKey("OrganizationID"); - }); - - modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => - { - b.HasOne("Remotely.Shared.Models.Organization", "Organization") - .WithMany("RemotelyUsers") - .HasForeignKey("OrganizationID"); - }); -#pragma warning restore 612, 618 - } - } -} diff --git a/Server/Migrations/20191212152649_Device alias.cs b/Server/Migrations/20191212152649_Device alias.cs deleted file mode 100644 index 2108ff2b..00000000 --- a/Server/Migrations/20191212152649_Device alias.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Remotely.Server.Migrations -{ - public partial class Devicealias : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.AddColumn( - name: "Alias", - table: "Devices", - maxLength: 100, - nullable: true); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropColumn( - name: "Alias", - table: "Devices"); - } - } -} diff --git a/Server/Migrations/20200218144304_API Tokens and Device Updates.cs b/Server/Migrations/20200218144304_API Tokens and Device Updates.cs deleted file mode 100644 index e7806082..00000000 --- a/Server/Migrations/20200218144304_API Tokens and Device Updates.cs +++ /dev/null @@ -1,109 +0,0 @@ -using System; -using Microsoft.EntityFrameworkCore.Migrations; - -namespace Remotely.Server.Migrations -{ - public partial class APITokensandDeviceUpdates : Migration - { - protected override void Up(MigrationBuilder migrationBuilder) - { - migrationBuilder.RenameColumn( - name: "FreeMemory", - table: "Devices", - newName: "UsedMemory"); - - migrationBuilder.RenameColumn( - name: "FreeStorage", - table: "Devices", - newName: "UsedStorage"); - - migrationBuilder.AddColumn( - name: "CpuUtilization", - table: "Devices", - nullable: false, - defaultValue: 0.0); - - migrationBuilder.CreateTable( - name: "ApiTokens", - columns: table => new - { - ID = table.Column(nullable: false), - LastUsed = table.Column(nullable: true), - Name = table.Column(maxLength: 200, nullable: true), - OrganizationID = table.Column(nullable: true), - Secret = table.Column(nullable: true), - Token = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_ApiTokens", x => x.ID); - table.ForeignKey( - name: "FK_ApiTokens_Organizations_OrganizationID", - column: x => x.OrganizationID, - principalTable: "Organizations", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - - migrationBuilder.CreateIndex( - name: "IX_RemotelyUsers_UserName", - table: "RemotelyUsers", - column: "UserName"); - - migrationBuilder.CreateIndex( - name: "IX_Devices_DeviceName", - table: "Devices", - column: "DeviceName"); - - migrationBuilder.CreateIndex( - name: "IX_ApiTokens_OrganizationID", - table: "ApiTokens", - column: "OrganizationID"); - - migrationBuilder.CreateIndex( - name: "IX_ApiTokens_Token", - table: "ApiTokens", - column: "Token"); - } - - protected override void Down(MigrationBuilder migrationBuilder) - { - migrationBuilder.DropTable( - name: "ApiTokens"); - - migrationBuilder.DropIndex( - name: "IX_RemotelyUsers_UserName", - table: "RemotelyUsers"); - - migrationBuilder.DropIndex( - name: "IX_Devices_DeviceName", - table: "Devices"); - - migrationBuilder.DropColumn( - name: "CpuUtilization", - table: "Devices"); - - migrationBuilder.DropColumn( - name: "UsedMemory", - table: "Devices"); - - migrationBuilder.DropColumn( - name: "UsedStorage", - table: "Devices"); - - migrationBuilder.AddColumn( - name: "FreeMemory", - table: "Devices", - type: "REAL", - nullable: false, - defaultValue: 0.0); - - migrationBuilder.AddColumn( - name: "FreeStorage", - table: "Devices", - type: "REAL", - nullable: false, - defaultValue: 0.0); - } - } -} diff --git a/Server/Migrations/20200218144304_API Tokens and Device Updates.Designer.cs b/Server/Migrations/20200226021333_Initial.Designer.cs similarity index 68% rename from Server/Migrations/20200218144304_API Tokens and Device Updates.Designer.cs rename to Server/Migrations/20200226021333_Initial.Designer.cs index 475c5057..39ae38bc 100644 --- a/Server/Migrations/20200218144304_API Tokens and Device Updates.Designer.cs +++ b/Server/Migrations/20200226021333_Initial.Designer.cs @@ -4,35 +4,38 @@ using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Migrations; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Remotely.Server.Data; namespace Remotely.Server.Migrations { [DbContext(typeof(ApplicationDbContext))] - [Migration("20200218144304_API Tokens and Device Updates")] - partial class APITokensandDeviceUpdates + [Migration("20200226021333_Initial")] + partial class Initial { protected override void BuildTargetModel(ModelBuilder modelBuilder) { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.1"); + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { b.Property("Id") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("NormalizedName") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.HasKey("Id"); @@ -48,17 +51,18 @@ namespace Remotely.Server.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); b.Property("ClaimType") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ClaimValue") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("RoleId") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("Id"); @@ -70,57 +74,57 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => { b.Property("Id") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("AccessFailedCount") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Discriminator") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Email") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("EmailConfirmed") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("LockoutEnabled") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("LockoutEnd") - .HasColumnType("TEXT"); + .HasColumnType("timestamp with time zone"); b.Property("NormalizedEmail") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("NormalizedUserName") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("PasswordHash") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("PhoneNumber") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("PhoneNumberConfirmed") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("SecurityStamp") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TwoFactorEnabled") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("UserName") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.HasKey("Id"); @@ -141,17 +145,18 @@ namespace Remotely.Server.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); b.Property("ClaimType") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ClaimValue") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("UserId") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("Id"); @@ -163,19 +168,19 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { b.Property("LoginProvider") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("ProviderKey") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("ProviderDisplayName") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("UserId") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("LoginProvider", "ProviderKey"); @@ -187,10 +192,10 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { b.Property("UserId") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("RoleId") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("UserId", "RoleId"); @@ -202,18 +207,18 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { b.Property("UserId") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("LoginProvider") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("Value") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("UserId", "LoginProvider", "Name"); @@ -223,23 +228,23 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.ApiToken", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("LastUsed") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(200)") .HasMaxLength(200); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Secret") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Token") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("ID"); @@ -253,34 +258,34 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("CommandMode") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("CommandResults") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("CommandText") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("PSCoreResults") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("SenderConnectionID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("SenderUserID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TargetDeviceIDs") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TimeStamp") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.HasKey("ID"); @@ -292,72 +297,72 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.Device", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("AgentVersion") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Alias") - .HasColumnType("TEXT") + .HasColumnType("character varying(100)") .HasMaxLength(100); b.Property("CpuUtilization") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("CurrentUser") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("DeviceGroupID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("DeviceName") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Drives") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Is64Bit") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("IsOnline") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("LastOnline") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.Property("OSArchitecture") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("OSDescription") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Platform") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ProcessorCount") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("ServerVerificationToken") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Tags") - .HasColumnType("TEXT") + .HasColumnType("character varying(200)") .HasMaxLength(200); b.Property("TotalMemory") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("TotalStorage") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("UsedMemory") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("UsedStorage") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.HasKey("ID"); @@ -373,14 +378,14 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(200)") .HasMaxLength(200); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("ID"); @@ -392,25 +397,25 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.EventLog", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("EventType") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("Message") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Source") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("StackTrace") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TimeStamp") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.HasKey("ID"); @@ -422,22 +427,22 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("DateSent") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.Property("InvitedUser") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("IsAdmin") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ResetUrl") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("ID"); @@ -449,10 +454,10 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.Organization", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationName") - .HasColumnType("TEXT") + .HasColumnType("character varying(25)") .HasMaxLength(25); b.HasKey("ID"); @@ -463,22 +468,22 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ContentType") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("FileContents") - .HasColumnType("BLOB"); + .HasColumnType("bytea"); b.Property("FileName") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Timestamp") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.HasKey("ID"); @@ -487,18 +492,43 @@ namespace Remotely.Server.Migrations b.ToTable("SharedFiles"); }); + modelBuilder.Entity("Remotely.Shared.Models.UserDevicePermission", b => + { + b.Property("ID") + .HasColumnType("text"); + + b.Property("DeviceGroupID") + .HasColumnType("text"); + + b.Property("UserID") + .HasColumnType("text"); + + b.HasKey("ID"); + + b.HasIndex("DeviceGroupID"); + + b.HasIndex("UserID"); + + b.ToTable("PermissionLinks"); + }); + modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => { b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + b.Property("DeviceGroupID") + .HasColumnType("text"); + b.Property("IsAdministrator") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("UserOptions") - .HasColumnType("TEXT"); + .HasColumnType("text"); + + b.HasIndex("DeviceGroupID"); b.HasIndex("OrganizationID"); @@ -611,8 +641,23 @@ namespace Remotely.Server.Migrations .HasForeignKey("OrganizationID"); }); + modelBuilder.Entity("Remotely.Shared.Models.UserDevicePermission", b => + { + b.HasOne("Remotely.Shared.Models.DeviceGroup", "DeviceGroup") + .WithMany("PermissionLinks") + .HasForeignKey("DeviceGroupID"); + + b.HasOne("Remotely.Shared.Models.RemotelyUser", "User") + .WithMany("PermissionLinks") + .HasForeignKey("UserID"); + }); + modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => { + b.HasOne("Remotely.Shared.Models.DeviceGroup", null) + .WithMany("Users") + .HasForeignKey("DeviceGroupID"); + b.HasOne("Remotely.Shared.Models.Organization", "Organization") .WithMany("RemotelyUsers") .HasForeignKey("OrganizationID"); diff --git a/Server/Migrations/20191211163438_Initial.cs b/Server/Migrations/20200226021333_Initial.cs similarity index 81% rename from Server/Migrations/20191211163438_Initial.cs rename to Server/Migrations/20200226021333_Initial.cs index fe6acbdc..b4ffa354 100644 --- a/Server/Migrations/20191211163438_Initial.cs +++ b/Server/Migrations/20200226021333_Initial.cs @@ -1,5 +1,6 @@ using System; using Microsoft.EntityFrameworkCore.Migrations; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; namespace Remotely.Server.Migrations { @@ -38,7 +39,7 @@ namespace Remotely.Server.Migrations columns: table => new { Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), RoleId = table.Column(nullable: false), ClaimType = table.Column(nullable: true), ClaimValue = table.Column(nullable: true) @@ -54,6 +55,28 @@ namespace Remotely.Server.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "ApiTokens", + columns: table => new + { + ID = table.Column(nullable: false), + LastUsed = table.Column(nullable: true), + Name = table.Column(maxLength: 200, nullable: true), + OrganizationID = table.Column(nullable: true), + Secret = table.Column(nullable: true), + Token = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_ApiTokens", x => x.ID); + table.ForeignKey( + name: "FK_ApiTokens_Organizations_OrganizationID", + column: x => x.OrganizationID, + principalTable: "Organizations", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + }); + migrationBuilder.CreateTable( name: "CommandContexts", columns: table => new @@ -144,41 +167,6 @@ namespace Remotely.Server.Migrations onDelete: ReferentialAction.Restrict); }); - migrationBuilder.CreateTable( - name: "RemotelyUsers", - columns: table => new - { - Id = table.Column(nullable: false), - UserName = table.Column(maxLength: 256, nullable: true), - NormalizedUserName = table.Column(maxLength: 256, nullable: true), - Email = table.Column(maxLength: 256, nullable: true), - NormalizedEmail = table.Column(maxLength: 256, nullable: true), - EmailConfirmed = table.Column(nullable: false), - PasswordHash = table.Column(nullable: true), - SecurityStamp = table.Column(nullable: true), - ConcurrencyStamp = table.Column(nullable: true), - PhoneNumber = table.Column(nullable: true), - PhoneNumberConfirmed = table.Column(nullable: false), - TwoFactorEnabled = table.Column(nullable: false), - LockoutEnd = table.Column(nullable: true), - LockoutEnabled = table.Column(nullable: false), - AccessFailedCount = table.Column(nullable: false), - Discriminator = table.Column(nullable: false), - UserOptions = table.Column(nullable: true), - OrganizationID = table.Column(nullable: true), - IsAdministrator = table.Column(nullable: true) - }, - constraints: table => - { - table.PrimaryKey("PK_RemotelyUsers", x => x.Id); - table.ForeignKey( - name: "FK_RemotelyUsers_Organizations_OrganizationID", - column: x => x.OrganizationID, - principalTable: "Organizations", - principalColumn: "ID", - onDelete: ReferentialAction.Restrict); - }); - migrationBuilder.CreateTable( name: "SharedFiles", columns: table => new @@ -207,12 +195,14 @@ namespace Remotely.Server.Migrations { ID = table.Column(nullable: false), AgentVersion = table.Column(nullable: true), + Alias = table.Column(maxLength: 100, nullable: true), + CpuUtilization = table.Column(nullable: false), CurrentUser = table.Column(nullable: true), - DeviceName = table.Column(nullable: true), DeviceGroupID = table.Column(nullable: true), + DeviceName = table.Column(nullable: true), Drives = table.Column(nullable: true), - FreeMemory = table.Column(nullable: false), - FreeStorage = table.Column(nullable: false), + UsedMemory = table.Column(nullable: false), + UsedStorage = table.Column(nullable: false), Is64Bit = table.Column(nullable: false), IsOnline = table.Column(nullable: false), LastOnline = table.Column(nullable: false), @@ -243,12 +233,54 @@ namespace Remotely.Server.Migrations onDelete: ReferentialAction.Restrict); }); + migrationBuilder.CreateTable( + name: "RemotelyUsers", + columns: table => new + { + Id = table.Column(nullable: false), + UserName = table.Column(maxLength: 256, nullable: true), + NormalizedUserName = table.Column(maxLength: 256, nullable: true), + Email = table.Column(maxLength: 256, nullable: true), + NormalizedEmail = table.Column(maxLength: 256, nullable: true), + EmailConfirmed = table.Column(nullable: false), + PasswordHash = table.Column(nullable: true), + SecurityStamp = table.Column(nullable: true), + ConcurrencyStamp = table.Column(nullable: true), + PhoneNumber = table.Column(nullable: true), + PhoneNumberConfirmed = table.Column(nullable: false), + TwoFactorEnabled = table.Column(nullable: false), + LockoutEnd = table.Column(nullable: true), + LockoutEnabled = table.Column(nullable: false), + AccessFailedCount = table.Column(nullable: false), + Discriminator = table.Column(nullable: false), + UserOptions = table.Column(nullable: true), + OrganizationID = table.Column(nullable: true), + IsAdministrator = table.Column(nullable: true), + DeviceGroupID = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_RemotelyUsers", x => x.Id); + table.ForeignKey( + name: "FK_RemotelyUsers_DeviceGroups_DeviceGroupID", + column: x => x.DeviceGroupID, + principalTable: "DeviceGroups", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_RemotelyUsers_Organizations_OrganizationID", + column: x => x.OrganizationID, + principalTable: "Organizations", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + }); + migrationBuilder.CreateTable( name: "AspNetUserClaims", columns: table => new { Id = table.Column(nullable: false) - .Annotation("Sqlite:Autoincrement", true), + .Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn), UserId = table.Column(nullable: false), ClaimType = table.Column(nullable: true), ClaimValue = table.Column(nullable: true) @@ -328,6 +360,41 @@ namespace Remotely.Server.Migrations onDelete: ReferentialAction.Cascade); }); + migrationBuilder.CreateTable( + name: "PermissionLinks", + columns: table => new + { + ID = table.Column(nullable: false), + UserID = table.Column(nullable: true), + DeviceGroupID = table.Column(nullable: true) + }, + constraints: table => + { + table.PrimaryKey("PK_PermissionLinks", x => x.ID); + table.ForeignKey( + name: "FK_PermissionLinks_DeviceGroups_DeviceGroupID", + column: x => x.DeviceGroupID, + principalTable: "DeviceGroups", + principalColumn: "ID", + onDelete: ReferentialAction.Restrict); + table.ForeignKey( + name: "FK_PermissionLinks_RemotelyUsers_UserID", + column: x => x.UserID, + principalTable: "RemotelyUsers", + principalColumn: "Id", + onDelete: ReferentialAction.Restrict); + }); + + migrationBuilder.CreateIndex( + name: "IX_ApiTokens_OrganizationID", + table: "ApiTokens", + column: "OrganizationID"); + + migrationBuilder.CreateIndex( + name: "IX_ApiTokens_Token", + table: "ApiTokens", + column: "Token"); + migrationBuilder.CreateIndex( name: "IX_AspNetRoleClaims_RoleId", table: "AspNetRoleClaims", @@ -369,6 +436,11 @@ namespace Remotely.Server.Migrations table: "Devices", column: "DeviceGroupID"); + migrationBuilder.CreateIndex( + name: "IX_Devices_DeviceName", + table: "Devices", + column: "DeviceName"); + migrationBuilder.CreateIndex( name: "IX_Devices_OrganizationID", table: "Devices", @@ -384,6 +456,16 @@ namespace Remotely.Server.Migrations table: "InviteLinks", column: "OrganizationID"); + migrationBuilder.CreateIndex( + name: "IX_PermissionLinks_DeviceGroupID", + table: "PermissionLinks", + column: "DeviceGroupID"); + + migrationBuilder.CreateIndex( + name: "IX_PermissionLinks_UserID", + table: "PermissionLinks", + column: "UserID"); + migrationBuilder.CreateIndex( name: "EmailIndex", table: "RemotelyUsers", @@ -395,11 +477,21 @@ namespace Remotely.Server.Migrations column: "NormalizedUserName", unique: true); + migrationBuilder.CreateIndex( + name: "IX_RemotelyUsers_DeviceGroupID", + table: "RemotelyUsers", + column: "DeviceGroupID"); + migrationBuilder.CreateIndex( name: "IX_RemotelyUsers_OrganizationID", table: "RemotelyUsers", column: "OrganizationID"); + migrationBuilder.CreateIndex( + name: "IX_RemotelyUsers_UserName", + table: "RemotelyUsers", + column: "UserName"); + migrationBuilder.CreateIndex( name: "IX_SharedFiles_OrganizationID", table: "SharedFiles", @@ -408,6 +500,9 @@ namespace Remotely.Server.Migrations protected override void Down(MigrationBuilder migrationBuilder) { + migrationBuilder.DropTable( + name: "ApiTokens"); + migrationBuilder.DropTable( name: "AspNetRoleClaims"); @@ -435,6 +530,9 @@ namespace Remotely.Server.Migrations migrationBuilder.DropTable( name: "InviteLinks"); + migrationBuilder.DropTable( + name: "PermissionLinks"); + migrationBuilder.DropTable( name: "SharedFiles"); diff --git a/Server/Migrations/ApplicationDbContextModelSnapshot.cs b/Server/Migrations/ApplicationDbContextModelSnapshot.cs index 69f61cef..cabdabd5 100644 --- a/Server/Migrations/ApplicationDbContextModelSnapshot.cs +++ b/Server/Migrations/ApplicationDbContextModelSnapshot.cs @@ -3,6 +3,7 @@ using System; using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Infrastructure; using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; using Remotely.Server.Data; namespace Remotely.Server.Migrations @@ -14,23 +15,25 @@ namespace Remotely.Server.Migrations { #pragma warning disable 612, 618 modelBuilder - .HasAnnotation("ProductVersion", "3.1.1"); + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn) + .HasAnnotation("ProductVersion", "3.1.2") + .HasAnnotation("Relational:MaxIdentifierLength", 63); modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b => { b.Property("Id") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("NormalizedName") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.HasKey("Id"); @@ -46,17 +49,18 @@ namespace Remotely.Server.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); b.Property("ClaimType") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ClaimValue") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("RoleId") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("Id"); @@ -68,57 +72,57 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b => { b.Property("Id") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("AccessFailedCount") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("ConcurrencyStamp") .IsConcurrencyToken() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Discriminator") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Email") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("EmailConfirmed") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("LockoutEnabled") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("LockoutEnd") - .HasColumnType("TEXT"); + .HasColumnType("timestamp with time zone"); b.Property("NormalizedEmail") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("NormalizedUserName") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.Property("PasswordHash") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("PhoneNumber") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("PhoneNumberConfirmed") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("SecurityStamp") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TwoFactorEnabled") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("UserName") - .HasColumnType("TEXT") + .HasColumnType("character varying(256)") .HasMaxLength(256); b.HasKey("Id"); @@ -139,17 +143,18 @@ namespace Remotely.Server.Migrations { b.Property("Id") .ValueGeneratedOnAdd() - .HasColumnType("INTEGER"); + .HasColumnType("integer") + .HasAnnotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn); b.Property("ClaimType") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ClaimValue") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("UserId") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("Id"); @@ -161,19 +166,19 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin", b => { b.Property("LoginProvider") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("ProviderKey") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("ProviderDisplayName") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("UserId") .IsRequired() - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("LoginProvider", "ProviderKey"); @@ -185,10 +190,10 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole", b => { b.Property("UserId") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("RoleId") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("UserId", "RoleId"); @@ -200,18 +205,18 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken", b => { b.Property("UserId") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("LoginProvider") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(128)") .HasMaxLength(128); b.Property("Value") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("UserId", "LoginProvider", "Name"); @@ -221,23 +226,23 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.ApiToken", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("LastUsed") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(200)") .HasMaxLength(200); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Secret") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Token") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("ID"); @@ -251,34 +256,34 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("CommandMode") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("CommandResults") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("CommandText") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("PSCoreResults") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("SenderConnectionID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("SenderUserID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TargetDeviceIDs") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TimeStamp") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.HasKey("ID"); @@ -290,72 +295,72 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.Device", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("AgentVersion") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Alias") - .HasColumnType("TEXT") + .HasColumnType("character varying(100)") .HasMaxLength(100); b.Property("CpuUtilization") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("CurrentUser") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("DeviceGroupID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("DeviceName") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Drives") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Is64Bit") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("IsOnline") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("LastOnline") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.Property("OSArchitecture") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("OSDescription") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Platform") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ProcessorCount") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("ServerVerificationToken") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Tags") - .HasColumnType("TEXT") + .HasColumnType("character varying(200)") .HasMaxLength(200); b.Property("TotalMemory") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("TotalStorage") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("UsedMemory") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.Property("UsedStorage") - .HasColumnType("REAL"); + .HasColumnType("double precision"); b.HasKey("ID"); @@ -371,14 +376,14 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.DeviceGroup", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Name") - .HasColumnType("TEXT") + .HasColumnType("character varying(200)") .HasMaxLength(200); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("ID"); @@ -390,25 +395,25 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.EventLog", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("EventType") - .HasColumnType("INTEGER"); + .HasColumnType("integer"); b.Property("Message") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Source") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("StackTrace") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("TimeStamp") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.HasKey("ID"); @@ -420,22 +425,22 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("DateSent") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.Property("InvitedUser") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("IsAdmin") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ResetUrl") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.HasKey("ID"); @@ -447,10 +452,10 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.Organization", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationName") - .HasColumnType("TEXT") + .HasColumnType("character varying(25)") .HasMaxLength(25); b.HasKey("ID"); @@ -461,22 +466,22 @@ namespace Remotely.Server.Migrations modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b => { b.Property("ID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("ContentType") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("FileContents") - .HasColumnType("BLOB"); + .HasColumnType("bytea"); b.Property("FileName") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("Timestamp") - .HasColumnType("TEXT"); + .HasColumnType("timestamp without time zone"); b.HasKey("ID"); @@ -485,18 +490,43 @@ namespace Remotely.Server.Migrations b.ToTable("SharedFiles"); }); + modelBuilder.Entity("Remotely.Shared.Models.UserDevicePermission", b => + { + b.Property("ID") + .HasColumnType("text"); + + b.Property("DeviceGroupID") + .HasColumnType("text"); + + b.Property("UserID") + .HasColumnType("text"); + + b.HasKey("ID"); + + b.HasIndex("DeviceGroupID"); + + b.HasIndex("UserID"); + + b.ToTable("PermissionLinks"); + }); + modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => { b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser"); + b.Property("DeviceGroupID") + .HasColumnType("text"); + b.Property("IsAdministrator") - .HasColumnType("INTEGER"); + .HasColumnType("boolean"); b.Property("OrganizationID") - .HasColumnType("TEXT"); + .HasColumnType("text"); b.Property("UserOptions") - .HasColumnType("TEXT"); + .HasColumnType("text"); + + b.HasIndex("DeviceGroupID"); b.HasIndex("OrganizationID"); @@ -609,8 +639,23 @@ namespace Remotely.Server.Migrations .HasForeignKey("OrganizationID"); }); + modelBuilder.Entity("Remotely.Shared.Models.UserDevicePermission", b => + { + b.HasOne("Remotely.Shared.Models.DeviceGroup", "DeviceGroup") + .WithMany("PermissionLinks") + .HasForeignKey("DeviceGroupID"); + + b.HasOne("Remotely.Shared.Models.RemotelyUser", "User") + .WithMany("PermissionLinks") + .HasForeignKey("UserID"); + }); + modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b => { + b.HasOne("Remotely.Shared.Models.DeviceGroup", null) + .WithMany("Users") + .HasForeignKey("DeviceGroupID"); + b.HasOne("Remotely.Shared.Models.Organization", "Organization") .WithMany("RemotelyUsers") .HasForeignKey("OrganizationID"); diff --git a/Server/Pages/EditDevice.cshtml.cs b/Server/Pages/EditDevice.cshtml.cs index 7a71cdd9..fb3fe226 100644 --- a/Server/Pages/EditDevice.cshtml.cs +++ b/Server/Pages/EditDevice.cshtml.cs @@ -63,7 +63,7 @@ namespace Remotely.Server.Pages Input.Tags = device?.Tags; } - var groups = DataService.GetDeviceGroupsForUserName(User.Identity.Name); + var groups = DataService.GetDeviceGroups(User.Identity.Name); DeviceGroups.AddRange(groups.Select(x => new SelectListItem(x.Name, x.ID))); } public class InputModel diff --git a/Server/Pages/Index.cshtml.cs b/Server/Pages/Index.cshtml.cs index 2fe9b735..c74708fc 100644 --- a/Server/Pages/Index.cshtml.cs +++ b/Server/Pages/Index.cshtml.cs @@ -45,7 +45,7 @@ namespace Remotely.Server.Pages } DefaultPrompt = DataService.GetDefaultPrompt(User.Identity.Name); - var groups = DataService.GetDeviceGroupsForUserName(User.Identity.Name); + var groups = DataService.GetDeviceGroups(User.Identity.Name); if (groups?.Any() == true) { DeviceGroups.AddRange(groups.Select(x => new SelectListItem(x.Name, x.ID))); diff --git a/Server/Server.csproj b/Server/Server.csproj index b96d0739..4306e881 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -10,6 +10,7 @@ AnyCPU;x86;x64 Remotely.Server Remotely_Server + 36e32491-91a5-42e6-a466-819233f0c593 diff --git a/Server/Services/DataService.cs b/Server/Services/DataService.cs index 152d7609..3cc9900c 100644 --- a/Server/Services/DataService.cs +++ b/Server/Services/DataService.cs @@ -12,6 +12,7 @@ using Remotely.Server.Data; using Microsoft.Extensions.Hosting; using System.Threading.Tasks; using Remotely.Server.Auth; +using Microsoft.Extensions.Primitives; namespace Remotely.Server.Services { @@ -63,11 +64,6 @@ namespace Remotely.Server.Services return true; } - public string GetOrganizationNameById(string organizationID) - { - return RemotelyContext.Organizations.FirstOrDefault(x => x.ID == organizationID)?.OrganizationName; - } - public InviteLink AddInvite(string orgID, Invite invite) { invite.InvitedUser = invite.InvitedUser.ToLower(); @@ -105,18 +101,6 @@ namespace Remotely.Server.Services RemotelyContext.SaveChanges(); } - public bool SetNewUserProperties(string targetName, string organizationID, bool isAdmin) - { - var targetUser = GetUserByName(targetName); - - targetUser.OrganizationID = organizationID; - targetUser.IsAdministrator = isAdmin; - - RemotelyContext.SaveChanges(); - - return true; - } - public bool AddOrUpdateDevice(Device device, out Device updatedDevice) { device.LastOnline = DateTime.Now; @@ -261,18 +245,31 @@ namespace Remotely.Server.Services await RemotelyContext.SaveChangesAsync(); } - public void DeleteDeviceGroup(string orgID, string deviceGroupId) + public void DeleteDeviceGroup(string orgID, string deviceGroupID) { - var deviceGroup = RemotelyContext.DeviceGroups.FirstOrDefault(x => - x.ID == deviceGroupId && - x.OrganizationID == orgID); + var deviceGroup = RemotelyContext.DeviceGroups + .Include(x => x.Devices) + .Include(x => x.PermissionLinks) + .ThenInclude(x => x.User) + .FirstOrDefault(x => + x.ID == deviceGroupID && + x.OrganizationID == orgID); - deviceGroup.Devices.ForEach(x => + deviceGroup.Devices?.ForEach(x => { x.DeviceGroup = null; }); + deviceGroup.PermissionLinks?.ToList()?.ForEach(x => + { + x.User = null; + x.DeviceGroup = null; + + RemotelyContext.PermissionLinks.Remove(x); + }); + RemotelyContext.DeviceGroups.Remove(deviceGroup); + RemotelyContext.SaveChanges(); } @@ -319,24 +316,40 @@ namespace Remotely.Server.Services public bool DoesUserHaveAccessToDevice(string deviceID, RemotelyUser remotelyUser) { - return RemotelyContext.Devices.Any(x => x.ID == deviceID && x.OrganizationID == remotelyUser.OrganizationID); + return RemotelyContext.Devices + .Include(x => x.DeviceGroup) + .ThenInclude(x => x.PermissionLinks) + .Any(x => x.OrganizationID == remotelyUser.OrganizationID && + x.ID == deviceID && + ( + remotelyUser.IsAdministrator || + x.DeviceGroup.PermissionLinks.Count == 0 || + x.DeviceGroup.PermissionLinks.Any(x => x.UserID == remotelyUser.Id + ))); } public bool DoesUserHaveAccessToDevice(string deviceID, string remotelyUserID) { var remotelyUser = RemotelyContext.Users.Find(remotelyUserID); - return RemotelyContext.Devices.Any(x => x.ID == deviceID && x.OrganizationID == remotelyUser.OrganizationID); + return DoesUserHaveAccessToDevice(deviceID, remotelyUser); } public string[] FilterDeviceIDsByUserPermission(string[] deviceIDs, RemotelyUser remotelyUser) { - return RemotelyContext.Devices.Where(x => - deviceIDs.Contains(x.ID) && - x.OrganizationID == remotelyUser.OrganizationID - ) - .Select(x => x.ID) - .ToArray(); + return RemotelyContext.Devices + .Include(x => x.DeviceGroup) + .ThenInclude(x => x.PermissionLinks) + .Where(x => + x.OrganizationID == remotelyUser.OrganizationID && + deviceIDs.Contains(x.ID) && + ( + remotelyUser.IsAdministrator || + x.DeviceGroup.PermissionLinks.Count == 0 || + x.DeviceGroup.PermissionLinks.Any(x => x.UserID == remotelyUser.Id + ))) + .Select(x => x.ID) + .ToArray(); } public IEnumerable GetAllApiTokens(string userID) @@ -424,7 +437,7 @@ namespace Remotely.Server.Services return RemotelyContext.Devices.Count(); } - public IEnumerable GetDeviceGroupsForUserName(string username) + public IEnumerable GetDeviceGroups(string username) { var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == username); @@ -433,14 +446,33 @@ namespace Remotely.Server.Services return null; } - return RemotelyContext.DeviceGroups.Where(x => x.OrganizationID == user.OrganizationID) ?? Enumerable.Empty(); + return RemotelyContext.DeviceGroups + .Include(x => x.PermissionLinks) + .ThenInclude(x => x.User) + .Where(x => + x.OrganizationID == user.OrganizationID && + ( + user.IsAdministrator || + x.PermissionLinks.Any(x=>x.UserID == user.Id) + ) + ) ?? Enumerable.Empty(); } public IEnumerable GetDevicesForUser(string userName) { - // TODO: Add authorization groups. var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == userName); - return RemotelyContext.Devices.Where(x => x.OrganizationID == user.OrganizationID); + var userID = user.Id; + + return RemotelyContext.Devices + .Include(x => x.DeviceGroup) + .ThenInclude(x => x.PermissionLinks) + .Where(x => + x.OrganizationID == user.OrganizationID && + ( + user.IsAdministrator || + x.DeviceGroup.PermissionLinks.Count == 0 || + x.DeviceGroup.PermissionLinks.Any(x => x.UserID == userID + ))); } public IEnumerable GetEventLogs(string userName, DateTime from, DateTime to) @@ -471,6 +503,10 @@ namespace Remotely.Server.Services .OrganizationName; } + public string GetOrganizationNameById(string organizationID) + { + return RemotelyContext.Organizations.FirstOrDefault(x => x.ID == organizationID)?.OrganizationName; + } public SharedFile GetSharedFiled(string fileID) { return RemotelyContext.SharedFiles.Find(fileID); @@ -540,24 +576,107 @@ namespace Remotely.Server.Services RemotelyContext.SaveChanges(); } + public async Task RemoveUserFromDeviceGroup(string orgID, string groupID, string userID) + { + var deviceGroup = RemotelyContext.DeviceGroups + .Include(x => x.PermissionLinks) + .ThenInclude(x => x.User) + .FirstOrDefault(x => + x.ID == groupID && + x.OrganizationID == orgID); + + if (deviceGroup?.PermissionLinks?.Any(x => x.UserID == userID) == true) + { + var link = deviceGroup.PermissionLinks.FirstOrDefault(x => x.UserID == userID); + + link.User = null; + link.DeviceGroup = null; + + RemotelyContext.PermissionLinks.Remove(link); + + await RemotelyContext.SaveChangesAsync(); + return true; + } + return false; + } + + public bool AddUserToDeviceGroup(string orgID, string groupID, string userName, out string resultMessage) + { + resultMessage = string.Empty; + + var deviceGroup = RemotelyContext.DeviceGroups + .Include(x => x.PermissionLinks) + .FirstOrDefault(x => + x.ID == groupID && + x.OrganizationID == orgID); + + if (deviceGroup == null) + { + resultMessage = "Device group not found."; + return false; + } + + userName = userName.Trim().ToLower(); + + var user = RemotelyContext.Users + .Include(x => x.PermissionLinks) + .FirstOrDefault(x => + x.UserName.ToLower() == userName && + x.OrganizationID == orgID); + + if (user == null) + { + resultMessage = "User not found."; + return false; + } + + deviceGroup.PermissionLinks = deviceGroup.PermissionLinks ?? new List(); + user.PermissionLinks = user.PermissionLinks ?? new List(); + + if (deviceGroup.PermissionLinks.Any(x => x.UserID == user.Id)) + { + resultMessage = "User already in group."; + return false; + } + + var link = new UserDevicePermission() + { + DeviceGroup = deviceGroup, + DeviceGroupID = deviceGroup.ID, + User = user, + UserID = user.Id + }; + + deviceGroup.PermissionLinks.Add(link); + user.PermissionLinks.Add(link); + RemotelyContext.SaveChanges(); + resultMessage = user.Id; + return true; + } + public async Task RemoveUserFromOrganization(string orgID, string targetUserID) { - var target = RemotelyContext.Users.FirstOrDefault(x => - x.Id == targetUserID && - x.OrganizationID == orgID); + var target = RemotelyContext.Users + .Include(x => x.PermissionLinks) + .ThenInclude(x => x.DeviceGroup) + .FirstOrDefault(x => + x.Id == targetUserID && + x.OrganizationID == orgID); - if (GetOrganizationCount() >= AppConfig.MaxOrganizationCount) + if (target?.PermissionLinks?.Any() == true) { - await UserManager.DeleteAsync(target); - } - else - { - var newOrganization = new Organization(); - target.Organization = newOrganization; - RemotelyContext.Organizations.Add(newOrganization); + foreach (var link in target.PermissionLinks.ToList()) + { + link.DeviceGroup = null; + link.User = null; + + RemotelyContext.PermissionLinks.Remove(link); + } } - RemotelyContext.SaveChanges(); + await RemotelyContext.SaveChangesAsync(); + + await UserManager.DeleteAsync(target); } public async Task RenameApiToken(string userName, string tokenId, string tokenName) @@ -602,6 +721,17 @@ namespace Remotely.Server.Services } } + public bool SetNewUserProperties(string targetName, string organizationID, bool isAdmin) + { + var targetUser = GetUserByName(targetName); + + targetUser.OrganizationID = organizationID; + targetUser.IsAdministrator = isAdmin; + + RemotelyContext.SaveChanges(); + + return true; + } public void SetServerVerificationToken(string deviceID, string verificationToken) { var device = RemotelyContext.Devices.Find(deviceID); diff --git a/Server/Startup.cs b/Server/Startup.cs index e1665ffc..0330776e 100644 --- a/Server/Startup.cs +++ b/Server/Startup.cs @@ -30,6 +30,8 @@ using Microsoft.Extensions.Hosting; using Swashbuckle.AspNetCore.Swagger; using Microsoft.OpenApi.Models; using Remotely.Server.Auth; +using Microsoft.Data.SqlClient; +using Npgsql; namespace Remotely.Server { @@ -69,9 +71,17 @@ namespace Remotely.Server } else if (dbProvider == "postgresql") { + var connectionBuilder = new NpgsqlConnectionStringBuilder(Configuration.GetConnectionString("PostgreSQL")); + + // Password needs to be set in User Secrets in dev environment. + // See https://docs.microsoft.com/en-us/aspnet/core/security/app-secrets?view=aspnetcore-3.1 + if (IsDev) + { + connectionBuilder.Password = Configuration["PostgresPassword"]; + } + services.AddDbContext(options => - options.UseNpgsql( - Configuration.GetConnectionString("PostgreSQL"))); + options.UseNpgsql(connectionBuilder.ConnectionString)); } services.AddIdentity(options => options.Stores.MaxLengthForKeys = 128) diff --git a/Server/appsettings.json b/Server/appsettings.json index 3bd4ddd3..9f4788ad 100644 --- a/Server/appsettings.json +++ b/Server/appsettings.json @@ -2,7 +2,7 @@ "ConnectionStrings": { "SQLite": "DataSource=Server.db", "SQLServer": "Server=(localdb)\\mssqllocaldb;Database=Remotely-Server-53bc9b9d-9d6a-45d4-8429-2a2761773502;Trusted_Connection=True;MultipleActiveResultSets=true", - "PostgreSQL": "Host=localhost;Database=;Username=;Password=" + "PostgreSQL": "Host=localhost;Database=Remotely;Username=postgres;" }, "Logging": { "LogLevel": { @@ -13,7 +13,7 @@ "AllowApiLogin": false, "MaxOrganizationCount": 1, "DataRetentionInDays": 90, - "DBProvider": "SQLite", + "DBProvider": "PostgreSQL", "DefaultPrompt": "~>", "EnableWindowsEventLog": false, "KnownProxies": [], @@ -21,7 +21,7 @@ "RedirectToHttps": false, "RemoteControlSessionLimit": 1, "RemoteControlRequiresAuthentication": true, - "Require2FA": false, + "Require2FA": false, "SmtpHost": "", "SmtpPort": 25, "SmtpUserName": "", @@ -32,6 +32,6 @@ "TrustedCorsOrigins": [], "Theme": "Light", "UseHsts": false, - "UseWebRtc": true + "UseWebRtc": true } } \ No newline at end of file diff --git a/Server/wwwroot/scripts/Pages/OrganizationManagement.js b/Server/wwwroot/scripts/Pages/OrganizationManagement.js index 7a524717..40bb2f79 100644 --- a/Server/wwwroot/scripts/Pages/OrganizationManagement.js +++ b/Server/wwwroot/scripts/Pages/OrganizationManagement.js @@ -13,17 +13,31 @@ document.getElementById("invitesHelpButton").addEventListener("click", (ev) => { document.getElementById("deviceGroupHelpButton").addEventListener("click", (ev) => { ShowModal("Device Groups", `Device groups can be used to organize and filter computers on the grid.`); }); +document.getElementById("addUsersToDeviceGroupButton").addEventListener("click", (ev) => { + var selectList = document.getElementById("deviceGroupList"); + if (selectList.selectedOptions.length == 0) { + return; + } + if (selectList.selectedOptions.length > 1) { + ShowModal("Device Group Users", "You can only edit users for 1 device group at a time."); + return; + } + var groupID = selectList.selectedOptions[0].value; + var modalDiv = document.querySelector(`.modal[group='${groupID}']`); + $(modalDiv).modal("show"); +}); document.getElementById("removeDeviceGroupButton").addEventListener("click", (ev) => { var selectList = document.getElementById("deviceGroupList"); + var selectedValues = []; for (var i = 0; i < selectList.selectedOptions.length; i++) { - let selectedValue = selectList.selectedOptions[i].value; + selectedValues.push(selectList.selectedOptions[i].value); + } + selectedValues.forEach(x => { let xhr = new XMLHttpRequest(); xhr.onload = (ev) => { console.log(ev.srcElement); if (xhr.status == 200) { - document.querySelectorAll(`.all-device-groups-list option[value='${selectedValue}']`).forEach(option => { - option.remove(); - }); + document.querySelector(`#deviceGroupList option[value='${x}']`).remove(); } else if (xhr.status == 400) { ShowModal("Invalid Request", xhr.responseText); @@ -37,25 +51,60 @@ document.getElementById("removeDeviceGroupButton").addEventListener("click", (ev }; xhr.open("delete", location.origin + "/api/OrganizationManagement/DeviceGroup"); xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(JSON.stringify(selectedValue)); - } + xhr.send(JSON.stringify(x)); + }); }); document.getElementById("deviceGroupInput").addEventListener("keypress", (e) => { if (e.key.toLowerCase() == "enter") { document.getElementById("addDeviceGroupButton").click(); } }); -document.getElementById("addDeviceGroupButton").addEventListener("click", () => { - var input = document.getElementById("deviceGroupInput"); - if (input.checkValidity() && input.value.length > 0) { - var xhr = new XMLHttpRequest(); - xhr.onload = () => { +document.querySelectorAll(".remove-user-from-device-group-button").forEach((x) => { + x.addEventListener("click", clickEv => { + var groupID = clickEv.currentTarget.getAttribute("group"); + var selectList = document.querySelector(`.modal[group='${groupID}'] select.device-group-user-list`); + var selectedValues = []; + for (var i = 0; i < selectList.selectedOptions.length; i++) { + selectedValues.push(selectList.selectedOptions[i].value); + } + selectedValues.forEach(user => { + let xhr = new XMLHttpRequest(); + xhr.onload = (ev) => { + console.log(ev.srcElement); + if (xhr.status == 200) { + selectList.querySelector(`option[value='${user}']`).remove(); + } + else if (xhr.status == 400) { + ShowModal("Invalid Request", xhr.responseText); + } + else { + showError(xhr); + } + }; + xhr.onerror = () => { + showError(xhr); + }; + xhr.open("delete", location.origin + `/api/OrganizationManagement/DeviceGroup/${groupID}/Users/`); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(JSON.stringify(user)); + }); + }); +}); +document.querySelectorAll(".add-user-to-devicegroup-button").forEach((x) => { + x.addEventListener("click", (clickEv) => { + var groupID = clickEv.currentTarget.getAttribute("group"); + var modal = document.querySelector(`.modal[group='${groupID}']`); + var selectList = modal.querySelector(`select.device-group-user-list`); + var userInput = modal.querySelector(`input.add-user-to-devicegroup-input`); + let xhr = new XMLHttpRequest(); + xhr.onload = (ev) => { + console.log(ev.srcElement); if (xhr.status == 200) { - document.querySelectorAll(`.all-device-groups-list`).forEach((list) => { - var newOption = new Option(input.value, xhr.responseText); - list.options.add(newOption); - }); - input.value = ""; + var option = document.createElement("option"); + option.value = xhr.responseText; + option.text = userInput.value; + selectList.options.add(option); + userInput.value = ""; } else if (xhr.status == 400) { ShowModal("Invalid Request", xhr.responseText); @@ -67,10 +116,18 @@ document.getElementById("addDeviceGroupButton").addEventListener("click", () => xhr.onerror = () => { showError(xhr); }; - xhr.open("post", location.origin + "/api/OrganizationManagement/DeviceGroup"); + xhr.open("post", location.origin + `/api/OrganizationManagement/DeviceGroup/${groupID}/Users/`); xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(JSON.stringify({ Name: input.value })); - } + xhr.send(JSON.stringify(userInput.value)); + }); +}); +document.querySelectorAll(".add-user-to-devicegroup-input").forEach(x => { + x.addEventListener("keypress", (ev) => { + if (ev.key.toLowerCase() == "enter") { + var groupID = ev.currentTarget.getAttribute("group"); + document.querySelector(`.add-user-to-devicegroup-button[group='${groupID}']`).click(); + } + }); }); document.getElementById("organizationNameInput").addEventListener("input", (ev) => { var addon = ev.currentTarget.parentElement.querySelector(".fa"); diff --git a/Server/wwwroot/scripts/Pages/OrganizationManagement.js.map b/Server/wwwroot/scripts/Pages/OrganizationManagement.js.map index 2c067b66..448f4f6e 100644 --- a/Server/wwwroot/scripts/Pages/OrganizationManagement.js.map +++ b/Server/wwwroot/scripts/Pages/OrganizationManagement.js.map @@ -1 +1 @@ -{"version":3,"file":"OrganizationManagement.js","sourceRoot":"","sources":["OrganizationManagement.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"OrganizationManagement.js","sourceRoot":"","sources":["OrganizationManagement.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/Server/wwwroot/scripts/Pages/OrganizationManagement.ts b/Server/wwwroot/scripts/Pages/OrganizationManagement.ts index b86ba630..b5e715e4 100644 --- a/Server/wwwroot/scripts/Pages/OrganizationManagement.ts +++ b/Server/wwwroot/scripts/Pages/OrganizationManagement.ts @@ -18,17 +18,34 @@ document.getElementById("deviceGroupHelpButton").addEventListener("click", (ev) }); +document.getElementById("addUsersToDeviceGroupButton").addEventListener("click", (ev) => { + var selectList = document.getElementById("deviceGroupList") as HTMLSelectElement; + if (selectList.selectedOptions.length == 0) { + return; + } + if (selectList.selectedOptions.length > 1) { + ShowModal("Device Group Users", "You can only edit users for 1 device group at a time."); + return; + } + + var groupID = selectList.selectedOptions[0].value; + var modalDiv = document.querySelector(`.modal[group='${groupID}']`) as HTMLDivElement; + $(modalDiv).modal("show"); +}); + document.getElementById("removeDeviceGroupButton").addEventListener("click", (ev) => { var selectList = document.getElementById("deviceGroupList") as HTMLSelectElement; + var selectedValues = []; for (var i = 0; i < selectList.selectedOptions.length; i++) { - let selectedValue = selectList.selectedOptions[i].value; + selectedValues.push(selectList.selectedOptions[i].value); + } + + selectedValues.forEach(x => { let xhr = new XMLHttpRequest(); xhr.onload = (ev) => { console.log(ev.srcElement); if (xhr.status == 200) { - document.querySelectorAll(`.all-device-groups-list option[value='${selectedValue}']`).forEach(option => { - option.remove(); - }) + document.querySelector(`#deviceGroupList option[value='${x}']`).remove(); } else if (xhr.status == 400) { ShowModal("Invalid Request", xhr.responseText); @@ -42,27 +59,64 @@ document.getElementById("removeDeviceGroupButton").addEventListener("click", (ev } xhr.open("delete", location.origin + "/api/OrganizationManagement/DeviceGroup"); xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(JSON.stringify(selectedValue)); - } - + xhr.send(JSON.stringify(x)); + }) }); document.getElementById("deviceGroupInput").addEventListener("keypress", (e) => { if (e.key.toLowerCase() == "enter") { document.getElementById("addDeviceGroupButton").click(); } }) -document.getElementById("addDeviceGroupButton").addEventListener("click", () => { - var input = document.getElementById("deviceGroupInput") as HTMLInputElement; - if (input.checkValidity() && input.value.length > 0) { - var xhr = new XMLHttpRequest(); - xhr.onload = () => { +document.querySelectorAll(".remove-user-from-device-group-button").forEach((x:HTMLElement) => { + x.addEventListener("click", clickEv => { + var groupID = (clickEv.currentTarget as HTMLButtonElement).getAttribute("group"); + var selectList = document.querySelector(`.modal[group='${groupID}'] select.device-group-user-list`) as HTMLSelectElement; + var selectedValues = []; + for (var i = 0; i < selectList.selectedOptions.length; i++) { + selectedValues.push(selectList.selectedOptions[i].value); + } + + selectedValues.forEach(user => { + let xhr = new XMLHttpRequest(); + xhr.onload = (ev) => { + console.log(ev.srcElement); + if (xhr.status == 200) { + selectList.querySelector(`option[value='${user}']`).remove() + } + else if (xhr.status == 400) { + ShowModal("Invalid Request", xhr.responseText); + } + else { + showError(xhr); + } + } + xhr.onerror = () => { + showError(xhr); + } + xhr.open("delete", location.origin + `/api/OrganizationManagement/DeviceGroup/${groupID}/Users/`); + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(JSON.stringify(user)); + }) + }) +}); + +document.querySelectorAll(".add-user-to-devicegroup-button").forEach((x: HTMLElement) => { + x.addEventListener("click", (clickEv) => { + var groupID = (clickEv.currentTarget as HTMLButtonElement).getAttribute("group"); + var modal = document.querySelector(`.modal[group='${groupID}']`); + var selectList = modal.querySelector(`select.device-group-user-list`) as HTMLSelectElement; + var userInput = modal.querySelector(`input.add-user-to-devicegroup-input`) as HTMLInputElement; + + let xhr = new XMLHttpRequest(); + xhr.onload = (ev) => { + console.log(ev.srcElement); if (xhr.status == 200) { - document.querySelectorAll(`.all-device-groups-list`).forEach((list: HTMLSelectElement) => { - var newOption = new Option(input.value, xhr.responseText); - list.options.add(newOption); - }) - input.value = ""; + var option = document.createElement("option"); + option.value = xhr.responseText; + option.text = userInput.value; + selectList.options.add(option) + userInput.value = ""; } else if (xhr.status == 400) { ShowModal("Invalid Request", xhr.responseText); @@ -74,10 +128,20 @@ document.getElementById("addDeviceGroupButton").addEventListener("click", () => xhr.onerror = () => { showError(xhr); } - xhr.open("post", location.origin + "/api/OrganizationManagement/DeviceGroup"); + xhr.open("post", location.origin + `/api/OrganizationManagement/DeviceGroup/${groupID}/Users/`); xhr.setRequestHeader("Content-Type", "application/json"); - xhr.send(JSON.stringify({ Name: input.value })); - } + xhr.send(JSON.stringify(userInput.value)); + }); +}) + + +document.querySelectorAll(".add-user-to-devicegroup-input").forEach(x => { + x.addEventListener("keypress", (ev: KeyboardEvent) => { + if (ev.key.toLowerCase() == "enter") { + var groupID = (ev.currentTarget as HTMLInputElement).getAttribute("group"); + (document.querySelector(`.add-user-to-devicegroup-button[group='${groupID}']`) as HTMLButtonElement).click(); + } + }) }) document.getElementById("organizationNameInput").addEventListener("input", (ev) => { diff --git a/Shared/Models/ApiToken.cs b/Shared/Models/ApiToken.cs index 9c7bbac4..2915c4d3 100644 --- a/Shared/Models/ApiToken.cs +++ b/Shared/Models/ApiToken.cs @@ -17,7 +17,7 @@ namespace Remotely.Shared.Models public string Name { get; set; } [JsonIgnore] - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } public string OrganizationID { get; set; } public string Secret { get; set; } diff --git a/Shared/Models/CommandContext.cs b/Shared/Models/CommandContext.cs index 3cbe1fba..1e022ca5 100644 --- a/Shared/Models/CommandContext.cs +++ b/Shared/Models/CommandContext.cs @@ -19,7 +19,7 @@ namespace Remotely.Shared.Models public ICollection CommandResults { get; set; } = new List(); public DateTime TimeStamp { get; set; } = DateTime.Now; [JsonIgnore] - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } public string OrganizationID { get; set; } } } diff --git a/Shared/Models/Device.cs b/Shared/Models/Device.cs index 144d7c45..81b5c973 100644 --- a/Shared/Models/Device.cs +++ b/Shared/Models/Device.cs @@ -19,7 +19,7 @@ namespace Remotely.Shared.Models public string Alias { get; set; } public double CpuUtilization { get; set; } public string CurrentUser { get; set; } - public virtual DeviceGroup DeviceGroup { get; set; } + public DeviceGroup DeviceGroup { get; set; } public string DeviceGroupID { get; set; } public string DeviceName { get; set; } public List Drives { get; set; } @@ -37,7 +37,7 @@ namespace Remotely.Shared.Models public DateTime LastOnline { get; set; } [JsonIgnore] - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } public string OrganizationID { get; set; } public Architecture OSArchitecture { get; set; } diff --git a/Shared/Models/DeviceGroup.cs b/Shared/Models/DeviceGroup.cs index d2c5f1b2..d0b9e4ca 100644 --- a/Shared/Models/DeviceGroup.cs +++ b/Shared/Models/DeviceGroup.cs @@ -14,11 +14,14 @@ namespace Remotely.Shared.Models [Key] public string ID { get; set; } = Guid.NewGuid().ToString(); - public virtual List Devices { get; set; } + [JsonIgnore] + public List Devices { get; set; } [JsonIgnore] public Organization Organization { get; set; } public string OrganizationID { get; set; } + + public List PermissionLinks { get; set; } } } diff --git a/Shared/Models/EventLog.cs b/Shared/Models/EventLog.cs index 56e69874..5dc822fe 100644 --- a/Shared/Models/EventLog.cs +++ b/Shared/Models/EventLog.cs @@ -17,7 +17,7 @@ namespace Remotely.Shared.Models public string OrganizationID { get; set; } public DateTime TimeStamp { get; set; } = DateTime.Now; [JsonIgnore] - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } } public enum EventType { diff --git a/Shared/Models/InviteLink.cs b/Shared/Models/InviteLink.cs index 65e660d4..37cb8ae6 100644 --- a/Shared/Models/InviteLink.cs +++ b/Shared/Models/InviteLink.cs @@ -14,7 +14,7 @@ namespace Remotely.Shared.Models public bool IsAdmin { get; set; } public DateTime DateSent { get; set; } [JsonIgnore] - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } public string OrganizationID { get; set; } public string ResetUrl { get; set; } } diff --git a/Shared/Models/Organization.cs b/Shared/Models/Organization.cs index b84de729..5552face 100644 --- a/Shared/Models/Organization.cs +++ b/Shared/Models/Organization.cs @@ -7,24 +7,24 @@ namespace Remotely.Shared.Models { public class Organization { - public virtual ICollection ApiTokens { get; set; } + public ICollection ApiTokens { get; set; } - public virtual ICollection CommandContexts { get; set; } + public ICollection CommandContexts { get; set; } - public virtual ICollection DeviceGroups { get; set; } + public ICollection DeviceGroups { get; set; } - public virtual ICollection Devices { get; set; } + public ICollection Devices { get; set; } - public virtual ICollection EventLogs { get; set; } + public ICollection EventLogs { get; set; } [Key] public string ID { get; set; } = Guid.NewGuid().ToString(); - public virtual ICollection InviteLinks { get; set; } + public ICollection InviteLinks { get; set; } [StringLength(25)] public string OrganizationName { get; set; } - public virtual ICollection RemotelyUsers { get; set; } - public virtual ICollection SharedFiles { get; set; } + public ICollection RemotelyUsers { get; set; } + public ICollection SharedFiles { get; set; } } } \ No newline at end of file diff --git a/Shared/Models/RemotelyUser.cs b/Shared/Models/RemotelyUser.cs index 5b02e3bd..ee6b3c61 100644 --- a/Shared/Models/RemotelyUser.cs +++ b/Shared/Models/RemotelyUser.cs @@ -18,9 +18,11 @@ namespace Remotely.Shared.Models public RemotelyUserOptions UserOptions { get; set; } [JsonIgnore] - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } public string OrganizationID { get; set; } public bool IsAdministrator { get; set; } = true; + + public List PermissionLinks { get; set; } } } diff --git a/Shared/Models/SharedFile.cs b/Shared/Models/SharedFile.cs index d71b0a07..835830a1 100644 --- a/Shared/Models/SharedFile.cs +++ b/Shared/Models/SharedFile.cs @@ -13,7 +13,7 @@ namespace Remotely.Shared.Models public string ContentType { get; set; } public byte[] FileContents { get; set; } public DateTime Timestamp { get; set; } = DateTime.Now; - public virtual Organization Organization { get; set; } + public Organization Organization { get; set; } public string OrganizationID { get; set; } } } diff --git a/Shared/Models/UserDevicePermission.cs b/Shared/Models/UserDevicePermission.cs new file mode 100644 index 00000000..d246172f --- /dev/null +++ b/Shared/Models/UserDevicePermission.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Text; +using System.Text.Json.Serialization; + +namespace Remotely.Shared.Models +{ + public class UserDevicePermission + { + [Key] + public string ID { get; set; } = Guid.NewGuid().ToString(); + + public string UserID { get; set; } + + [JsonIgnore] + public RemotelyUser User { get; set; } + + public string DeviceGroupID { get; set; } + + [JsonIgnore] + public DeviceGroup DeviceGroup { get; set; } + } +}