Password reset link is now displayed in Organization Management when a user account is created as a result of an invite.

This commit is contained in:
Jared Goodwin 2019-07-03 15:59:20 -07:00
parent 10cdcddf5b
commit 434ffdf9fb
15 changed files with 643 additions and 58 deletions

View File

@ -19,8 +19,7 @@ The following steps will configure your Windows 10 machine for building the Remo
* Example: powershell -f [path]\Publish.ps1 -outdir C:\inetpub\remotely -rid win10-x86
* The output folder will now contain the server, with the clients in the Downloads folder.
* By default, the screen-sharing desktop app prompts for a host URL and can be changed thereafter.
* To hard-code a URL, set the Host value in /Desktop.Win/Services/Config.cs to the server's URL (same for the Desktop.Unix project).
* To hide the server name in the app, set ShowHostName to false.
* To hard-code an initial URL, set the Host value in /Desktop.Win/Services/Config.cs to the server's URL (same for the Desktop.Unix project).
## Hosting a Server (Windows)
* Create a site in IIS that will run Remotely.

View File

@ -23,14 +23,14 @@ namespace Remotely.Server.API
public DataService DataService { get; set; }
// GET api/<controller>/5
[HttpGet("{id}")]
public FileResult Get(string id)
public ActionResult Get(string id)
{
var sharedFile = DataService.GetSharedFiled(id);
if (sharedFile != null)
{
return File(sharedFile.FileContents, sharedFile.ContentType, sharedFile.FileName);
}
return null;
return NotFound();
}
[HttpPost]

View File

@ -120,18 +120,6 @@ namespace Remotely.Server.API
}
return Ok(result.Item2);
}
[HttpDelete("RemoveUserFromOrganization/{userID}")]
public IActionResult RemoveUserFromOrganization(string userID)
{
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
{
return Unauthorized();
}
DataService.RemoveUserFromOrganization(User.Identity.Name, userID);
return Ok("ok");
}
[HttpDelete("RemovePermissionFromUser/{userID}/{permissionID}")]
public IActionResult RemovePermissionFromUser(string userID, string permissionID)
{
@ -143,6 +131,18 @@ namespace Remotely.Server.API
DataService.RemovePermissionFromUser(User.Identity.Name, userID, permissionID.Trim());
return Ok("ok");
}
[HttpDelete("RemoveUserFromOrganization/{userID}")]
public IActionResult RemoveUserFromOrganization(string userID)
{
if (!DataService.GetUserByName(User.Identity.Name).IsAdministrator)
{
return Unauthorized();
}
DataService.RemoveUserFromOrganization(User.Identity.Name, userID);
return Ok("ok");
}
[HttpPost("SendInvite")]
public async Task<IActionResult> SendInvite([FromBody]Invite invite)
{
@ -166,16 +166,18 @@ namespace Remotely.Server.API
await UserManager.ConfirmEmailAsync(user, await UserManager.GenerateEmailConfirmationTokenAsync(user));
var resetCode = UrlEncoder.Default.Encode(await UserManager.GeneratePasswordResetTokenAsync(user));
var resetUrl = $"{Request.Scheme}://{Request.Host}/Identity/Account/ResetPassword?code={resetCode}";
invite.ResetUrl = resetUrl;
newUserMessage = $@"<br><br>Since you don't have an account yet, one has been created for you.
You will need to set a password first before attempting to join the organization.<br><br>
Set your password by <a href='{resetUrl}'>clicking here</a>. Your username/email
is <strong>${invite.InvitedUser}</strong>.";
is <strong>{invite.InvitedUser}</strong>.";
}
else
{
return BadRequest("There was an issue creating the new account.");
}
}
var newInvite = DataService.AddInvite(User.Identity.Name, invite, Request.Scheme + "://" + Request.Host);
var inviteURL = $"{Request.Scheme}://{Request.Host}/Invite?id={newInvite.ID}";

View File

@ -103,7 +103,7 @@
<tr>
<th>Invited User</th>
<th>Administrator</th>
<th>URL</th>
<th>Link(s)</th>
<th>Delete</th>
</tr>
</thead>
@ -113,7 +113,16 @@
<tr invite="@Model.Invites[i].ID">
<td class="middle-aligned"><label class="control-label">@Model.Invites[i].InvitedUser</label></td>
<td class="middle-aligned text-center">@Html.CheckBoxFor(x => x.Invites[i].IsAdmin, new { disabled = "disabled" })</td>
<td class="middle-aligned"><label class="control-label">@Request.Scheme://@Request.Host/Invite/?id=@Model.Invites[i].ID</label></td>
<td class="middle-aligned">
<label class="control-label">
<a href="@Request.Scheme://@Request.Host/Invite/?id=@Model.Invites[i].ID">Join Link</a>
@if (!string.IsNullOrWhiteSpace(Model.Invites[i].ResetUrl))
{
<br />
<a href="@Model.Invites[i].ResetUrl">Reset Password</a>
}
</label>
</td>
<td><button type="button" class="btn btn-danger delete-invite-button" invite="@Model.Invites[i].ID">Delete</button></td>
</tr>
}

View File

@ -75,7 +75,8 @@ namespace Remotely.Server.Areas.Identity.Pages.Account.Manage
ID = x.ID,
InvitedUser = x.InvitedUser,
IsAdmin = x.IsAdmin,
DateSent = x.DateSent
DateSent = x.DateSent,
ResetUrl = x.ResetUrl
}).ToList();
}
}

View File

@ -314,7 +314,8 @@ namespace Remotely.Server.Data
DateSent = DateTime.Now,
InvitedUser = invite.InvitedUser,
IsAdmin = invite.IsAdmin,
Organization = requester.Organization
Organization = requester.Organization,
ResetUrl = invite.ResetUrl
};
requester.Organization.InviteLinks.Add(newInvite);
RemotelyContext.SaveChanges();
@ -468,6 +469,11 @@ namespace Remotely.Server.Data
.ThenInclude(x => x.InviteLinks)
.FirstOrDefault(x => x.UserName == requesterUserName);
var invite = requester.Organization.InviteLinks.FirstOrDefault(x => x.ID == inviteID);
var user = RemotelyContext.Users.FirstOrDefault(x => x.UserName == invite.InvitedUser);
if (string.IsNullOrWhiteSpace(user.PasswordHash))
{
RemotelyContext.Remove(user);
}
RemotelyContext.Remove(invite);
RemotelyContext.SaveChanges();
}

View File

@ -0,0 +1,527 @@
// <auto-generated />
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("20190703215422_ResetUrl")]
partial class ResetUrl
{
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Name")
.HasMaxLength(256);
b.Property<string>("NormalizedName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedName")
.IsUnique()
.HasName("RoleNameIndex");
b.ToTable("AspNetRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("RoleId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("RoleId");
b.ToTable("AspNetRoleClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUser", b =>
{
b.Property<string>("Id")
.ValueGeneratedOnAdd();
b.Property<int>("AccessFailedCount");
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken();
b.Property<string>("Discriminator")
.IsRequired();
b.Property<string>("Email")
.HasMaxLength(256);
b.Property<bool>("EmailConfirmed");
b.Property<bool>("LockoutEnabled");
b.Property<DateTimeOffset?>("LockoutEnd");
b.Property<string>("NormalizedEmail")
.HasMaxLength(256);
b.Property<string>("NormalizedUserName")
.HasMaxLength(256);
b.Property<string>("PasswordHash");
b.Property<string>("PhoneNumber");
b.Property<bool>("PhoneNumberConfirmed");
b.Property<string>("SecurityStamp");
b.Property<bool>("TwoFactorEnabled");
b.Property<string>("UserName")
.HasMaxLength(256);
b.HasKey("Id");
b.HasIndex("NormalizedEmail")
.HasName("EmailIndex");
b.HasIndex("NormalizedUserName")
.IsUnique()
.HasName("UserNameIndex");
b.ToTable("RemotelyUsers");
b.HasDiscriminator<string>("Discriminator").HasValue("IdentityUser");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd();
b.Property<string>("ClaimType");
b.Property<string>("ClaimValue");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("Id");
b.HasIndex("UserId");
b.ToTable("AspNetUserClaims");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("ProviderKey")
.HasMaxLength(128);
b.Property<string>("ProviderDisplayName");
b.Property<string>("UserId")
.IsRequired();
b.HasKey("LoginProvider", "ProviderKey");
b.HasIndex("UserId");
b.ToTable("AspNetUserLogins");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("RoleId");
b.HasKey("UserId", "RoleId");
b.HasIndex("RoleId");
b.ToTable("AspNetUserRoles");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.Property<string>("UserId");
b.Property<string>("LoginProvider")
.HasMaxLength(128);
b.Property<string>("Name")
.HasMaxLength(128);
b.Property<string>("Value");
b.HasKey("UserId", "LoginProvider", "Name");
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("CommandMode");
b.Property<string>("CommandResults");
b.Property<string>("CommandText");
b.Property<string>("OrganizationID");
b.Property<string>("PSCoreResults");
b.Property<string>("SenderConnectionID");
b.Property<string>("SenderUserID");
b.Property<string>("TargetDeviceIDs");
b.Property<DateTime>("TimeStamp");
b.HasKey("ID");
b.HasIndex("OrganizationID");
b.ToTable("CommandContexts");
});
modelBuilder.Entity("Remotely.Shared.Models.Device", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("CurrentUser");
b.Property<string>("DeviceName");
b.Property<string>("Drives");
b.Property<double>("FreeMemory");
b.Property<double>("FreeStorage");
b.Property<bool>("Is64Bit");
b.Property<bool>("IsOnline");
b.Property<DateTime>("LastOnline");
b.Property<int>("OSArchitecture");
b.Property<string>("OSDescription");
b.Property<string>("OrganizationID");
b.Property<string>("Platform");
b.Property<int>("ProcessorCount");
b.Property<string>("ServerVerificationToken");
b.Property<string>("Tags")
.HasMaxLength(200);
b.Property<double>("TotalMemory");
b.Property<double>("TotalStorage");
b.HasKey("ID");
b.HasIndex("OrganizationID");
b.ToTable("Devices");
});
modelBuilder.Entity("Remotely.Shared.Models.DevicePermissionLink", b =>
{
b.Property<string>("PermissionGroupID");
b.Property<string>("DeviceID");
b.HasKey("PermissionGroupID", "DeviceID");
b.HasIndex("DeviceID");
b.ToTable("DevicePermissionLinks");
});
modelBuilder.Entity("Remotely.Shared.Models.EventLog", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<int>("EventType");
b.Property<string>("Message");
b.Property<string>("OrganizationID");
b.Property<string>("Source");
b.Property<string>("StackTrace");
b.Property<DateTime>("TimeStamp");
b.HasKey("ID");
b.HasIndex("OrganizationID");
b.ToTable("EventLogs");
});
modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<DateTime>("DateSent");
b.Property<string>("InvitedUser");
b.Property<bool>("IsAdmin");
b.Property<string>("OrganizationID");
b.Property<string>("ResetUrl");
b.HasKey("ID");
b.HasIndex("OrganizationID");
b.ToTable("InviteLinks");
});
modelBuilder.Entity("Remotely.Shared.Models.Organization", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("OrganizationName")
.HasMaxLength(25);
b.HasKey("ID");
b.ToTable("Organizations");
});
modelBuilder.Entity("Remotely.Shared.Models.PermissionGroup", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("Name")
.HasMaxLength(100);
b.Property<string>("OrganizationID");
b.HasKey("ID");
b.HasIndex("OrganizationID");
b.ToTable("PermissionGroups");
});
modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
b.Property<string>("ContentType");
b.Property<byte[]>("FileContents");
b.Property<string>("FileName");
b.Property<string>("OrganizationID");
b.Property<DateTime>("Timestamp");
b.HasKey("ID");
b.HasIndex("OrganizationID");
b.ToTable("SharedFiles");
});
modelBuilder.Entity("Remotely.Shared.Models.UserPermissionLink", b =>
{
b.Property<string>("PermissionGroupID");
b.Property<string>("RemotelyUserID");
b.HasKey("PermissionGroupID", "RemotelyUserID");
b.HasIndex("RemotelyUserID");
b.ToTable("UserPermissionLinks");
});
modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b =>
{
b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser");
b.Property<bool>("IsAdministrator");
b.Property<string>("OrganizationID");
b.Property<string>("UserOptions");
b.HasIndex("OrganizationID");
b.ToTable("RemotelyUsers");
b.HasDiscriminator().HasValue("RemotelyUser");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole")
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<string>", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityUser")
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade);
});
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.Organization", "Organization")
.WithMany("Devices")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely.Shared.Models.DevicePermissionLink", b =>
{
b.HasOne("Remotely.Shared.Models.Device", "Device")
.WithMany("DevicePermissionLinks")
.HasForeignKey("DeviceID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Remotely.Shared.Models.PermissionGroup", "PermissionGroup")
.WithMany("DevicePermissionLinks")
.HasForeignKey("PermissionGroupID")
.OnDelete(DeleteBehavior.Cascade);
});
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.PermissionGroup", b =>
{
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("PermissionGroups")
.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.UserPermissionLink", b =>
{
b.HasOne("Remotely.Shared.Models.PermissionGroup", "PermissionGroup")
.WithMany("UserPermissionLinks")
.HasForeignKey("PermissionGroupID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Remotely.Shared.Models.RemotelyUser", "RemotelyUser")
.WithMany("UserPermissionLinks")
.HasForeignKey("RemotelyUserID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b =>
{
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("RemotelyUsers")
.HasForeignKey("OrganizationID");
});
#pragma warning restore 612, 618
}
}
}

View File

@ -0,0 +1,22 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Remotely.Server.Migrations
{
public partial class ResetUrl : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ResetUrl",
table: "InviteLinks",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ResetUrl",
table: "InviteLinks");
}
}
}

View File

@ -14,7 +14,7 @@ namespace Remotely.Server.Migrations
{
#pragma warning disable 612, 618
modelBuilder
.HasAnnotation("ProductVersion", "2.2.3-servicing-35854");
.HasAnnotation("ProductVersion", "2.2.4-servicing-10062");
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole", b =>
{
@ -182,7 +182,7 @@ namespace Remotely.Server.Migrations
b.ToTable("AspNetUserTokens");
});
modelBuilder.Entity("Remotely_Shared.Models.CommandContext", b =>
modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -212,7 +212,7 @@ namespace Remotely.Server.Migrations
b.ToTable("CommandContexts");
});
modelBuilder.Entity("Remotely_Shared.Models.Device", b =>
modelBuilder.Entity("Remotely.Shared.Models.Device", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -259,7 +259,7 @@ namespace Remotely.Server.Migrations
b.ToTable("Devices");
});
modelBuilder.Entity("Remotely_Shared.Models.DevicePermissionLink", b =>
modelBuilder.Entity("Remotely.Shared.Models.DevicePermissionLink", b =>
{
b.Property<string>("PermissionGroupID");
@ -272,7 +272,7 @@ namespace Remotely.Server.Migrations
b.ToTable("DevicePermissionLinks");
});
modelBuilder.Entity("Remotely_Shared.Models.EventLog", b =>
modelBuilder.Entity("Remotely.Shared.Models.EventLog", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -296,7 +296,7 @@ namespace Remotely.Server.Migrations
b.ToTable("EventLogs");
});
modelBuilder.Entity("Remotely_Shared.Models.InviteLink", b =>
modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -309,6 +309,8 @@ namespace Remotely.Server.Migrations
b.Property<string>("OrganizationID");
b.Property<string>("ResetUrl");
b.HasKey("ID");
b.HasIndex("OrganizationID");
@ -316,7 +318,7 @@ namespace Remotely.Server.Migrations
b.ToTable("InviteLinks");
});
modelBuilder.Entity("Remotely_Shared.Models.Organization", b =>
modelBuilder.Entity("Remotely.Shared.Models.Organization", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -329,7 +331,7 @@ namespace Remotely.Server.Migrations
b.ToTable("Organizations");
});
modelBuilder.Entity("Remotely_Shared.Models.PermissionGroup", b =>
modelBuilder.Entity("Remotely.Shared.Models.PermissionGroup", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -346,7 +348,7 @@ namespace Remotely.Server.Migrations
b.ToTable("PermissionGroups");
});
modelBuilder.Entity("Remotely_Shared.Models.SharedFile", b =>
modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b =>
{
b.Property<string>("ID")
.ValueGeneratedOnAdd();
@ -368,7 +370,7 @@ namespace Remotely.Server.Migrations
b.ToTable("SharedFiles");
});
modelBuilder.Entity("Remotely_Shared.Models.UserPermissionLink", b =>
modelBuilder.Entity("Remotely.Shared.Models.UserPermissionLink", b =>
{
b.Property<string>("PermissionGroupID");
@ -381,7 +383,7 @@ namespace Remotely.Server.Migrations
b.ToTable("UserPermissionLinks");
});
modelBuilder.Entity("Remotely_Shared.Models.RemotelyUser", b =>
modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b =>
{
b.HasBaseType("Microsoft.AspNetCore.Identity.IdentityUser");
@ -443,77 +445,77 @@ namespace Remotely.Server.Migrations
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Remotely_Shared.Models.CommandContext", b =>
modelBuilder.Entity("Remotely.Shared.Models.CommandContext", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("CommandContexts")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely_Shared.Models.Device", b =>
modelBuilder.Entity("Remotely.Shared.Models.Device", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("Devices")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely_Shared.Models.DevicePermissionLink", b =>
modelBuilder.Entity("Remotely.Shared.Models.DevicePermissionLink", b =>
{
b.HasOne("Remotely_Shared.Models.Device", "Device")
b.HasOne("Remotely.Shared.Models.Device", "Device")
.WithMany("DevicePermissionLinks")
.HasForeignKey("DeviceID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Remotely_Shared.Models.PermissionGroup", "PermissionGroup")
b.HasOne("Remotely.Shared.Models.PermissionGroup", "PermissionGroup")
.WithMany("DevicePermissionLinks")
.HasForeignKey("PermissionGroupID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Remotely_Shared.Models.EventLog", b =>
modelBuilder.Entity("Remotely.Shared.Models.EventLog", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("EventLogs")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely_Shared.Models.InviteLink", b =>
modelBuilder.Entity("Remotely.Shared.Models.InviteLink", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("InviteLinks")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely_Shared.Models.PermissionGroup", b =>
modelBuilder.Entity("Remotely.Shared.Models.PermissionGroup", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("PermissionGroups")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely_Shared.Models.SharedFile", b =>
modelBuilder.Entity("Remotely.Shared.Models.SharedFile", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("SharedFiles")
.HasForeignKey("OrganizationID");
});
modelBuilder.Entity("Remotely_Shared.Models.UserPermissionLink", b =>
modelBuilder.Entity("Remotely.Shared.Models.UserPermissionLink", b =>
{
b.HasOne("Remotely_Shared.Models.PermissionGroup", "PermissionGroup")
b.HasOne("Remotely.Shared.Models.PermissionGroup", "PermissionGroup")
.WithMany("UserPermissionLinks")
.HasForeignKey("PermissionGroupID")
.OnDelete(DeleteBehavior.Cascade);
b.HasOne("Remotely_Shared.Models.RemotelyUser", "RemotelyUser")
b.HasOne("Remotely.Shared.Models.RemotelyUser", "RemotelyUser")
.WithMany("UserPermissionLinks")
.HasForeignKey("RemotelyUserID")
.OnDelete(DeleteBehavior.Cascade);
});
modelBuilder.Entity("Remotely_Shared.Models.RemotelyUser", b =>
modelBuilder.Entity("Remotely.Shared.Models.RemotelyUser", b =>
{
b.HasOne("Remotely_Shared.Models.Organization", "Organization")
b.HasOne("Remotely.Shared.Models.Organization", "Organization")
.WithMany("RemotelyUsers")
.HasForeignKey("OrganizationID");
});

View File

@ -9,7 +9,7 @@
@if (showBanner)
{
<div id="cookieConsent" class="alert alert-info alert-dismissible fade show" role="alert">
This site only uses cookies that are necessary for security and login. <a asp-page="/Privacy">Learn More</a>.
This site only uses cookies for security and login. <a asp-page="/Privacy">Learn More</a>.
<button type="button" class="accept-policy close" data-dismiss="alert" aria-label="Close" data-cookie-string="@cookieString">
<span aria-hidden="true">Accept</span>
</button>

View File

@ -229,10 +229,17 @@ document.getElementById("sendInviteButton").addEventListener("click", (ev) => {
var tbody = document.querySelector("#invitesTable tbody");
var newRow = document.createElement("tr");
newRow.setAttribute("invite", newInvite.ID);
newRow.innerHTML = `<td class="middle-aligned"><label class="control-label">${newInvite.InvitedUser}</label></td>
var innerHtml = `<td class="middle-aligned"><label class="control-label">${newInvite.InvitedUser}</label></td>
<td class="middle-aligned text-center"><input type="checkbox" disabled ${newInvite.IsAdmin ? "checked" : ""}/></td>
<td class="middle-aligned"><label class="control-label">${location.origin}/Invite/?id=${newInvite.ID}</label></td>
<td class="middle-aligned">
<label class="control-label">
<a href="${location.origin}/Invite/?id=${newInvite.ID}">Join Link</a>`;
if (newInvite.ResetUrl) {
innerHtml += `<br /> <a href="${newInvite.ResetUrl}">Reset Password</a>`;
}
innerHtml += ` </label> </td>
<td><button type="button" class="btn btn-danger delete-invite-button" invite="${newInvite.ID}">Delete</button></td>`;
newRow.innerHTML = innerHtml;
tbody.appendChild(newRow);
newRow.querySelector(".delete-invite-button").addEventListener("click", (ev) => {
deleteInvite(ev);

File diff suppressed because one or more lines are too long

View File

@ -239,10 +239,18 @@ document.getElementById("sendInviteButton").addEventListener("click", (ev) => {
var tbody = document.querySelector("#invitesTable tbody");
var newRow = document.createElement("tr");
newRow.setAttribute("invite", newInvite.ID);
newRow.innerHTML = `<td class="middle-aligned"><label class="control-label">${newInvite.InvitedUser}</label></td>
var innerHtml = `<td class="middle-aligned"><label class="control-label">${newInvite.InvitedUser}</label></td>
<td class="middle-aligned text-center"><input type="checkbox" disabled ${newInvite.IsAdmin ? "checked" : ""}/></td>
<td class="middle-aligned"><label class="control-label">${location.origin}/Invite/?id=${newInvite.ID}</label></td>
<td class="middle-aligned">
<label class="control-label">
<a href="${location.origin}/Invite/?id=${newInvite.ID}">Join Link</a>`;
if (newInvite.ResetUrl) {
innerHtml += `<br /> <a href="${newInvite.ResetUrl}">Reset Password</a>`;
}
innerHtml += ` </label> </td>
<td><button type="button" class="btn btn-danger delete-invite-button" invite="${newInvite.ID}">Delete</button></td>`;
newRow.innerHTML = innerHtml;
tbody.appendChild(newRow);
newRow.querySelector(".delete-invite-button").addEventListener("click", (ev:MouseEvent) => {
deleteInvite(ev);

View File

@ -13,5 +13,6 @@ namespace Remotely.Shared.Models
public bool IsAdmin { get; set; }
public DateTime DateSent { get; set; }
public virtual Organization Organization { get; set; }
public string ResetUrl { get; set; }
}
}

View File

@ -24,5 +24,6 @@ namespace Remotely.Shared.ViewModels
public bool IsAdmin { get; set; }
public DateTime DateSent { get; set; }
public string InvitedUser { get; set; }
public string ResetUrl { get; set; }
}
}