Skip to content

Commit

Permalink
Merge pull request #149 from Resgrid/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
ucswift authored Aug 29, 2024
2 parents 7172602 + d3e383b commit 1ead6ab
Show file tree
Hide file tree
Showing 65 changed files with 2,672 additions and 1,372 deletions.
16 changes: 16 additions & 0 deletions Common/Resgrid/Postmark/GetMessageStatus.bru
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
meta {
name: GetMessageStatus
type: http
seq: 1
}

get {
url: https://api.postmarkapp.com/messages/outbound/8bea308e-cc9c-4801-85e5-b98f8af9de1d/details
body: none
auth: none
}

headers {
Accept: application/json
X-Postmark-Server-Token:
}
1 change: 1 addition & 0 deletions Core/Resgrid.Config/OutboundEmailServerConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public static class OutboundEmailServerConfig
public static string Password = "";

public static string PostmarkApiKey = "";
public static string PostmarkMessageStream = "";

public static string AwsAccessKey = "";
public static string AwsSecretKey = "";
Expand Down
6 changes: 4 additions & 2 deletions Core/Resgrid.Config/ServiceBusConfig.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ public static class ServiceBusConfig
public static string AuditQueueName = "audittest";
public static string UnitLoactionQueueName = "unitlocationtest";
public static string PersonnelLoactionQueueName = "personnellocationtest";
public static string SecurityRefreshQueueName = "securityrefreshtest";
#else
public static string CallBroadcastQueueName = "callbroadcast";
public static string MessageBroadcastQueueName = "messagebroadcast";
Expand All @@ -27,6 +28,7 @@ public static class ServiceBusConfig
public static string AuditQueueName = "audit";
public static string UnitLoactionQueueName = "unitlocation";
public static string PersonnelLoactionQueueName = "personnellocation";
public static string SecurityRefreshQueueName = "securityrefresh";
#endif

#region Azure Service Bus Values
Expand All @@ -39,8 +41,8 @@ public static class ServiceBusConfig

#region RabbitMQ Bus Values
public static string RabbitHostname = "rgdevinfaserver";
public static string RabbitHostname2 = "rgdevinfaserver2"; // For 3 host cluster, node 2
public static string RabbitHostname3 = "rgdevinfaserver3"; // For 3 host cluster, node 3
public static string RabbitHostname2 = ""; // For 3 host cluster, node 2
public static string RabbitHostname3 = ""; // For 3 host cluster, node 3
public static string RabbitUsername = "";
public static string RabbbitPassword = "";
public static string RabbbitExchange = "";
Expand Down
20 changes: 7 additions & 13 deletions Core/Resgrid.Framework/Logging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
using Serilog;
using Serilog.Core;
using Serilog.Events;
using Serilog.Sinks.Elasticsearch;
using System;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;

namespace Resgrid.Framework
{
Expand All @@ -20,7 +20,7 @@ public static class Logging

public static void Initialize(string key)
{
if (_isInitialized == false)
if (!_isInitialized)
{
if (SystemBehaviorConfig.ErrorLoggerType == ErrorLoggerTypes.Sentry)
{
Expand All @@ -36,23 +36,17 @@ public static void Initialize(string key)
o.MinimumBreadcrumbLevel = LogEventLevel.Debug;
o.MinimumEventLevel = LogEventLevel.Error;
o.Dsn = dsn;
o.AttachStacktrace = true;
o.SendDefaultPii = true;
o.AutoSessionTracking = true;
o.TracesSampleRate = ExternalErrorConfig.SentryPerfSampleRate;
o.Environment = ExternalErrorConfig.Environment;
o.Release = Assembly.GetEntryAssembly().GetName().Version.ToString();
o.ProfilesSampleRate = 0.0;
}).CreateLogger();
}
else if (SystemBehaviorConfig.ErrorLoggerType == ErrorLoggerTypes.Elk)
else
{
_logger = new LoggerConfiguration()
.WriteTo.Elasticsearch(new ElasticsearchSinkOptions(new Uri(ExternalErrorConfig.ElkServiceUrl))
{
AutoRegisterTemplate = true,
AutoRegisterTemplateVersion = AutoRegisterTemplateVersion.ESv6
}).CreateLogger();
.Enrich.FromLogContext()
.MinimumLevel.Debug()
.WriteTo.Console()
.CreateLogger();
}

_isInitialized = true;
Expand Down
8 changes: 4 additions & 4 deletions Core/Resgrid.Framework/Resgrid.Framework.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
<PackageReference Include="HtmlAgilityPack" Version="1.11.59" />
<PackageReference Include="NodaTime" Version="3.1.11" />
<PackageReference Include="protobuf-net" Version="3.2.30" />
<PackageReference Include="Sentry" Version="4.6.2" />
<PackageReference Include="Sentry.Serilog" Version="4.6.2" />
<PackageReference Include="Serilog" Version="3.1.1" />
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="10.0.0" />
<PackageReference Include="Sentry" Version="4.10.2" />
<PackageReference Include="Sentry.Serilog" Version="4.10.2" />
<PackageReference Include="Serilog" Version="4.0.1" />
<PackageReference Include="Serilog.Sinks.Console" Version="6.0.0" />
<PackageReference Include="TimeZoneConverter" Version="6.1.0" />
<PackageReference Include="Vereyon.Web.HtmlSanitizer" Version="1.8.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
Expand Down
23 changes: 23 additions & 0 deletions Core/Resgrid.Model/Events/SecurityRefreshEvent.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using ProtoBuf;
using System;

namespace Resgrid.Model.Events
{
[ProtoContract]
public class SecurityRefreshEvent
{
[ProtoMember(1)]
public string EventId { get; set; }

[ProtoMember(2)]
public int DepartmentId { get; set; }

[ProtoMember(3)]
public SecurityCacheTypes Type { get; set; }

public SecurityRefreshEvent()
{
EventId = Guid.NewGuid().ToString();
}
}
}
3 changes: 2 additions & 1 deletion Core/Resgrid.Model/PermissionTypes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ public enum PermissionTypes
ViewGroupUsers,
DeleteCall,
CloseCall,
AddCallData
AddCallData,
ViewGroupUnits
}

}
1 change: 1 addition & 0 deletions Core/Resgrid.Model/Providers/ICacheProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public interface ICacheProvider
bool IsConnected();
Task<bool> SetStringAsync(string cacheKey, string value, TimeSpan expiration);
Task<string> GetStringAsync(string cacheKey);
Task<T> GetAsync<T>(string cacheKey) where T : class;
}
}
1 change: 1 addition & 0 deletions Core/Resgrid.Model/Providers/IOutboundQueueProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public interface IOutboundQueueProvider
Task<bool> EnqueueShiftNotification(ShiftQueueItem shiftQueueItem);
Task<bool> EnqueueDistributionList(DistributionListQueueItem distributionListQueue);
Task<bool> EnqueueAuditEvent(AuditEvent auditEvent);
Task<bool> EnqueueSecurityRefreshEvent(SecurityRefreshEvent securityRefreshEvent);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,20 @@ public interface IDepartmentGroupMembersRepository: IRepository<DepartmentGroupM
Task<IEnumerable<DepartmentGroupMember>> GetAllGroupMembersByUserAndDepartmentAsync(string userId,
int departmentId);

/// <summary>
/// Delete group by group identifier asynchronous.
/// </summary>
/// <param name="groupId">The group identifier.</param>
/// <param name="departmentId">The department identifier.</param>
/// <returns>Task&lt;IEnumerable&lt;DepartmentGroupMember&gt;&gt;.</returns>
Task<bool> DeleteGroupMembersByGroupIdAsync(int groupId, int departmentId, CancellationToken cancellationToken = default(CancellationToken));


/// <summary>
/// Gets all group admins department asynchronous.
/// </summary>
/// <param name="departmentId">The department identifier.</param>
/// <returns>Task&lt;IEnumerable&lt;DepartmentGroupMember&gt;&gt;.</returns>
Task<IEnumerable<DepartmentGroupMember>> GetAllGroupAdminsByDepartmentIdAsync(int departmentId);
}
}
2 changes: 1 addition & 1 deletion Core/Resgrid.Model/Resgrid.Model.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
<PackageReference Include="GeoCoordinate.NetCore" Version="1.0.0.1" />
<PackageReference Include="GeoJSON.Net" Version="1.2.19" />
<PackageReference Include="Microsoft.AspNetCore.Identity" Version="2.2.0" />
<PackageReference Include="MimeKit" Version="4.4.0" />
<PackageReference Include="MimeKit" Version="4.7.1" />
<PackageReference Include="MongoDB.Driver" Version="2.24.0" />
<PackageReference Include="protobuf-net" Version="3.2.30" />
<PackageReference Include="Stripe.net" Version="45.1.0" />
Expand Down
10 changes: 10 additions & 0 deletions Core/Resgrid.Model/SecurityCacheTypes.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Resgrid.Model
{
public enum SecurityCacheTypes
{
WhoCanViewUnits = 1,
WhoCanViewUnitLocations = 2,
WhoCanViewPersonnel = 3,
WhoCanViewPersonnelLocations = 4,
}
}
8 changes: 8 additions & 0 deletions Core/Resgrid.Model/Services/IAuthorizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -308,5 +308,13 @@ public interface IAuthorizationService
Task<bool> CanUserAddNoteAsync(string userId);

Task<bool> CanUserEditNoteAsync(string userId, int noteId);

Task<bool> CanUserViewPersonViaMatrixAsync(string userToView, string userId, int departmentId);

Task<bool> CanUserViewPersonLocationViaMatrixAsync(string userToView, string userId, int departmentId);

Task<bool> CanUserViewUnitViaMatrixAsync(int unitToView, string userId, int departmentId);

Task<bool> CanUserViewUnitLocationViaMatrixAsync(int unitToView, string userId, int departmentId);
}
}
2 changes: 2 additions & 0 deletions Core/Resgrid.Model/Services/IDepartmentGroupsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -224,5 +224,7 @@ Task<DepartmentGroupMember> MoveUserIntoGroupAsync(string userId, int groupId, b
Task<List<DepartmentGroup>> GetAllGroupsForDepartmentUnlimitedThinAsync(int departmentId);

Task<bool> DeleteAllMembersFromGroupAsync(DepartmentGroup departmentGroup, CancellationToken cancellationToken = default(CancellationToken));

Task<List<DepartmentGroupMember>> GetAllGroupAdminsByDepartmentIdAsync(int departmentId);
}
}
15 changes: 15 additions & 0 deletions Core/Resgrid.Model/VisibilityPayloadUnits.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using ProtoBuf;
using System.Collections.Generic;

namespace Resgrid.Model
{
[ProtoContract]
public class VisibilityPayloadUnits
{
[ProtoMember(1)]
public bool EveryoneNoGroupLock { get; set; }

[ProtoMember(2)]
public Dictionary<int, List<string>> Units { get; set; }
}
}
16 changes: 16 additions & 0 deletions Core/Resgrid.Model/VisibilityPayloadUsers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using ProtoBuf;
using System.Collections.Generic;


namespace Resgrid.Model
{
[ProtoContract]
public class VisibilityPayloadUsers
{
[ProtoMember(1)]
public bool EveryoneNoGroupLock { get; set; }

[ProtoMember(2)]
public Dictionary<string, List<string>> Users { get; set; }
}
}
100 changes: 99 additions & 1 deletion Core/Resgrid.Services/AuthorizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.VisualBasic;
using MongoDB.Driver;
using Resgrid.Model;
using Resgrid.Model.Providers;
using Resgrid.Model.Services;

namespace Resgrid.Services
Expand All @@ -27,12 +29,19 @@ public class AuthorizationService : IAuthorizationService
private readonly ICertificationService _certificationService;
private readonly IDocumentsService _documentsService;
private readonly INotesService _notesService;
private readonly ICacheProvider _cacheProvider;

private static string WhoCanViewUnitsCacheKey = "ViewUnitsSecurityMaxtix_{0}";
private static string WhoCanViewUnitLocationsCacheKey = "ViewUnitLocationsSecurityMaxtix_{0}";
private static string WhoCanViewPersonnelCacheKey = "ViewUsersSecurityMaxtix_{0}";
private static string WhoCanViewPersonnelLocationsCacheKey = "ViewUserLocationsSecurityMaxtix_{0}";

public AuthorizationService(IDepartmentsService departmentsService, IInvitesService invitesService,
ICallsService callsService, IMessageService messageService, IWorkLogsService workLogsService, ISubscriptionsService subscriptionsService,
IDepartmentGroupsService departmentGroupsService, IPersonnelRolesService personnelRolesService, IUnitsService unitsService,
IPermissionsService permissionsService, ICalendarService calendarService, IProtocolsService protocolsService,
IShiftsService shiftsService, ICustomStateService customStateService, ICertificationService certificationService, IDocumentsService documentsService, INotesService notesService)
IShiftsService shiftsService, ICustomStateService customStateService, ICertificationService certificationService,
IDocumentsService documentsService, INotesService notesService, ICacheProvider cacheProvider)
{
_departmentsService = departmentsService;
_invitesService = invitesService;
Expand All @@ -51,6 +60,7 @@ public AuthorizationService(IDepartmentsService departmentsService, IInvitesServ
_certificationService = certificationService;
_documentsService = documentsService;
_notesService = notesService;
_cacheProvider = cacheProvider;
}
#endregion Private Members and Constructors

Expand Down Expand Up @@ -1188,5 +1198,93 @@ public async Task<bool> CanUserEditNoteAsync(string userId, int noteId)

return false;
}

public async Task<bool> CanUserViewPersonViaMatrixAsync(string userToView, string userId, int departmentId)
{
var matrix = await _cacheProvider.GetAsync<VisibilityPayloadUsers>(string.Format(WhoCanViewPersonnelCacheKey, departmentId));

// Fail open if the cache is not available for now. -SJ 8-26-2024
if (matrix == null)
return true;

if (matrix.EveryoneNoGroupLock)
return true;

if (!matrix.Users.ContainsKey(userToView))
return true;

var userViewList = matrix.Users[userToView];

if (userViewList.Contains(userId))
return true;

return false;
}

public async Task<bool> CanUserViewPersonLocationViaMatrixAsync(string userToView, string userId, int departmentId)
{
var matrix = await _cacheProvider.GetAsync<VisibilityPayloadUsers>(string.Format(WhoCanViewPersonnelLocationsCacheKey, departmentId));

// Fail open if the cache is not available for now. -SJ 8-26-2024
if (matrix == null)
return true;

if (matrix.EveryoneNoGroupLock)
return true;

if (!matrix.Users.ContainsKey(userToView))
return true;

var userViewList = matrix.Users[userToView];

if (userViewList.Contains(userId))
return true;

return false;
}

public async Task<bool> CanUserViewUnitViaMatrixAsync(int unitToView, string userId, int departmentId)
{
var matrix = await _cacheProvider.GetAsync<VisibilityPayloadUnits>(string.Format(WhoCanViewUnitsCacheKey, departmentId));

// Fail open if the cache is not available for now. -SJ 8-26-2024
if (matrix == null)
return true;

if (matrix.EveryoneNoGroupLock)
return true;

if (!matrix.Units.ContainsKey(unitToView))
return true;

var userViewList = matrix.Units[unitToView];

if (userViewList.Contains(userId))
return true;

return false;
}

public async Task<bool> CanUserViewUnitLocationViaMatrixAsync(int unitToView, string userId, int departmentId)
{
var matrix = await _cacheProvider.GetAsync<VisibilityPayloadUnits>(string.Format(WhoCanViewUnitLocationsCacheKey, departmentId));

// Fail open if the cache is not available for now. -SJ 8-26-2024
if (matrix == null)
return true;

if (matrix.EveryoneNoGroupLock)
return true;

if (!matrix.Units.ContainsKey(unitToView))
return true;

var userViewList = matrix.Units[unitToView];

if (userViewList.Contains(userId))
return true;

return false;
}
}
}
Loading

0 comments on commit 1ead6ab

Please sign in to comment.