Skip to content

Commit

Permalink
Merge pull request #152 from Resgrid/develop
Browse files Browse the repository at this point in the history
CU-3wen6jw adding permission checks for users
  • Loading branch information
ucswift authored Sep 7, 2024
2 parents 6aae0cd + 87ce6c6 commit 923c2b6
Show file tree
Hide file tree
Showing 17 changed files with 331 additions and 99 deletions.
2 changes: 2 additions & 0 deletions Core/Resgrid.Model/Services/IAuthorizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -316,5 +316,7 @@ public interface IAuthorizationService
Task<bool> CanUserViewUnitViaMatrixAsync(int unitToView, string userId, int departmentId);

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

Task<bool> CanUserViewAllPeopleAsync(string userId, int departmentId);
}
}
71 changes: 71 additions & 0 deletions Core/Resgrid.Services/AuthorizationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,71 @@ where roleIds.Contains(r.PersonnelRoleId)
return false;
}

/// <summary>
/// Purpose of this method is to determine if a user can view all people in a department. This is used for the personnel lists where we have an "All" option.
/// </summary>
/// <param name="userId"></param>
/// <param name="departmentId"></param>
/// <returns></returns>
public async Task<bool> CanUserViewAllPeopleAsync(string userId, int departmentId)
{
var permission = await _permissionsService.GetPermissionByDepartmentTypeAsync(departmentId, PermissionTypes.ViewGroupUsers);

if (permission == null)
return true;

bool isGroupAdmin = false;
var group = await _departmentGroupsService.GetGroupForUserAsync(userId, departmentId);

var roles = await _personnelRolesService.GetRolesForUserAsync(userId, departmentId);
var department = await _departmentsService.GetDepartmentByIdAsync(departmentId);

if (group != null)
isGroupAdmin = group.IsUserGroupAdmin(userId);

if (permission.Action == (int)PermissionActions.DepartmentAdminsOnly && department.IsUserAnAdmin(userId))
{ // Department Admins only
return true;
}
else if (permission.Action == (int)PermissionActions.DepartmentAndGroupAdmins && !permission.LockToGroup && (department.IsUserAnAdmin(userId) || isGroupAdmin))
{ // Department and group Admins (not locked to group)
return true;
}
else if (permission.Action == (int)PermissionActions.DepartmentAndGroupAdmins && permission.LockToGroup && (department.IsUserAnAdmin(userId) || isGroupAdmin))
{ // Department and group Admins (locked to group)
return true; // Department Admins have access.
}
else if (permission.Action == (int)PermissionActions.DepartmentAdminsAndSelectRoles && department.IsUserAnAdmin(userId))
{
return true;
}
else if (permission.Action == (int)PermissionActions.DepartmentAdminsAndSelectRoles && !department.IsUserAnAdmin(userId))
{
if (permission.LockToGroup)
return false;

if (!String.IsNullOrWhiteSpace(permission.Data))
{
var roleIds = permission.Data.Split(char.Parse(",")).Select(int.Parse);
var role = from r in roles
where roleIds.Contains(r.PersonnelRoleId)
select r;

if (role.Any())
{
return true;
}
}

}
else if (permission.Action == (int)PermissionActions.Everyone && !permission.LockToGroup)
{
return true;
}

return false;
}

public async Task<bool> CanUserDeleteCallAsync(string userId, int callId, int departmentId)
{
var permission = await _permissionsService.GetPermissionByDepartmentTypeAsync(departmentId, PermissionTypes.DeleteCall);
Expand Down Expand Up @@ -1210,6 +1275,9 @@ public async Task<bool> CanUserViewPersonViaMatrixAsync(string userToView, strin
if (matrix.EveryoneNoGroupLock)
return true;

if (userToView == userId)
return true;

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

Expand All @@ -1232,6 +1300,9 @@ public async Task<bool> CanUserViewPersonLocationViaMatrixAsync(string userToVie
if (matrix.EveryoneNoGroupLock)
return true;

if (userToView == userId)
return true;

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

Expand Down
109 changes: 74 additions & 35 deletions Core/Resgrid.Services/SubscriptionsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,13 @@
using System.Threading;
using System.Threading.Tasks;
using MongoDB.Driver;
using Resgrid.Config;
using Resgrid.Framework;
using Resgrid.Model;
using Resgrid.Model.Billing.Api;
using Resgrid.Model.Providers;
using Resgrid.Model.Repositories;
using Resgrid.Model.Services;
using Resgrid.Providers.Voip.LiveKit;
using Resgrid.Providers.Voip.LiveKit.Model;
using RestSharp;
using RestSharp.Serializers.NewtonsoftJson;
using Stripe;
using Stripe.Checkout;

namespace Resgrid.Services
{
Expand Down Expand Up @@ -61,7 +55,12 @@ public SubscriptionsService(IPlansRepository plansRepository, IPaymentRepository

if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetCurrentPlanForDepartment", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand All @@ -85,7 +84,12 @@ public async Task<DepartmentPlanCount> GetPlanCountsForDepartmentAsync(int depar
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};
var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());

var request = new RestRequest($"/api/Billing/GetPlanCountsForDepartment", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand All @@ -109,7 +113,12 @@ public async Task<Payment> GetCurrentPaymentForDepartmentAsync(int departmentId,
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetCurrentPaymentForDepartment", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -154,7 +163,12 @@ public async Task<Payment> GetPreviousNonFreePaymentForDepartmentAsync(int depar
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetPreviousNonFreePaymentForDepartment", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -185,7 +199,12 @@ public async Task<Payment> GetUpcomingPaymentForDepartmentAsync(int departmentId
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetUpcomingPaymentForDepartment", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -214,7 +233,12 @@ public async Task<Payment> GetPaymentByTransactionIdAsync(string transactionId)
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetPaymentByTransactionId", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand All @@ -238,7 +262,12 @@ public async Task<Payment> GetPaymentByTransactionIdAsync(string transactionId)
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetPlanById", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -272,7 +301,12 @@ public async Task<Payment> GetPaymentByTransactionIdAsync(string transactionId)
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetPlanByExternalId", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -308,7 +342,12 @@ public async Task<Payment> GetPaymentByIdAsync(int paymentId)
{
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
var client = new RestClient(Config.SystemBehaviorConfig.BillingApiBaseUrl, configureSerialization: s => s.UseNewtonsoftJson());
var options = new RestClientOptions(Config.SystemBehaviorConfig.BillingApiBaseUrl)
{
MaxTimeout = 200000 // ms
};

var client = new RestClient(options, configureSerialization: s => s.UseNewtonsoftJson());
var request = new RestRequest($"/api/Billing/GetPaymentById", Method.Get);
request.AddHeader("X-API-Key", Config.ApiConfig.BackendInternalApikey);
request.AddHeader("Content-Type", "application/json");
Expand Down Expand Up @@ -349,26 +388,26 @@ public bool CanPlanSendMessageSms(int planId)
if (!String.IsNullOrWhiteSpace(Config.SystemBehaviorConfig.BillingApiBaseUrl) && !String.IsNullOrWhiteSpace(Config.ApiConfig.BackendInternalApikey))
{
if (planId == 4 // Professional
|| planId == 5 // Ultimate
|| planId == 9 // Unlimited
|| planId == 10 // Enterprise
|| planId == 14 // Professional Monthly
|| planId == 15 // Ultimate Monthly
|| planId == 16 // Enterprise Monthly
|| planId == 17 // Enterprise+
|| planId == 18 // Enterprise+ Monthly
|| planId == 20 // Univeral
|| planId == 21 // Univeral Monthly
|| planId == 26 // Professional
|| planId == 27 // Professional Monthly
|| planId == 28 // Ultimate
|| planId == 29 // Ultimate Monthly
|| planId == 30 // Enterprise
|| planId == 31 // Enterprise Monthly
|| planId == 32 // Enterprise+
|| planId == 32 // Enterprise+ Monthly
|| planId == 34 // Unified
|| planId == 35 // Unified Monthly
|| planId == 5 // Ultimate
|| planId == 9 // Unlimited
|| planId == 10 // Enterprise
|| planId == 14 // Professional Monthly
|| planId == 15 // Ultimate Monthly
|| planId == 16 // Enterprise Monthly
|| planId == 17 // Enterprise+
|| planId == 18 // Enterprise+ Monthly
|| planId == 20 // Univeral
|| planId == 21 // Univeral Monthly
|| planId == 26 // Professional
|| planId == 27 // Professional Monthly
|| planId == 28 // Ultimate
|| planId == 29 // Ultimate Monthly
|| planId == 30 // Enterprise
|| planId == 31 // Enterprise Monthly
|| planId == 32 // Enterprise+
|| planId == 32 // Enterprise+ Monthly
|| planId == 34 // Unified
|| planId == 35 // Unified Monthly
)
return true;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public async Task<Department> GetDepartmentWithMembersByIdAsync(int departmentId
if (department != null && department.Members != null)
{
department.AdminUsers = new List<string>();
department.AdminUsers.Add(department.ManagingUserId);
foreach (var member in department.Members)
{
if (member.IsAdmin.GetValueOrDefault())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public async Task<DepartmentPlanCount> GetDepartmentPlanCountsByDepartmentIdAsyn
}
catch (Exception ex)
{
Logging.LogException(ex);
Logging.LogException(ex, extraMessage: $"GetDepartmentPlanCountsByDepartmentIdAsync DepartmentId: {departmentId}");

throw;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,9 @@ public async Task<ActionResult<GetAllPersonnelInfosResult>> GetAllPersonnelInfos

foreach (var u in users)
{
if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(u.UserId, UserId, DepartmentId))
continue;

var log = (from l in actionLogs
where l.UserId == u.UserId
select l).FirstOrDefault();
Expand Down
10 changes: 10 additions & 0 deletions Web/Resgrid.Web.ServicesCore/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using System.Threading;
using Autofac.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Resgrid.Config;
Expand All @@ -29,6 +30,15 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
})
.ConfigureWebHostDefaults(webBuilder =>
{
var builder = new Microsoft.Extensions.Configuration.ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: false)
.AddEnvironmentVariables();
var config = builder.Build();
bool configResult = ConfigProcessor.LoadAndProcessConfig(config["AppOptions:ConfigPath"]);
bool envConfigResult = ConfigProcessor.LoadAndProcessEnvVariables(config.AsEnumerable());
if (!string.IsNullOrWhiteSpace(Config.ExternalErrorConfig.ExternalErrorServiceUrlForApi))
{
webBuilder.UseSentry(options =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<DeleteExistingFiles>True</DeleteExistingFiles>
<ExcludeApp_Data>False</ExcludeApp_Data>
<LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
<DeleteExistingFiles>true</DeleteExistingFiles>
<ExcludeApp_Data>false</ExcludeApp_Data>
<LaunchSiteAfterPublish>true</LaunchSiteAfterPublish>
<LastUsedBuildConfiguration>Debug</LastUsedBuildConfiguration>
<LastUsedPlatform>Any CPU</LastUsedPlatform>
<PublishProvider>FileSystem</PublishProvider>
<PublishUrl>bin\Release\netcoreapp3.1\publish\</PublishUrl>
<PublishUrl>G:\Resgrid\_RGApi</PublishUrl>
<WebPublishMethod>FileSystem</WebPublishMethod>
<SiteUrlToLaunchAfterPublish />
<TargetFramework>net5.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<ProjectGuid>24e2241d-d82c-443d-9613-f900e44c003e</ProjectGuid>
<SelfContained>true</SelfContained>
Expand Down
3 changes: 1 addition & 2 deletions Web/Resgrid.Web.ServicesCore/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"AppOptions": {
"ConfigPath": null
"ConfigPath": "C:\\Resgrid\\Config\\ResgridConfig.json"
},
"ConnectionStrings": {
"ResgridContext": "Server=rgdevserver;Database=Resgrid;User Id=resgrid_app;Password=resgrid123;MultipleActiveResultSets=True;TrustServerCertificate=True;"
},
"Logging": {
"IncludeScopes": false,
Expand Down
3 changes: 1 addition & 2 deletions Web/Resgrid.Web.ServicesCore/appsettings.Production.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"AppOptions": {
"ConfigPath": null
"ConfigPath": "C:\\Resgrid\\Config\\ResgridConfig.json"
},
"ConnectionStrings": {
"ResgridContext": "Server=rgdevserver;Database=Resgrid;User Id=resgrid_app;Password=resgrid123;MultipleActiveResultSets=True;TrustServerCertificate=True;"
},
"Logging": {
"IncludeScopes": false,
Expand Down
Loading

0 comments on commit 923c2b6

Please sign in to comment.