mirror of
https://github.com/immense/Remotely.git
synced 2025-10-26 11:27:15 +00:00
2124 lines
72 KiB
C#
2124 lines
72 KiB
C#
using Microsoft.AspNetCore.Components.Forms;
|
|
using Microsoft.AspNetCore.Http;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Primitives;
|
|
using Remotely.Server.Data;
|
|
using Remotely.Server.Models;
|
|
using Remotely.Shared.Enums;
|
|
using Remotely.Shared.Models;
|
|
using Remotely.Shared.Utilities;
|
|
using Remotely.Shared.ViewModels;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace Remotely.Server.Services
|
|
{
|
|
// TODO: Separate this into domain-specific services.
|
|
public interface IDataService
|
|
{
|
|
Task AddAlert(string deviceID, string organizationID, string alertMessage, string details = null);
|
|
bool AddDeviceGroup(string orgID, DeviceGroup deviceGroup, out string deviceGroupID, out string errorMessage);
|
|
|
|
InviteLink AddInvite(string orgID, InviteViewModel invite);
|
|
|
|
bool AddOrUpdateDevice(Device device, out Device updatedDevice);
|
|
|
|
Task AddOrUpdateSavedScript(SavedScript script, string userId);
|
|
|
|
void AddOrUpdateScriptResult(ScriptResult scriptResult);
|
|
|
|
Task AddOrUpdateScriptSchedule(ScriptSchedule schedule);
|
|
|
|
Task AddScriptRun(ScriptRun scriptRun);
|
|
|
|
Task<string> AddSharedFile(IBrowserFile file, string organizationID, Action<double, string> progressCallback);
|
|
|
|
Task<string> AddSharedFile(IFormFile file, string organizationID);
|
|
|
|
bool AddUserToDeviceGroup(string orgID, string groupID, string userName, out string resultMessage);
|
|
|
|
void ChangeUserIsAdmin(string organizationID, string targetUserID, bool isAdmin);
|
|
|
|
void CleanupOldRecords();
|
|
|
|
Task ClearLogs(string currentUserName);
|
|
Task<ApiToken> CreateApiToken(string userName, string tokenName, string secretHash);
|
|
|
|
Task<Device> CreateDevice(DeviceSetupOptions options);
|
|
|
|
Task<bool> CreateUser(string userEmail, bool isAdmin, string organizationID);
|
|
|
|
Task DeleteAlert(Alert alert);
|
|
|
|
Task DeleteAllAlerts(string orgID, string userName = null);
|
|
|
|
Task DeleteApiToken(string userName, string tokenId);
|
|
|
|
void DeleteDeviceGroup(string orgID, string deviceGroupID);
|
|
|
|
void DeleteInvite(string orgID, string inviteID);
|
|
|
|
Task DeleteSavedScript(Guid scriptId);
|
|
|
|
Task DeleteScriptSchedule(int scriptScheduleId);
|
|
|
|
Task DeleteUser(string orgID, string targetUserID);
|
|
|
|
void DetachEntity(object entity);
|
|
|
|
void DeviceDisconnected(string deviceID);
|
|
|
|
bool DoesUserExist(string userName);
|
|
|
|
bool DoesUserHaveAccessToDevice(string deviceID, RemotelyUser remotelyUser);
|
|
|
|
bool DoesUserHaveAccessToDevice(string deviceID, string remotelyUserID);
|
|
Task<DeviceGroup> GetDeviceGroup(string deviceGroupID);
|
|
string[] FilterDeviceIDsByUserPermission(string[] deviceIDs, RemotelyUser remotelyUser);
|
|
Task AddScriptResultToScriptRun(string scriptResultId, int scriptRunId);
|
|
string[] FilterUsersByDevicePermission(IEnumerable<string> userIDs, string deviceID);
|
|
|
|
Task<Alert> GetAlert(string alertID);
|
|
|
|
Alert[] GetAlerts(string userID);
|
|
|
|
ApiToken[] GetAllApiTokens(string userID);
|
|
|
|
ScriptResult[] GetAllCommandResults(string orgID);
|
|
|
|
ScriptResult[] GetAllCommandResultsForUser(string orgId, string userName, string deviceId);
|
|
|
|
Device[] GetAllDevices(string orgID);
|
|
|
|
EventLog[] GetAllEventLogs(string orgID);
|
|
|
|
InviteLink[] GetAllInviteLinks(string organizationId);
|
|
|
|
ScriptResult[] GetAllScriptResults(string orgId, string deviceId);
|
|
|
|
ScriptResult[] GetAllScriptResultsForUser(string orgId, string userName);
|
|
|
|
RemotelyUser[] GetAllUsersForServer();
|
|
|
|
Task<RemotelyUser[]> GetAllUsersInOrganization(string orgId);
|
|
|
|
ApiToken GetApiKey(string keyId);
|
|
|
|
Task<BrandingInfo> GetBrandingInfo(string organizationId);
|
|
|
|
Task<Organization> GetDefaultOrganization();
|
|
|
|
Task<string> GetDefaultRelayCode();
|
|
|
|
Device GetDevice(string deviceID);
|
|
|
|
Device GetDevice(string orgID, string deviceID);
|
|
|
|
int GetDeviceCount();
|
|
|
|
int GetDeviceCount(RemotelyUser user);
|
|
|
|
DeviceGroup[] GetDeviceGroups(string username);
|
|
|
|
DeviceGroup[] GetDeviceGroupsForOrganization(string organizationId);
|
|
|
|
List<Device> GetDevices(IEnumerable<string> deviceIds);
|
|
|
|
Device[] GetDevicesForUser(string userName);
|
|
|
|
EventLog[] GetEventLogs(string userName, DateTimeOffset from, DateTimeOffset to, EventType? type, string message);
|
|
|
|
Organization GetOrganizationById(string organizationID);
|
|
|
|
Task<Organization> GetOrganizationByRelayCode(string relayCode);
|
|
|
|
Task<Organization> GetOrganizationByUserName(string userName);
|
|
|
|
int GetOrganizationCount();
|
|
|
|
string GetOrganizationNameById(string organizationID);
|
|
|
|
string GetOrganizationNameByUserName(string userName);
|
|
|
|
Task<List<ScriptRun>> GetPendingScriptRuns(string deviceId);
|
|
|
|
Task<List<SavedScript>> GetQuickScripts(string userId);
|
|
|
|
Task<SavedScript> GetSavedScript(Guid scriptId);
|
|
|
|
Task<SavedScript> GetSavedScript(string userId, Guid scriptId);
|
|
|
|
Task<List<SavedScript>> GetSavedScriptsWithoutContent(string userId, string organizationId);
|
|
|
|
ScriptResult GetScriptResult(string scriptResultId);
|
|
|
|
ScriptResult GetScriptResult(string scriptResultId, string orgID);
|
|
|
|
Task<List<ScriptSchedule>> GetScriptSchedules(string organizationID);
|
|
|
|
Task<List<ScriptSchedule>> GetScriptSchedulesDue();
|
|
List<string> GetServerAdmins();
|
|
|
|
SharedFile GetSharedFiled(string fileID);
|
|
|
|
int GetTotalDevices();
|
|
|
|
Task<RemotelyUser> GetUserAsync(string username);
|
|
|
|
RemotelyUser GetUserByID(string userID);
|
|
|
|
RemotelyUser GetUserByNameWithOrg(string userName);
|
|
|
|
RemotelyUserOptions GetUserOptions(string userName);
|
|
|
|
bool JoinViaInvitation(string userName, string inviteID);
|
|
|
|
void PopulateRelayCodes();
|
|
|
|
void RemoveDevices(string[] deviceIDs);
|
|
|
|
Task<bool> RemoveUserFromDeviceGroup(string orgID, string groupID, string userID);
|
|
Task RenameApiToken(string userName, string tokenId, string tokenName);
|
|
|
|
void SetAllDevicesNotOnline();
|
|
|
|
Task SetDisplayName(RemotelyUser user, string displayName);
|
|
|
|
Task SetIsDefaultOrganization(string orgID, bool isDefault);
|
|
|
|
Task SetIsServerAdmin(string targetUserId, bool isServerAdmin, string callerUserId);
|
|
|
|
void SetServerVerificationToken(string deviceID, string verificationToken);
|
|
|
|
Task<bool> TempPasswordSignIn(string email, string password);
|
|
|
|
Task UpdateBrandingInfo(
|
|
string organizationId,
|
|
string productName,
|
|
byte[] iconBytes,
|
|
ColorPickerModel titleForeground,
|
|
ColorPickerModel titleBackground,
|
|
ColorPickerModel titleButtonForeground);
|
|
Task<Device> UpdateDevice(DeviceSetupOptions deviceOptions, string organizationId);
|
|
void UpdateDevice(string deviceID, string tag, string alias, string deviceGroupID, string notes, WebRtcSetting webRtcSetting);
|
|
void UpdateOrganizationName(string orgID, string organizationName);
|
|
void UpdateTags(string deviceID, string tags);
|
|
void UpdateUserOptions(string userName, RemotelyUserOptions options);
|
|
bool ValidateApiKey(string keyId, string apiSecret, string requestPath, string remoteIP);
|
|
void WriteEvent(EventLog eventLog);
|
|
void WriteEvent(Exception ex, string organizationID);
|
|
void WriteEvent(string message, EventType eventType, string organizationID);
|
|
void WriteEvent(string message, string organizationID);
|
|
void WriteLog(LogLevel logLevel, string category, EventId eventId, string state, Exception exception, string[] scopeStack);
|
|
}
|
|
|
|
public class DataService : IDataService
|
|
{
|
|
private readonly IApplicationConfig _appConfig;
|
|
|
|
private readonly IDbContextFactory<AppDb> _dbFactory;
|
|
private readonly IHostEnvironment _hostEnvironment;
|
|
|
|
public DataService(IDbContextFactory<AppDb> dbFactory,
|
|
IApplicationConfig appConfig,
|
|
IHostEnvironment hostEnvironment)
|
|
{
|
|
_dbFactory = dbFactory;
|
|
_appConfig = appConfig;
|
|
_hostEnvironment = hostEnvironment;
|
|
}
|
|
|
|
public async Task AddAlert(string deviceId, string organizationID, string alertMessage, string details = null)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var users = dbContext.Users
|
|
.Include(x => x.Alerts)
|
|
.Where(x => x.OrganizationID == organizationID);
|
|
|
|
if (!string.IsNullOrWhiteSpace(deviceId))
|
|
{
|
|
var filteredUserIDs = FilterUsersByDevicePermissionInternal(
|
|
dbContext,
|
|
users.Select(x => x.Id),
|
|
deviceId);
|
|
|
|
users = users.Where(x => filteredUserIDs.Contains(x.Id));
|
|
}
|
|
|
|
await users.ForEachAsync(x =>
|
|
{
|
|
var alert = new Alert()
|
|
{
|
|
CreatedOn = DateTimeOffset.Now,
|
|
DeviceID = deviceId,
|
|
Message = alertMessage,
|
|
OrganizationID = organizationID,
|
|
Details = details
|
|
};
|
|
x.Alerts.Add(alert);
|
|
});
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public bool AddDeviceGroup(string orgID, DeviceGroup deviceGroup, out string deviceGroupID, out string errorMessage)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
deviceGroupID = null;
|
|
errorMessage = null;
|
|
|
|
var organization = dbContext.Organizations
|
|
.Include(x => x.DeviceGroups)
|
|
.FirstOrDefault(x => x.ID == orgID);
|
|
|
|
if (dbContext.DeviceGroups.Any(x =>
|
|
x.OrganizationID == orgID &&
|
|
x.Name.ToLower() == deviceGroup.Name.ToLower()))
|
|
{
|
|
errorMessage = "Device group already exists.";
|
|
return false;
|
|
}
|
|
|
|
dbContext.Attach(deviceGroup);
|
|
deviceGroup.Organization = organization;
|
|
deviceGroup.OrganizationID = orgID;
|
|
|
|
organization.DeviceGroups.Add(deviceGroup);
|
|
dbContext.SaveChanges();
|
|
deviceGroupID = deviceGroup.ID;
|
|
return true;
|
|
}
|
|
|
|
public InviteLink AddInvite(string orgID, InviteViewModel invite)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var organization = dbContext.Organizations
|
|
.Include(x => x.InviteLinks)
|
|
.FirstOrDefault(x => x.ID == orgID);
|
|
|
|
var inviteLink = new InviteLink()
|
|
{
|
|
InvitedUser = invite.InvitedUser.ToLower(),
|
|
DateSent = DateTimeOffset.Now,
|
|
IsAdmin = invite.IsAdmin,
|
|
Organization = organization,
|
|
OrganizationID = organization.ID,
|
|
};
|
|
|
|
organization.InviteLinks.Add(inviteLink);
|
|
dbContext.SaveChanges();
|
|
return inviteLink;
|
|
}
|
|
|
|
public bool AddOrUpdateDevice(Device device, out Device updatedDevice)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var existingDevice = dbContext.Devices.Find(device.ID);
|
|
if (existingDevice != null)
|
|
{
|
|
existingDevice.CurrentUser = device.CurrentUser;
|
|
existingDevice.DeviceName = device.DeviceName;
|
|
existingDevice.Drives = device.Drives;
|
|
existingDevice.CpuUtilization = device.CpuUtilization;
|
|
existingDevice.UsedMemory = device.UsedMemory;
|
|
existingDevice.UsedStorage = device.UsedStorage;
|
|
existingDevice.Is64Bit = device.Is64Bit;
|
|
existingDevice.IsOnline = true;
|
|
existingDevice.OSArchitecture = device.OSArchitecture;
|
|
existingDevice.OSDescription = device.OSDescription;
|
|
existingDevice.Platform = device.Platform;
|
|
existingDevice.ProcessorCount = device.ProcessorCount;
|
|
existingDevice.PublicIP = device.PublicIP;
|
|
existingDevice.TotalMemory = device.TotalMemory;
|
|
existingDevice.TotalStorage = device.TotalStorage;
|
|
existingDevice.AgentVersion = device.AgentVersion;
|
|
existingDevice.LastOnline = DateTimeOffset.Now;
|
|
updatedDevice = existingDevice;
|
|
}
|
|
else
|
|
{
|
|
device.LastOnline = DateTimeOffset.Now;
|
|
if (_hostEnvironment.IsDevelopment() && dbContext.Organizations.Any())
|
|
{
|
|
var org = dbContext.Organizations.FirstOrDefault();
|
|
device.Organization = org;
|
|
device.OrganizationID = org?.ID;
|
|
}
|
|
|
|
updatedDevice = device;
|
|
|
|
if (!dbContext.Organizations.Any(x => x.ID == device.OrganizationID))
|
|
{
|
|
WriteEvent(new EventLog()
|
|
{
|
|
EventType = EventType.Info,
|
|
Message = $"Unable to add device {device.DeviceName} because organization {device.OrganizationID}" +
|
|
$"does not exist. Device ID: {device.ID}.",
|
|
Source = "DataService.AddOrUpdateDevice"
|
|
});
|
|
return false;
|
|
}
|
|
dbContext.Devices.Add(device);
|
|
}
|
|
dbContext.SaveChanges();
|
|
return true;
|
|
}
|
|
|
|
public async Task AddOrUpdateSavedScript(SavedScript script, string userId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.SavedScripts.Update(script);
|
|
script.CreatorId = userId;
|
|
script.Creator = dbContext.Users.Find(userId);
|
|
script.OrganizationID = script.Creator.OrganizationID;
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public void AddOrUpdateScriptResult(ScriptResult result)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var device = dbContext.Devices.Find(result.DeviceID);
|
|
|
|
if (device is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
result.OrganizationID = device.OrganizationID;
|
|
|
|
var existingResult = dbContext.ScriptResults.Find(result.ID);
|
|
if (existingResult is not null)
|
|
{
|
|
var entry = dbContext.Entry(existingResult);
|
|
entry.CurrentValues.SetValues(result);
|
|
entry.State = EntityState.Modified;
|
|
}
|
|
else
|
|
{
|
|
dbContext.ScriptResults.Add(result);
|
|
}
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public async Task AddOrUpdateScriptSchedule(ScriptSchedule schedule)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var existingSchedule = await dbContext.ScriptSchedules
|
|
.Include(x => x.Creator)
|
|
.Include(x => x.Devices)
|
|
.Include(x => x.DeviceGroups)
|
|
.FirstOrDefaultAsync(x => x.Id == schedule.Id);
|
|
|
|
if (existingSchedule is null)
|
|
{
|
|
dbContext.Update(schedule);
|
|
}
|
|
else
|
|
{
|
|
var entry = dbContext.Entry(existingSchedule);
|
|
entry.CurrentValues.SetValues(schedule);
|
|
|
|
existingSchedule.Devices.Clear();
|
|
if (schedule.Devices?.Any() == true)
|
|
{
|
|
var deviceIds = schedule.Devices.Select(x => x.ID);
|
|
var newDevices = await dbContext.Devices
|
|
.Where(x => deviceIds.Contains(x.ID))
|
|
.ToListAsync();
|
|
existingSchedule.Devices.AddRange(newDevices);
|
|
}
|
|
|
|
existingSchedule.DeviceGroups.Clear();
|
|
if (schedule.DeviceGroups?.Any() == true)
|
|
{
|
|
var deviceGroupIds = schedule.DeviceGroups.Select(x => x.ID);
|
|
var newDeviceGroups = await dbContext.DeviceGroups
|
|
.Where(x => deviceGroupIds.Contains(x.ID))
|
|
.ToListAsync();
|
|
existingSchedule.DeviceGroups.AddRange(newDeviceGroups);
|
|
}
|
|
}
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task AddScriptResultToScriptRun(string scriptResultId, int scriptRunId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var run = await dbContext.ScriptRuns
|
|
.Include(x => x.Results)
|
|
.Include(x => x.DevicesCompleted)
|
|
.FirstOrDefaultAsync(x => x.Id == scriptRunId);
|
|
|
|
var result = await dbContext.ScriptResults.FindAsync(scriptResultId);
|
|
|
|
if (run is not null && result is not null)
|
|
{
|
|
run.Results.Add(result);
|
|
|
|
var device = await dbContext.Devices
|
|
.Include(x => x.ScriptRunsCompleted)
|
|
.FirstOrDefaultAsync(x => x.ID == result.DeviceID);
|
|
|
|
if (device is not null)
|
|
{
|
|
run.DevicesCompleted.Add(device);
|
|
device.ScriptRunsCompleted.Add(run);
|
|
}
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
public async Task AddScriptRun(ScriptRun scriptRun)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Attach(scriptRun);
|
|
dbContext.ScriptRuns.Add(scriptRun);
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task<string> AddSharedFile(IBrowserFile file, string organizationID, Action<double, string> progressCallback)
|
|
{
|
|
var fileContents = new byte[file.Size];
|
|
using var stream = file.OpenReadStream(AppConstants.MaxUploadFileSize);
|
|
|
|
for (var i = 0; i < file.Size; i += 5_000)
|
|
{
|
|
var readSize = (int)Math.Min(5_000, file.Size - i);
|
|
await stream.ReadAsync(fileContents.AsMemory(i, readSize));
|
|
|
|
progressCallback.Invoke((double)stream.Position / stream.Length, file.Name);
|
|
}
|
|
|
|
return await AddSharedFileInternal(file.Name, fileContents, file.ContentType, organizationID);
|
|
}
|
|
|
|
public async Task<string> AddSharedFile(IFormFile file, string organizationID)
|
|
{
|
|
var fileContents = new byte[file.Length];
|
|
using var stream = file.OpenReadStream();
|
|
await stream.ReadAsync(fileContents.AsMemory(0, (int)file.Length));
|
|
|
|
return await AddSharedFileInternal(file.Name, fileContents, file.ContentType, organizationID);
|
|
}
|
|
|
|
public bool AddUserToDeviceGroup(string orgID, string groupID, string userName, out string resultMessage)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
resultMessage = string.Empty;
|
|
|
|
var deviceGroup = dbContext.DeviceGroups
|
|
.Include(x => x.Users)
|
|
.FirstOrDefault(x =>
|
|
x.ID == groupID &&
|
|
x.OrganizationID == orgID);
|
|
|
|
if (deviceGroup == null)
|
|
{
|
|
resultMessage = "Device group not found.";
|
|
return false;
|
|
}
|
|
|
|
userName = userName.Trim().ToLower();
|
|
|
|
var user = dbContext.Users
|
|
.Include(x => x.DeviceGroups)
|
|
.FirstOrDefault(x =>
|
|
x.UserName.ToLower() == userName &&
|
|
x.OrganizationID == orgID);
|
|
|
|
if (user == null)
|
|
{
|
|
resultMessage = "User not found.";
|
|
return false;
|
|
}
|
|
|
|
deviceGroup.Devices ??= new List<Device>();
|
|
user.DeviceGroups ??= new List<DeviceGroup>();
|
|
|
|
if (deviceGroup.Users.Any(x => x.Id == user.Id))
|
|
{
|
|
resultMessage = "User already in group.";
|
|
return false;
|
|
}
|
|
|
|
deviceGroup.Users.Add(user);
|
|
user.DeviceGroups.Add(deviceGroup);
|
|
dbContext.SaveChanges();
|
|
resultMessage = user.Id;
|
|
return true;
|
|
}
|
|
|
|
public void ChangeUserIsAdmin(string organizationID, string targetUserID, bool isAdmin)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var targetUser = dbContext.Users.FirstOrDefault(x =>
|
|
x.OrganizationID == organizationID &&
|
|
x.Id == targetUserID);
|
|
|
|
if (targetUser != null)
|
|
{
|
|
targetUser.IsAdministrator = isAdmin;
|
|
dbContext.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public void CleanupOldRecords()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
if (_appConfig.DataRetentionInDays > -1)
|
|
{
|
|
|
|
var expirationDate = DateTimeOffset.Now - TimeSpan.FromDays(_appConfig.DataRetentionInDays);
|
|
|
|
var scriptRuns = dbContext.ScriptRuns
|
|
.Include(x=>x.Results)
|
|
.Include(x=>x.Devices)
|
|
.Include(x=>x.DevicesCompleted)
|
|
.Where(x => x.RunAt < expirationDate);
|
|
|
|
foreach (var run in scriptRuns)
|
|
{
|
|
run.Devices?.Clear();
|
|
run.DevicesCompleted?.Clear();
|
|
run.Results?.Clear();
|
|
}
|
|
|
|
dbContext.RemoveRange(scriptRuns);
|
|
|
|
var eventLogs = dbContext.EventLogs
|
|
.Where(x => x.TimeStamp < expirationDate);
|
|
|
|
dbContext.RemoveRange(eventLogs);
|
|
|
|
var commandResults = dbContext.ScriptResults
|
|
.Where(x => x.TimeStamp < expirationDate);
|
|
|
|
dbContext.RemoveRange(commandResults);
|
|
|
|
var sharedFiles = dbContext.SharedFiles
|
|
.Where(x => x.Timestamp < expirationDate);
|
|
|
|
dbContext.RemoveRange(sharedFiles);
|
|
|
|
dbContext.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public async Task ClearLogs(string currentUserName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var currentUser = await dbContext.Users.FirstOrDefaultAsync(x => x.UserName == currentUserName);
|
|
if (currentUser is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
|
|
if (currentUser.IsServerAdmin)
|
|
{
|
|
dbContext.EventLogs.RemoveRange(dbContext.EventLogs);
|
|
dbContext.ScriptResults.RemoveRange(dbContext.ScriptResults);
|
|
}
|
|
else
|
|
{
|
|
var eventLogs = dbContext.EventLogs.Where(x => x.OrganizationID == currentUser.OrganizationID);
|
|
var commandResults = dbContext.ScriptResults.Where(x => x.OrganizationID == currentUser.OrganizationID);
|
|
|
|
dbContext.ScriptResults.RemoveRange(commandResults);
|
|
dbContext.EventLogs.RemoveRange(eventLogs);
|
|
}
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
WriteEvent(ex, currentUser.OrganizationID);
|
|
}
|
|
}
|
|
|
|
public async Task<ApiToken> CreateApiToken(string userName, string tokenName, string secretHash)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == userName);
|
|
|
|
var newToken = new ApiToken()
|
|
{
|
|
Name = tokenName,
|
|
OrganizationID = user.OrganizationID,
|
|
Secret = secretHash
|
|
};
|
|
dbContext.ApiTokens.Add(newToken);
|
|
await dbContext.SaveChangesAsync();
|
|
return newToken;
|
|
}
|
|
|
|
public async Task<Device> CreateDevice(DeviceSetupOptions options)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
try
|
|
{
|
|
if (options is null ||
|
|
string.IsNullOrWhiteSpace(options.DeviceID) ||
|
|
string.IsNullOrWhiteSpace(options.OrganizationID) ||
|
|
dbContext.Devices.Any(x => x.ID == options.DeviceID))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var device = new Device()
|
|
{
|
|
ID = options.DeviceID,
|
|
OrganizationID = options.OrganizationID
|
|
};
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.DeviceAlias))
|
|
{
|
|
device.Alias = options.DeviceAlias;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(options.DeviceGroupName))
|
|
{
|
|
var group = dbContext.DeviceGroups.FirstOrDefault(x =>
|
|
x.Name.ToLower() == options.DeviceGroupName.ToLower() &&
|
|
x.OrganizationID == device.OrganizationID);
|
|
device.DeviceGroup = group;
|
|
}
|
|
|
|
dbContext.Devices.Add(device);
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
return device;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
WriteEvent(ex, options.OrganizationID);
|
|
return null;
|
|
}
|
|
|
|
}
|
|
|
|
public async Task<bool> CreateUser(string userEmail, bool isAdmin, string organizationID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
try
|
|
{
|
|
var user = new RemotelyUser()
|
|
{
|
|
UserName = userEmail.Trim().ToLower(),
|
|
Email = userEmail.Trim().ToLower(),
|
|
IsAdministrator = isAdmin,
|
|
OrganizationID = organizationID,
|
|
UserOptions = new RemotelyUserOptions()
|
|
};
|
|
var org = dbContext.Organizations
|
|
.Include(x => x.RemotelyUsers)
|
|
.FirstOrDefault(x => x.ID == organizationID);
|
|
dbContext.Users.Add(user);
|
|
org.RemotelyUsers.Add(user);
|
|
await dbContext.SaveChangesAsync();
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
WriteEvent(ex, organizationID);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
|
|
public async Task DeleteAlert(Alert alert)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Alerts.Remove(alert);
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task DeleteAllAlerts(string orgID, string userName = null)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var alerts = dbContext.Alerts.Where(x => x.OrganizationID == orgID);
|
|
|
|
if (!string.IsNullOrWhiteSpace(userName))
|
|
{
|
|
var userId = GetUserByNameWithOrg(userName)?.Id;
|
|
|
|
alerts = alerts.Where(x => x.UserID == userId);
|
|
}
|
|
|
|
dbContext.Alerts.RemoveRange(alerts);
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task DeleteApiToken(string userName, string tokenId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == userName);
|
|
var token = dbContext.ApiTokens.FirstOrDefault(x =>
|
|
x.OrganizationID == user.OrganizationID &&
|
|
x.ID == tokenId);
|
|
|
|
dbContext.ApiTokens.Remove(token);
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public void DeleteDeviceGroup(string orgID, string deviceGroupID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var deviceGroup = dbContext.DeviceGroups
|
|
.Include(x => x.Devices)
|
|
.Include(x => x.Users)
|
|
.ThenInclude(x => x.DeviceGroups)
|
|
.FirstOrDefault(x =>
|
|
x.ID == deviceGroupID &&
|
|
x.OrganizationID == orgID);
|
|
|
|
deviceGroup.Devices?.ForEach(x =>
|
|
{
|
|
x.DeviceGroup = null;
|
|
});
|
|
|
|
deviceGroup.Users?.ForEach(x =>
|
|
{
|
|
x.DeviceGroups.Remove(deviceGroup);
|
|
});
|
|
|
|
deviceGroup.Devices.Clear();
|
|
deviceGroup.Users.Clear();
|
|
|
|
dbContext.DeviceGroups.Remove(deviceGroup);
|
|
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public void DeleteInvite(string orgID, string inviteID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var invite = dbContext.InviteLinks.FirstOrDefault(x =>
|
|
x.OrganizationID == orgID &&
|
|
x.ID == inviteID);
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == invite.InvitedUser);
|
|
|
|
if (user != null && string.IsNullOrWhiteSpace(user.PasswordHash))
|
|
{
|
|
dbContext.Remove(user);
|
|
}
|
|
dbContext.Remove(invite);
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public async Task DeleteSavedScript(Guid scriptId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var script = dbContext.SavedScripts.Find(scriptId);
|
|
if (script is not null)
|
|
{
|
|
dbContext.SavedScripts.Remove(script);
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
public async Task DeleteScriptSchedule(int scriptScheduleId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var schedule = dbContext.ScriptSchedules.Find(scriptScheduleId);
|
|
if (schedule is not null)
|
|
{
|
|
dbContext.ScriptSchedules.Remove(schedule);
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
}
|
|
|
|
public async Task DeleteUser(string orgID, string targetUserID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var target = dbContext.Users
|
|
.Include(x => x.DeviceGroups)
|
|
.ThenInclude(x => x.Devices)
|
|
.Include(x => x.Organization)
|
|
.Include(x => x.Alerts)
|
|
.Include(x => x.SavedScripts)
|
|
.Include(x => x.ScriptSchedules)
|
|
.FirstOrDefault(x =>
|
|
x.Id == targetUserID &&
|
|
x.OrganizationID == orgID);
|
|
|
|
if (target is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (target.DeviceGroups?.Any() == true)
|
|
{
|
|
foreach (var deviceGroup in target.DeviceGroups.ToList())
|
|
{
|
|
deviceGroup.Users.Remove(target);
|
|
}
|
|
}
|
|
|
|
foreach (var alert in target.Alerts)
|
|
{
|
|
dbContext.Alerts.Remove(alert);
|
|
}
|
|
|
|
target.OrganizationID = null;
|
|
target.Organization = null;
|
|
|
|
dbContext
|
|
.Organizations
|
|
.Include(x => x.RemotelyUsers)
|
|
.FirstOrDefault(x => x.ID == orgID)
|
|
.RemotelyUsers.Remove(target);
|
|
|
|
|
|
dbContext.Users.Remove(target);
|
|
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
}
|
|
|
|
public void DetachEntity(object entity)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Entry(entity).State = EntityState.Detached;
|
|
}
|
|
|
|
public void DeviceDisconnected(string deviceID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var device = dbContext.Devices.Find(deviceID);
|
|
if (device != null)
|
|
{
|
|
device.LastOnline = DateTimeOffset.Now;
|
|
device.IsOnline = false;
|
|
dbContext.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public bool DoesUserExist(string userName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
if (string.IsNullOrWhiteSpace(userName))
|
|
{
|
|
return false;
|
|
}
|
|
return dbContext.Users.Any(x => x.UserName.Trim().ToLower() == userName.Trim().ToLower());
|
|
}
|
|
|
|
public bool DoesUserHaveAccessToDevice(string deviceID, RemotelyUser remotelyUser)
|
|
{
|
|
if (remotelyUser is null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices
|
|
.Include(x => x.DeviceGroup)
|
|
.ThenInclude(x => x.Users)
|
|
.Any(device => device.OrganizationID == remotelyUser.OrganizationID &&
|
|
device.ID == deviceID &&
|
|
(
|
|
remotelyUser.IsAdministrator ||
|
|
string.IsNullOrWhiteSpace(device.DeviceGroupID) ||
|
|
!device.DeviceGroup.Users.Any() ||
|
|
device.DeviceGroup.Users.Any(user => user.Id == remotelyUser.Id
|
|
)));
|
|
}
|
|
|
|
public bool DoesUserHaveAccessToDevice(string deviceID, string remotelyUserID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var remotelyUser = dbContext.Users.Find(remotelyUserID);
|
|
|
|
return DoesUserHaveAccessToDevice(deviceID, remotelyUser);
|
|
}
|
|
|
|
public string[] FilterDeviceIDsByUserPermission(string[] deviceIDs, RemotelyUser remotelyUser)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices
|
|
.Include(x => x.DeviceGroup)
|
|
.ThenInclude(x => x.Users)
|
|
.Where(device =>
|
|
device.OrganizationID == remotelyUser.OrganizationID &&
|
|
deviceIDs.Contains(device.ID) &&
|
|
(
|
|
remotelyUser.IsAdministrator ||
|
|
device.DeviceGroup.Users.Count == 0 ||
|
|
device.DeviceGroup.Users.Any(user => user.Id == remotelyUser.Id
|
|
)))
|
|
.Select(x => x.ID)
|
|
.ToArray();
|
|
}
|
|
|
|
public string[] FilterUsersByDevicePermission(IEnumerable<string> userIDs, string deviceID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return FilterUsersByDevicePermissionInternal(dbContext, userIDs, deviceID);
|
|
}
|
|
|
|
public async Task<Alert> GetAlert(string alertID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return await dbContext.Alerts
|
|
.Include(x => x.Device)
|
|
.Include(x => x.User)
|
|
.FirstOrDefaultAsync(x => x.ID == alertID);
|
|
}
|
|
|
|
public Alert[] GetAlerts(string userID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Alerts
|
|
.Include(x => x.Device)
|
|
.Include(x => x.User)
|
|
.Where(x => x.UserID == userID)
|
|
.OrderByDescending(x => x.CreatedOn)
|
|
.ToArray();
|
|
}
|
|
|
|
public ApiToken[] GetAllApiTokens(string userID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.Id == userID);
|
|
|
|
return dbContext.ApiTokens
|
|
.Where(x => x.OrganizationID == user.OrganizationID)
|
|
.OrderByDescending(x => x.LastUsed)
|
|
.ToArray();
|
|
}
|
|
|
|
public ScriptResult[] GetAllCommandResults(string orgID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ScriptResults
|
|
.Where(x => x.OrganizationID == orgID)
|
|
.OrderByDescending(x => x.TimeStamp)
|
|
.ToArray();
|
|
}
|
|
|
|
public ScriptResult[] GetAllCommandResultsForUser(string orgId, string userName, string deviceId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ScriptResults
|
|
.Where(x => x.OrganizationID == orgId &&
|
|
x.SenderUserName == userName &&
|
|
x.DeviceID == deviceId)
|
|
.OrderByDescending(x => x.TimeStamp)
|
|
.ToArray();
|
|
}
|
|
|
|
public Device[] GetAllDevices(string orgID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices.Where(x => x.OrganizationID == orgID).ToArray();
|
|
}
|
|
|
|
public EventLog[] GetAllEventLogs(string orgID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.EventLogs
|
|
.Where(x => x.OrganizationID == orgID)
|
|
.OrderByDescending(x => x.TimeStamp)
|
|
.ToArray();
|
|
}
|
|
|
|
public InviteLink[] GetAllInviteLinks(string organizationId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.InviteLinks
|
|
.Where(x => x.OrganizationID == organizationId)
|
|
.ToArray();
|
|
}
|
|
|
|
public ScriptResult[] GetAllScriptResults(string orgId, string deviceId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ScriptResults
|
|
.Where(x => x.OrganizationID == orgId && x.DeviceID == deviceId)
|
|
.OrderByDescending(x => x.TimeStamp)
|
|
.ToArray();
|
|
}
|
|
|
|
public ScriptResult[] GetAllScriptResultsForUser(string orgId, string userName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ScriptResults
|
|
.Where(x => x.OrganizationID == orgId && x.SenderUserName == userName)
|
|
.OrderByDescending(x => x.TimeStamp)
|
|
.ToArray();
|
|
}
|
|
|
|
public RemotelyUser[] GetAllUsersForServer()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Users.ToArray();
|
|
}
|
|
|
|
public async Task<RemotelyUser[]> GetAllUsersInOrganization(string orgId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(orgId))
|
|
{
|
|
return Array.Empty<RemotelyUser>();
|
|
}
|
|
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var organization = await dbContext.Organizations
|
|
.Include(x => x.RemotelyUsers)
|
|
.FirstOrDefaultAsync(x => x.ID == orgId);
|
|
|
|
return organization.RemotelyUsers.ToArray();
|
|
}
|
|
|
|
public ApiToken GetApiKey(string keyId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(keyId))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ApiTokens.FirstOrDefault(x => x.ID == keyId);
|
|
}
|
|
|
|
public async Task<BrandingInfo> GetBrandingInfo(string organizationId)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(organizationId))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var organization = await dbContext.Organizations
|
|
.Include(x => x.BrandingInfo)
|
|
.FirstOrDefaultAsync(x => x.ID == organizationId);
|
|
|
|
if (organization is null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (organization.BrandingInfo is null)
|
|
{
|
|
organization.BrandingInfo = new BrandingInfo();
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
return organization.BrandingInfo;
|
|
}
|
|
|
|
public async Task<Organization> GetDefaultOrganization()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return await dbContext.Organizations.FirstOrDefaultAsync(x => x.IsDefaultOrganization);
|
|
}
|
|
|
|
public async Task<string> GetDefaultRelayCode()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var relayCode = await dbContext.Organizations
|
|
.Where(x => x.IsDefaultOrganization)
|
|
.Select(x => x.RelayCode)
|
|
.FirstOrDefaultAsync();
|
|
|
|
return relayCode;
|
|
}
|
|
|
|
public Device GetDevice(string orgID, string deviceID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices.FirstOrDefault(x =>
|
|
x.OrganizationID == orgID &&
|
|
x.ID == deviceID);
|
|
}
|
|
|
|
public Device GetDevice(string deviceID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices.FirstOrDefault(x => x.ID == deviceID);
|
|
}
|
|
|
|
public int GetDeviceCount()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices.Count();
|
|
}
|
|
|
|
public int GetDeviceCount(RemotelyUser user)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices
|
|
.Include(x => x.DeviceGroup)
|
|
.ThenInclude(x => x.Users)
|
|
.Count(x =>
|
|
x.OrganizationID == user.OrganizationID &&
|
|
(
|
|
user.IsAdministrator ||
|
|
string.IsNullOrWhiteSpace(x.DeviceGroupID) ||
|
|
!x.DeviceGroup.Users.Any() ||
|
|
x.DeviceGroup.Users.Any(deviceUser => deviceUser.Id == user.Id)
|
|
));
|
|
}
|
|
|
|
public async Task<DeviceGroup> GetDeviceGroup(string deviceGroupID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
return await dbContext.DeviceGroups.FindAsync(deviceGroupID);
|
|
}
|
|
|
|
public DeviceGroup[] GetDeviceGroups(string username)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == username);
|
|
|
|
if (user is null)
|
|
{
|
|
return null;
|
|
}
|
|
var userId = user.Id;
|
|
|
|
var groupIds = dbContext.DeviceGroups
|
|
.Include(x => x.Users)
|
|
.ThenInclude(x => x.DeviceGroups)
|
|
.Where(x =>
|
|
x.OrganizationID == user.OrganizationID &&
|
|
(
|
|
user.IsAdministrator ||
|
|
x.Users.Count == 0 ||
|
|
x.Users.Any(x => x.Id == userId)
|
|
)
|
|
)
|
|
.Select(x => x.ID);
|
|
|
|
if (groupIds.Any())
|
|
{
|
|
return dbContext.DeviceGroups
|
|
.Where(x => groupIds.Contains(x.ID))
|
|
.OrderBy(x => x.Name)
|
|
.ToArray();
|
|
}
|
|
|
|
return Array.Empty<DeviceGroup>();
|
|
}
|
|
|
|
public DeviceGroup[] GetDeviceGroupsForOrganization(string organizationId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.DeviceGroups
|
|
.Include(x => x.Users)
|
|
.ThenInclude(x => x.DeviceGroups)
|
|
.Where(x => x.OrganizationID == organizationId)
|
|
.OrderBy(x => x.Name)
|
|
.ToArray();
|
|
}
|
|
|
|
public List<Device> GetDevices(IEnumerable<string> deviceIds)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices
|
|
.Where(x => deviceIds.Contains(x.ID))
|
|
.ToList();
|
|
|
|
}
|
|
|
|
public Device[] GetDevicesForUser(string userName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
if (string.IsNullOrWhiteSpace(userName))
|
|
{
|
|
return Array.Empty<Device>();
|
|
}
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == userName);
|
|
|
|
if (user is null)
|
|
{
|
|
return Array.Empty<Device>();
|
|
}
|
|
|
|
var deviceIds = dbContext.Devices
|
|
.Include(x => x.DeviceGroup)
|
|
.ThenInclude(x => x.Users)
|
|
.Where(x =>
|
|
x.OrganizationID == user.OrganizationID &&
|
|
(
|
|
user.IsAdministrator ||
|
|
string.IsNullOrWhiteSpace(x.DeviceGroupID) ||
|
|
!x.DeviceGroup.Users.Any() ||
|
|
x.DeviceGroup.Users.Any(deviceUser => deviceUser.Id == user.Id)
|
|
))
|
|
.Select(x => x.ID);
|
|
|
|
return dbContext.Devices
|
|
.Where(x => deviceIds.Contains(x.ID))
|
|
.ToArray();
|
|
}
|
|
|
|
public EventLog[] GetEventLogs(string userName, DateTimeOffset from, DateTimeOffset to, EventType? type, string message)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = dbContext.Users
|
|
.FirstOrDefault(x => x.UserName == userName);
|
|
|
|
var query = dbContext.EventLogs
|
|
.AsNoTracking()
|
|
.AsQueryable();
|
|
|
|
var fromDate = from.Date;
|
|
var toDate = to.Date.AddDays(1);
|
|
|
|
if (user.IsServerAdmin)
|
|
{
|
|
query = query.Where(x => x.TimeStamp >= fromDate && x.TimeStamp <= toDate)
|
|
.OrderByDescending(x => x.TimeStamp);
|
|
}
|
|
else
|
|
{
|
|
var orgID = user.OrganizationID;
|
|
query = query
|
|
.Where(x => x.OrganizationID == orgID &&
|
|
x.TimeStamp >= fromDate && x.TimeStamp <= toDate)
|
|
.OrderByDescending(x => x.TimeStamp);
|
|
}
|
|
if (type != null)
|
|
{
|
|
query = query.Where(x => x.EventType == type);
|
|
}
|
|
if (!string.IsNullOrWhiteSpace(message))
|
|
{
|
|
message = message.ToLower();
|
|
query = query.Where(x => x.Message.ToLower().Contains(message));
|
|
}
|
|
return query.ToArray();
|
|
}
|
|
|
|
public Organization GetOrganizationById(string organizationID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Organizations.Find(organizationID);
|
|
}
|
|
|
|
public async Task<Organization> GetOrganizationByRelayCode(string relayCode)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
if (string.IsNullOrWhiteSpace(relayCode))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return await dbContext.Organizations.FirstOrDefaultAsync(x => x.RelayCode == relayCode.ToLower());
|
|
}
|
|
|
|
public async Task<Organization> GetOrganizationByUserName(string userName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = await dbContext
|
|
.Users
|
|
.Include(x => x.Organization)
|
|
.FirstOrDefaultAsync(x => x.UserName.ToLower() == userName.ToLower());
|
|
|
|
return user.Organization;
|
|
}
|
|
|
|
public int GetOrganizationCount()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Organizations.Count();
|
|
}
|
|
|
|
public string GetOrganizationNameById(string organizationID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Organizations.FirstOrDefault(x => x.ID == organizationID)?.OrganizationName;
|
|
}
|
|
|
|
public string GetOrganizationNameByUserName(string userName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Users
|
|
.Include(x => x.Organization)
|
|
.FirstOrDefault(x => x.UserName == userName)
|
|
.Organization
|
|
.OrganizationName;
|
|
}
|
|
|
|
public async Task<List<ScriptRun>> GetPendingScriptRuns(string deviceId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var pendingRuns = new List<ScriptRun>();
|
|
|
|
var now = Time.Now;
|
|
|
|
var scriptRunGroups = dbContext.ScriptRuns
|
|
.Include(x => x.Devices)
|
|
.Include(x => x.DevicesCompleted)
|
|
.Where(scriptRun =>
|
|
scriptRun.RunOnNextConnect &&
|
|
dbContext.SavedScripts.Any(savedScript => savedScript.Id == scriptRun.SavedScriptId) &&
|
|
scriptRun.Devices.Any(device => device.ID == deviceId) &&
|
|
scriptRun.RunAt < now)
|
|
.AsEnumerable()
|
|
.GroupBy(x => x.SavedScriptId);
|
|
|
|
foreach (var group in scriptRunGroups)
|
|
{
|
|
var latestRun = group
|
|
.OrderByDescending(x => x.RunAt)
|
|
.FirstOrDefault();
|
|
|
|
if (!latestRun.DevicesCompleted.Any(x => x.ID == deviceId))
|
|
{
|
|
pendingRuns.Add(latestRun);
|
|
}
|
|
}
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
|
|
|
|
return pendingRuns;
|
|
}
|
|
|
|
public async Task<List<SavedScript>> GetQuickScripts(string userId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return await dbContext.SavedScripts
|
|
.Where(x => x.CreatorId == userId && x.IsQuickScript)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<SavedScript> GetSavedScript(string userId, Guid scriptId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return await dbContext.SavedScripts
|
|
.FirstOrDefaultAsync(x =>
|
|
x.Id == scriptId &&
|
|
(x.IsPublic || x.CreatorId == userId));
|
|
}
|
|
|
|
public async Task<SavedScript> GetSavedScript(Guid scriptId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
return await dbContext.SavedScripts.FirstOrDefaultAsync(x => x.Id == scriptId);
|
|
}
|
|
|
|
public async Task<List<SavedScript>> GetSavedScriptsWithoutContent(string userId, string organizationId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var query = dbContext.SavedScripts
|
|
.Include(x => x.Creator)
|
|
.Where(x => x.Creator.OrganizationID == organizationId &&
|
|
(x.IsPublic || x.CreatorId == userId));
|
|
|
|
return await query.Select(x => new SavedScript()
|
|
{
|
|
Creator = x.Creator,
|
|
CreatorId = x.CreatorId,
|
|
FolderPath = x.FolderPath,
|
|
Id = x.Id,
|
|
IsPublic = x.IsPublic,
|
|
IsQuickScript = x.IsQuickScript,
|
|
Name = x.Name,
|
|
OrganizationID = x.OrganizationID
|
|
}).ToListAsync();
|
|
}
|
|
|
|
public ScriptResult GetScriptResult(string commandResultID, string orgID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ScriptResults
|
|
.FirstOrDefault(x =>
|
|
x.OrganizationID == orgID &&
|
|
x.ID == commandResultID);
|
|
}
|
|
|
|
public ScriptResult GetScriptResult(string commandResultID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.ScriptResults.Find(commandResultID);
|
|
}
|
|
|
|
public async Task<List<ScriptSchedule>> GetScriptSchedules(string organizationId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
return await dbContext.ScriptSchedules
|
|
.Include(x => x.Creator)
|
|
.Include(x => x.Devices)
|
|
.Include(x => x.DeviceGroups)
|
|
.Where(x => x.OrganizationID == organizationId)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public async Task<List<ScriptSchedule>> GetScriptSchedulesDue()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var now = Time.Now;
|
|
|
|
return await dbContext.ScriptSchedules
|
|
.Include(x => x.Devices)
|
|
.Include(x => x.DeviceGroups)
|
|
.ThenInclude(x => x.Devices)
|
|
.Where(x => x.NextRun < now)
|
|
.ToListAsync();
|
|
}
|
|
|
|
public List<string> GetServerAdmins()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Users
|
|
.Where(x => x.IsServerAdmin)
|
|
.Select(x => x.UserName)
|
|
.ToList();
|
|
}
|
|
|
|
public SharedFile GetSharedFiled(string fileID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.SharedFiles.Find(fileID);
|
|
}
|
|
|
|
public int GetTotalDevices()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Devices.Count();
|
|
}
|
|
|
|
public async Task<RemotelyUser> GetUserAsync(string username)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(username))
|
|
{
|
|
return null;
|
|
}
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return await dbContext.Users.FirstOrDefaultAsync(x => x.UserName == username);
|
|
}
|
|
|
|
public RemotelyUser GetUserByID(string userID)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(userID))
|
|
{
|
|
return null;
|
|
}
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Users.FirstOrDefault(x => x.Id == userID);
|
|
}
|
|
|
|
public RemotelyUser GetUserByNameWithOrg(string userName)
|
|
{
|
|
if (userName == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Users
|
|
.Include(x => x.Organization)
|
|
.FirstOrDefault(x => x.UserName.ToLower().Trim() == userName.ToLower().Trim());
|
|
}
|
|
|
|
public RemotelyUserOptions GetUserOptions(string userName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
return dbContext.Users
|
|
.FirstOrDefault(x => x.UserName == userName)
|
|
.UserOptions;
|
|
}
|
|
|
|
public bool JoinViaInvitation(string userName, string inviteID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var invite = dbContext.InviteLinks.FirstOrDefault(x =>
|
|
x.InvitedUser.ToLower() == userName.ToLower() &&
|
|
x.ID == inviteID);
|
|
|
|
if (invite == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == userName);
|
|
var organization = dbContext.Organizations
|
|
.Include(x => x.RemotelyUsers)
|
|
.FirstOrDefault(x => x.ID == invite.OrganizationID);
|
|
|
|
user.Organization = organization;
|
|
user.OrganizationID = organization.ID;
|
|
user.IsAdministrator = invite.IsAdmin;
|
|
organization.RemotelyUsers.Add(user);
|
|
|
|
dbContext.SaveChanges();
|
|
|
|
dbContext.InviteLinks.Remove(invite);
|
|
dbContext.SaveChanges();
|
|
return true;
|
|
}
|
|
|
|
public void PopulateRelayCodes()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
foreach (var organization in dbContext.Organizations)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(organization.RelayCode))
|
|
{
|
|
do
|
|
{
|
|
organization.RelayCode = new string(Guid.NewGuid().ToString().Take(4).ToArray());
|
|
}
|
|
while (dbContext.Organizations.Any(x => x.ID != organization.ID && x.RelayCode == organization.RelayCode));
|
|
}
|
|
}
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public void RemoveDevices(string[] deviceIDs)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var devices = dbContext.Devices
|
|
.Include(x => x.ScriptResults)
|
|
.Include(x => x.ScriptRuns)
|
|
.Include(x => x.ScriptSchedules)
|
|
.Include(x => x.ScriptRunsCompleted)
|
|
.Include(x => x.DeviceGroup)
|
|
.Include(x => x.Alerts)
|
|
.Where(x => deviceIDs.Contains(x.ID));
|
|
|
|
dbContext.Devices.RemoveRange(devices);
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public async Task<bool> RemoveUserFromDeviceGroup(string orgID, string groupID, string userID)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var deviceGroup = dbContext.DeviceGroups
|
|
.Include(x => x.Users)
|
|
.ThenInclude(x => x.DeviceGroups)
|
|
.FirstOrDefault(x =>
|
|
x.ID == groupID &&
|
|
x.OrganizationID == orgID);
|
|
|
|
if (deviceGroup?.Users?.Any(x => x.Id == userID) == true)
|
|
{
|
|
var user = deviceGroup.Users.FirstOrDefault(x => x.Id == userID);
|
|
|
|
user.DeviceGroups.Remove(deviceGroup);
|
|
deviceGroup.Users.Remove(user);
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public async Task RenameApiToken(string userName, string tokenId, string tokenName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var user = dbContext.Users.FirstOrDefault(x => x.UserName == userName);
|
|
var token = dbContext.ApiTokens.FirstOrDefault(x =>
|
|
x.OrganizationID == user.OrganizationID &&
|
|
x.ID == tokenId);
|
|
|
|
token.Name = tokenName;
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public void SetAllDevicesNotOnline()
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Devices.ForEachAsync(x =>
|
|
{
|
|
x.IsOnline = false;
|
|
}).Wait();
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public async Task SetDisplayName(RemotelyUser user, string displayName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Attach(user);
|
|
user.UserOptions.DisplayName = displayName;
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task SetIsDefaultOrganization(string orgID, bool isDefault)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var organization = await dbContext.Organizations.FindAsync(orgID);
|
|
if (organization is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (isDefault)
|
|
{
|
|
await dbContext.Organizations.ForEachAsync(x => x.IsDefaultOrganization = false);
|
|
}
|
|
|
|
organization.IsDefaultOrganization = isDefault;
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public async Task SetIsServerAdmin(string targetUserId, bool isServerAdmin, string callerUserId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var caller = await dbContext.Users.FindAsync(callerUserId);
|
|
if (caller?.IsServerAdmin != true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var targetUser = await dbContext.Users.FindAsync(targetUserId);
|
|
|
|
if (targetUser is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (caller.Id == targetUser.Id)
|
|
{
|
|
// A server admin can't change themselves.
|
|
return;
|
|
}
|
|
|
|
targetUser.IsServerAdmin = isServerAdmin;
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public void SetServerVerificationToken(string deviceID, string verificationToken)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var device = dbContext.Devices.Find(deviceID);
|
|
if (device != null)
|
|
{
|
|
device.ServerVerificationToken = verificationToken;
|
|
dbContext.SaveChanges();
|
|
}
|
|
}
|
|
|
|
public async Task<bool> TempPasswordSignIn(string email, string password)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(password))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var user = GetUserByNameWithOrg(email);
|
|
|
|
if (user is null)
|
|
{
|
|
return false;
|
|
}
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
if (user.TempPassword == password)
|
|
{
|
|
user.TempPassword = string.Empty;
|
|
await dbContext.SaveChangesAsync();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public async Task UpdateBrandingInfo(
|
|
string organizationId,
|
|
string productName,
|
|
byte[] iconBytes,
|
|
ColorPickerModel titleForeground,
|
|
ColorPickerModel titleBackground,
|
|
ColorPickerModel titleButtonForeground)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var organization = await dbContext.Organizations
|
|
.Include(x => x.BrandingInfo)
|
|
.FirstOrDefaultAsync(x => x.ID == organizationId);
|
|
|
|
if (organization is null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (organization.BrandingInfo is null)
|
|
{
|
|
organization.BrandingInfo = new BrandingInfo();
|
|
}
|
|
|
|
organization.BrandingInfo.Product = productName;
|
|
|
|
if (iconBytes?.Any() == true)
|
|
{
|
|
organization.BrandingInfo.Icon = iconBytes;
|
|
}
|
|
|
|
organization.BrandingInfo.TitleBackgroundRed = titleBackground.Red;
|
|
organization.BrandingInfo.TitleBackgroundGreen = titleBackground.Green;
|
|
organization.BrandingInfo.TitleBackgroundBlue = titleBackground.Blue;
|
|
|
|
organization.BrandingInfo.TitleForegroundRed = titleForeground.Red;
|
|
organization.BrandingInfo.TitleForegroundGreen = titleForeground.Green;
|
|
organization.BrandingInfo.TitleForegroundBlue = titleForeground.Blue;
|
|
|
|
organization.BrandingInfo.ButtonForegroundRed = titleButtonForeground.Red;
|
|
organization.BrandingInfo.ButtonForegroundGreen = titleButtonForeground.Green;
|
|
organization.BrandingInfo.ButtonForegroundBlue = titleButtonForeground.Blue;
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
}
|
|
|
|
public void UpdateDevice(string deviceID, string tag, string alias, string deviceGroupID, string notes, WebRtcSetting webRtcSetting)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var device = dbContext.Devices.Find(deviceID);
|
|
if (device == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
device.Tags = tag;
|
|
device.DeviceGroupID = deviceGroupID;
|
|
device.Alias = alias;
|
|
device.Notes = notes;
|
|
device.WebRtcSetting = webRtcSetting;
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public async Task<Device> UpdateDevice(DeviceSetupOptions deviceOptions, string organizationId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var device = dbContext.Devices.Find(deviceOptions.DeviceID);
|
|
if (device == null || device.OrganizationID != organizationId)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var group = await dbContext.DeviceGroups.FirstOrDefaultAsync(x =>
|
|
x.Name.ToLower() == deviceOptions.DeviceGroupName.ToLower() &&
|
|
x.OrganizationID == device.OrganizationID);
|
|
device.DeviceGroup = group;
|
|
|
|
device.Alias = deviceOptions.DeviceAlias;
|
|
await dbContext.SaveChangesAsync();
|
|
return device;
|
|
}
|
|
|
|
public void UpdateOrganizationName(string orgID, string organizationName)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Organizations
|
|
.FirstOrDefault(x => x.ID == orgID)
|
|
.OrganizationName = organizationName;
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public void UpdateTags(string deviceID, string tags)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var device = dbContext.Devices.Find(deviceID);
|
|
if (device == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
device.Tags = tags;
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public void UpdateUserOptions(string userName, RemotelyUserOptions options)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.Users.FirstOrDefault(x => x.UserName == userName).UserOptions = options;
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
public bool ValidateApiKey(string keyId, string apiSecret, string requestPath, string remoteIP)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var hasher = new PasswordHasher<RemotelyUser>();
|
|
var token = dbContext.ApiTokens.FirstOrDefault(x => x.ID == keyId);
|
|
|
|
|
|
var isValid = token is not null &&
|
|
hasher.VerifyHashedPassword(null, token.Secret, apiSecret) == PasswordVerificationResult.Success;
|
|
|
|
|
|
if (token is not null)
|
|
{
|
|
token.LastUsed = DateTimeOffset.Now;
|
|
dbContext.SaveChanges();
|
|
}
|
|
|
|
WriteEvent($"API token used. Token: {keyId}. Path: {requestPath}. Validated: {isValid}. Remote IP: {remoteIP}", EventType.Info, token?.OrganizationID);
|
|
|
|
return isValid;
|
|
}
|
|
|
|
public void WriteEvent(EventLog eventLog)
|
|
{
|
|
try
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.EventLogs.Add(eventLog);
|
|
dbContext.SaveChanges();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public void WriteEvent(Exception ex, string organizationID)
|
|
{
|
|
try
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.EventLogs.Add(new EventLog()
|
|
{
|
|
EventType = EventType.Error,
|
|
Message = ex.Message,
|
|
Source = ex.Source,
|
|
StackTrace = ex.StackTrace,
|
|
TimeStamp = DateTimeOffset.Now,
|
|
OrganizationID = organizationID
|
|
});
|
|
dbContext.SaveChanges();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public void WriteEvent(string message, string organizationID)
|
|
{
|
|
WriteEvent(message, EventType.Info, organizationID);
|
|
}
|
|
|
|
public void WriteEvent(string message, EventType eventType, string organizationID)
|
|
{
|
|
try
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
dbContext.EventLogs.Add(new EventLog()
|
|
{
|
|
EventType = eventType,
|
|
Message = message,
|
|
TimeStamp = DateTimeOffset.Now,
|
|
OrganizationID = organizationID
|
|
});
|
|
dbContext.SaveChanges();
|
|
}
|
|
catch { }
|
|
}
|
|
|
|
public void WriteLog(LogLevel logLevel, string category, EventId eventId, string state, Exception exception, string[] scopeStack)
|
|
{
|
|
// Prevent re-entrancy.
|
|
if (eventId.Name?.Contains("EntityFrameworkCore") == true)
|
|
{
|
|
return;
|
|
}
|
|
|
|
try
|
|
{
|
|
// TODO: Refactor EventLog to resemble these params. Replace WriteEvent with ILogger<T>.
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
EventType eventType = EventType.Debug;
|
|
switch (logLevel)
|
|
{
|
|
case LogLevel.None:
|
|
case LogLevel.Trace:
|
|
case LogLevel.Debug:
|
|
eventType = EventType.Debug;
|
|
break;
|
|
case LogLevel.Information:
|
|
eventType = EventType.Info;
|
|
break;
|
|
case LogLevel.Warning:
|
|
eventType = EventType.Warning;
|
|
break;
|
|
case LogLevel.Error:
|
|
case LogLevel.Critical:
|
|
eventType = EventType.Error;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
dbContext.EventLogs.Add(new EventLog()
|
|
{
|
|
StackTrace = exception?.StackTrace,
|
|
EventType = eventType,
|
|
Message = $"[{logLevel}] [{string.Join(" - ", scopeStack)} - {category}] | Message: {state} | Exception: {exception?.Message}",
|
|
TimeStamp = DateTimeOffset.Now
|
|
});
|
|
|
|
dbContext.SaveChanges();
|
|
}
|
|
catch { }
|
|
|
|
}
|
|
|
|
private async Task<string> AddSharedFileInternal(
|
|
string fileName,
|
|
byte[] fileContents,
|
|
string contentType,
|
|
string organizationId)
|
|
{
|
|
using var dbContext = _dbFactory.CreateDbContext();
|
|
|
|
var expirationDate = DateTimeOffset.Now.AddDays(-_appConfig.DataRetentionInDays);
|
|
var expiredFiles = dbContext.SharedFiles.Where(x => x.Timestamp < expirationDate);
|
|
dbContext.RemoveRange(expiredFiles);
|
|
|
|
var sharedFile = new SharedFile()
|
|
{
|
|
FileContents = fileContents,
|
|
FileName = fileName,
|
|
ContentType = contentType,
|
|
OrganizationID = organizationId
|
|
};
|
|
|
|
dbContext.SharedFiles.Add(sharedFile);
|
|
|
|
await dbContext.SaveChangesAsync();
|
|
return sharedFile.ID;
|
|
}
|
|
private string[] FilterUsersByDevicePermissionInternal(AppDb dbContext, IEnumerable<string> userIDs, string deviceID)
|
|
{
|
|
var device = dbContext.Devices
|
|
.Include(x => x.DeviceGroup)
|
|
.ThenInclude(x => x.Users)
|
|
.FirstOrDefault(x => x.ID == deviceID);
|
|
|
|
if (device is null)
|
|
{
|
|
return Array.Empty<string>();
|
|
}
|
|
|
|
var orgUsers = dbContext.Users
|
|
.Where(user =>
|
|
user.OrganizationID == device.OrganizationID &&
|
|
userIDs.Contains(user.Id));
|
|
|
|
if (string.IsNullOrWhiteSpace(device.DeviceGroupID) ||
|
|
!device.DeviceGroup.Users.Any())
|
|
{
|
|
return orgUsers
|
|
.Select(x => x.Id)
|
|
.ToArray();
|
|
}
|
|
|
|
var allowedUsers = device?.DeviceGroup?.Users?.Select(x => x.Id) ?? Array.Empty<string>();
|
|
|
|
return orgUsers
|
|
.Where(user =>
|
|
user.IsAdministrator ||
|
|
allowedUsers.Contains(user.Id)
|
|
)
|
|
.Select(x => x.Id)
|
|
.ToArray();
|
|
}
|
|
}
|
|
}
|