Create AlertsController and DataService methods.

This commit is contained in:
Jared Goodwin 2020-03-24 07:49:13 -07:00
parent bbfceeeb6b
commit 68a0cc0d7e
6 changed files with 217 additions and 103 deletions

View File

@ -1,9 +1,15 @@
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Remotely.Server.Auth;
using Remotely.Server.Services;
using Remotely.Shared.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
namespace Remotely.Server.API
@ -13,27 +19,103 @@ namespace Remotely.Server.API
[ServiceFilter(typeof(ApiAuthorizationFilter))]
public class AlertsController : ControllerBase
{
public AlertsController(DataService dataService, IEmailSenderEx emailSender)
{
DataService = dataService;
EmailSender = emailSender;
}
private DataService DataService { get; }
private IEmailSenderEx EmailSender { get; }
[HttpPost("Create")]
[ServiceFilter(typeof(ApiAuthorizationFilter))]
public async Task<IActionResult> Create(AlertOptions alertOptions)
{
Request.Headers.TryGetValue("OrganizationID", out var orgID);
DataService.WriteEvent("Alert created. Alert Options: " + JsonSerializer.Serialize(alertOptions), orgID);
if (alertOptions.ShouldAlert)
{
var alert = new Alert()
try
{
CreatedOn = DateTimeOffset.Now,
DeviceID = alertOptions.AlertDeviceID,
Message = alertOptions.AlertMessage
};
// TODO: Add alert.
var alert = new Alert()
{
CreatedOn = DateTimeOffset.Now,
DeviceID = alertOptions.AlertDeviceID,
Message = alertOptions.AlertMessage,
OrganizationID = orgID
};
await DataService.AddAlert(alert);
}
catch (Exception ex)
{
DataService.WriteEvent(ex, orgID);
}
}
// TODO: Email.
if (alertOptions.ShouldEmail)
{
try
{
await EmailSender.SendEmailAsync(alertOptions.EmailTo,
alertOptions.EmailSubject,
alertOptions.EmailBody,
orgID);
}
catch (Exception ex)
{
DataService.WriteEvent(ex, orgID);
}
}
// TODO: API request.
if (alertOptions.ShouldSendApiRequest)
{
try
{
var httpRequest = WebRequest.CreateHttp(alertOptions.ApiRequestUrl);
httpRequest.Method = alertOptions.ApiRequestMethod;
httpRequest.ContentType = "application/json";
foreach (var header in alertOptions.ApiRequestHeaders)
{
httpRequest.Headers.Add(header.Key, header.Value);
}
using (var rs = httpRequest.GetRequestStream())
using (var sw = new StreamWriter(rs))
{
sw.Write(alertOptions.ApiRequestBody);
}
var response = (HttpWebResponse)httpRequest.GetResponse();
DataService.WriteEvent($"Alert API Response Status: {response.StatusCode}.", orgID);
}
catch (Exception ex)
{
DataService.WriteEvent(ex, orgID);
}
}
return Ok();
}
[HttpPost("Delete/{alertID}")]
[ServiceFilter(typeof(ApiAuthorizationFilter))]
public async Task<IActionResult> Delete(string alertID)
{
Request.Headers.TryGetValue("OrganizationID", out var orgID);
var alert = await DataService.GetAlert(alertID);
if (alert?.OrganizationID == orgID)
{
await DataService.DeleteAlert(alert);
return Ok();
}
return Unauthorized();
}
}
}

View File

@ -18,6 +18,8 @@ namespace Remotely.Server.Data
{
}
public DbSet<Alert> Alerts { get; set; }
public DbSet<ApiToken> ApiTokens { get; set; }
public DbSet<CommandResult> CommandResults { get; set; }
@ -74,6 +76,9 @@ namespace Remotely.Server.Data
builder.Entity<Organization>()
.HasMany(x => x.ApiTokens)
.WithOne(x => x.Organization);
builder.Entity<Organization>()
.HasMany(x => x.Alerts)
.WithOne(x => x.Organization);
builder.Entity<CommandResult>()
@ -122,6 +127,9 @@ namespace Remotely.Server.Data
builder.Entity<Device>()
.HasIndex(x => x.DeviceName);
builder.Entity<Device>()
.HasMany(x => x.Alerts)
.WithOne(x => x.Device);
builder.Entity<ApiToken>()
.HasIndex(x => x.Token);

View File

@ -34,6 +34,12 @@ namespace Remotely.Server.Services
private ApplicationDbContext RemotelyContext { get; }
private UserManager<RemotelyUser> UserManager { get; }
public async Task AddAlert(Alert alert)
{
RemotelyContext.Alerts.Add(alert);
await RemotelyContext.SaveChangesAsync();
}
public bool AddDeviceGroup(string orgID, DeviceGroup deviceGroup, out string deviceGroupID, out string errorMessage)
{
deviceGroupID = null;
@ -64,12 +70,9 @@ namespace Remotely.Server.Services
return true;
}
public List<string> GetServerAdmins()
public async Task<Alert> GetAlert(string alertID)
{
return RemotelyContext.Users
.Where(x => x.IsServerAdmin)
.Select(x => x.UserName)
.ToList();
return await RemotelyContext.Alerts.FirstOrDefaultAsync(x => x.ID == alertID);
}
public InviteLink AddInvite(string orgID, Invite invite)
@ -109,7 +112,6 @@ namespace Remotely.Server.Services
RemotelyContext.SaveChanges();
}
public bool AddOrUpdateDevice(Device device, out Device updatedDevice)
{
var existingDevice = RemotelyContext.Devices.Find(device.ID);
@ -161,31 +163,6 @@ namespace Remotely.Server.Services
return true;
}
public async Task UpdateServerAdmins(List<string> serverAdmins, string callerUserName)
{
var currentAdmins = RemotelyContext.Users.Where(x => x.IsServerAdmin).ToList();
var removeAdmins = currentAdmins.Where(currentAdmin =>
!serverAdmins.Contains(currentAdmin.UserName.Trim().ToLower()) &&
currentAdmin.UserName.Trim().ToLower() != callerUserName.Trim().ToLower());
foreach (var removeAdmin in removeAdmins)
{
removeAdmin.IsServerAdmin = false;
}
var newAdmins = RemotelyContext.Users.Where(user =>
serverAdmins.Contains(user.UserName.Trim().ToLower()) &&
!user.IsServerAdmin);
foreach (var newAdmin in newAdmins)
{
newAdmin.IsServerAdmin = true;
}
await RemotelyContext.SaveChangesAsync();
}
public string AddSharedFile(IFormFile file, string organizationID)
{
var expirationDate = DateTimeOffset.Now.AddDays(-AppConfig.DataRetentionInDays);
@ -212,6 +189,60 @@ namespace Remotely.Server.Services
return newEntity.Entity.ID;
}
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<UserDevicePermission>();
user.PermissionLinks = user.PermissionLinks ?? new List<UserDevicePermission>();
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 void ChangeUserIsAdmin(string organizationID, string targetUserID, bool isAdmin)
{
var targetUser = RemotelyContext.Users.FirstOrDefault(x =>
@ -267,7 +298,6 @@ namespace Remotely.Server.Services
return newToken;
}
public async Task<bool> CreateUser(string userEmail, bool isAdmin, string organizationID)
{
try
@ -280,8 +310,8 @@ namespace Remotely.Server.Services
OrganizationID = organizationID
};
var org = RemotelyContext.Organizations
.Include(x=>x.RemotelyUsers)
.FirstOrDefault(x=>x.ID == organizationID);
.Include(x => x.RemotelyUsers)
.FirstOrDefault(x => x.ID == organizationID);
org.RemotelyUsers.Add(user);
await RemotelyContext.SaveChangesAsync();
return true;
@ -294,6 +324,11 @@ namespace Remotely.Server.Services
}
public async Task DeleteAlert(Alert alert)
{
RemotelyContext.Alerts.Remove(alert);
await RemotelyContext.SaveChangesAsync();
}
public async Task DeleteApiToken(string userName, string tokenId)
{
@ -401,7 +436,7 @@ namespace Remotely.Server.Services
return RemotelyContext.Devices
.Include(x => x.DeviceGroup)
.ThenInclude(x => x.PermissionLinks)
.Where(device =>
.Where(device =>
device.OrganizationID == remotelyUser.OrganizationID &&
deviceIDs.Contains(device.ID) &&
(
@ -437,7 +472,6 @@ namespace Remotely.Server.Services
.ToArray();
}
public IEnumerable<ApiToken> GetAllApiTokens(string userID)
{
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);
@ -540,12 +574,12 @@ namespace Remotely.Server.Services
return RemotelyContext.DeviceGroups
.Include(x => x.PermissionLinks)
.ThenInclude(x => x.User)
.Where(x =>
x.OrganizationID == user.OrganizationID &&
.Where(x =>
x.OrganizationID == user.OrganizationID &&
(
user.IsAdministrator ||
x.PermissionLinks.Count == 0 ||
x.PermissionLinks.Any(x=>x.UserID == user.Id)
x.PermissionLinks.Any(x => x.UserID == user.Id)
)
) ?? Enumerable.Empty<DeviceGroup>();
}
@ -558,7 +592,7 @@ namespace Remotely.Server.Services
return RemotelyContext.Devices
.Include(x => x.DeviceGroup)
.ThenInclude(x => x.PermissionLinks)
.Where(x =>
.Where(x =>
x.OrganizationID == user.OrganizationID &&
(
user.IsAdministrator ||
@ -599,6 +633,14 @@ namespace Remotely.Server.Services
{
return RemotelyContext.Organizations.FirstOrDefault(x => x.ID == organizationID)?.OrganizationName;
}
public List<string> GetServerAdmins()
{
return RemotelyContext.Users
.Where(x => x.IsServerAdmin)
.Select(x => x.UserName)
.ToList();
}
public SharedFile GetSharedFiled(string fileID)
{
return RemotelyContext.SharedFiles.Find(fileID);
@ -692,60 +734,6 @@ namespace Remotely.Server.Services
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<UserDevicePermission>();
user.PermissionLinks = user.PermissionLinks ?? new List<UserDevicePermission>();
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
@ -845,6 +833,30 @@ namespace Remotely.Server.Services
RemotelyContext.SaveChanges();
}
public async Task UpdateServerAdmins(List<string> serverAdmins, string callerUserName)
{
var currentAdmins = RemotelyContext.Users.Where(x => x.IsServerAdmin).ToList();
var removeAdmins = currentAdmins.Where(currentAdmin =>
!serverAdmins.Contains(currentAdmin.UserName.Trim().ToLower()) &&
currentAdmin.UserName.Trim().ToLower() != callerUserName.Trim().ToLower());
foreach (var removeAdmin in removeAdmins)
{
removeAdmin.IsServerAdmin = false;
}
var newAdmins = RemotelyContext.Users.Where(user =>
serverAdmins.Contains(user.UserName.Trim().ToLower()) &&
!user.IsServerAdmin);
foreach (var newAdmin in newAdmins)
{
newAdmin.IsServerAdmin = true;
}
await RemotelyContext.SaveChangesAsync();
}
public void UpdateTags(string deviceID, string tags)
{
var device = RemotelyContext.Devices.Find(deviceID);

View File

@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Text;
using System.Text.Json.Serialization;
namespace Remotely.Shared.Models
{
@ -10,9 +11,17 @@ namespace Remotely.Shared.Models
[Key]
public string ID { get; set; } = Guid.NewGuid().ToString();
public DateTimeOffset CreatedOn { get; set; } = DateTimeOffset.Now;
[JsonIgnore]
public Device Device { get; set; }
public string DeviceID { get; set; }
public string Message { get; set; }
[JsonIgnore]
public Organization Organization { get; set; }
public string OrganizationID { get; set; }
public ICollection<RemotelyUser> SeenBy { get; set; }
}
}

View File

@ -15,6 +15,7 @@ namespace Remotely.Shared.Models
public class Device
{
public string AgentVersion { get; set; }
public ICollection<Alert> Alerts { get; set; }
[StringLength(100)]
public string Alias { get; set; }
public double CpuUtilization { get; set; }

View File

@ -7,6 +7,8 @@ namespace Remotely.Shared.Models
{
public class Organization
{
public ICollection<Alert> Alerts { get; set; }
public ICollection<ApiToken> ApiTokens { get; set; }
public ICollection<CommandResult> CommandResults { get; set; }