diff --git a/Core/Resgrid.Model/Services/IAuthorizationService.cs b/Core/Resgrid.Model/Services/IAuthorizationService.cs index 32a2391b..0c0c41d4 100644 --- a/Core/Resgrid.Model/Services/IAuthorizationService.cs +++ b/Core/Resgrid.Model/Services/IAuthorizationService.cs @@ -316,5 +316,7 @@ public interface IAuthorizationService Task CanUserViewUnitViaMatrixAsync(int unitToView, string userId, int departmentId); Task CanUserViewUnitLocationViaMatrixAsync(int unitToView, string userId, int departmentId); + + Task CanUserViewAllPeopleAsync(string userId, int departmentId); } } diff --git a/Core/Resgrid.Services/AuthorizationService.cs b/Core/Resgrid.Services/AuthorizationService.cs index 82449a3a..2f4b0c82 100644 --- a/Core/Resgrid.Services/AuthorizationService.cs +++ b/Core/Resgrid.Services/AuthorizationService.cs @@ -775,6 +775,71 @@ where roleIds.Contains(r.PersonnelRoleId) return false; } + /// + /// 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. + /// + /// + /// + /// + public async Task 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 CanUserDeleteCallAsync(string userId, int callId, int departmentId) { var permission = await _permissionsService.GetPermissionByDepartmentTypeAsync(departmentId, PermissionTypes.DeleteCall); @@ -1210,6 +1275,9 @@ public async Task CanUserViewPersonViaMatrixAsync(string userToView, strin if (matrix.EveryoneNoGroupLock) return true; + if (userToView == userId) + return true; + if (!matrix.Users.ContainsKey(userToView)) return true; @@ -1232,6 +1300,9 @@ public async Task CanUserViewPersonLocationViaMatrixAsync(string userToVie if (matrix.EveryoneNoGroupLock) return true; + if (userToView == userId) + return true; + if (!matrix.Users.ContainsKey(userToView)) return true; diff --git a/Core/Resgrid.Services/SubscriptionsService.cs b/Core/Resgrid.Services/SubscriptionsService.cs index faa55529..0a94b673 100644 --- a/Core/Resgrid.Services/SubscriptionsService.cs +++ b/Core/Resgrid.Services/SubscriptionsService.cs @@ -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 { @@ -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"); @@ -85,7 +84,12 @@ public async Task 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"); @@ -109,7 +113,12 @@ public async Task 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"); @@ -154,7 +163,12 @@ public async Task 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"); @@ -185,7 +199,12 @@ public async Task 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"); @@ -214,7 +233,12 @@ public async Task 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"); @@ -238,7 +262,12 @@ public async Task 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"); @@ -272,7 +301,12 @@ public async Task 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"); @@ -308,7 +342,12 @@ public async Task 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"); @@ -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; diff --git a/Repositories/Resgrid.Repositories.DataRepository/DepartmentsRepository.cs b/Repositories/Resgrid.Repositories.DataRepository/DepartmentsRepository.cs index 87c00742..8c0b89e4 100644 --- a/Repositories/Resgrid.Repositories.DataRepository/DepartmentsRepository.cs +++ b/Repositories/Resgrid.Repositories.DataRepository/DepartmentsRepository.cs @@ -59,6 +59,7 @@ public async Task GetDepartmentWithMembersByIdAsync(int departmentId if (department != null && department.Members != null) { department.AdminUsers = new List(); + department.AdminUsers.Add(department.ManagingUserId); foreach (var member in department.Members) { if (member.IsAdmin.GetValueOrDefault()) diff --git a/Repositories/Resgrid.Repositories.DataRepository/PaymentRepository.cs b/Repositories/Resgrid.Repositories.DataRepository/PaymentRepository.cs index 6b20c231..f25d4ad8 100644 --- a/Repositories/Resgrid.Repositories.DataRepository/PaymentRepository.cs +++ b/Repositories/Resgrid.Repositories.DataRepository/PaymentRepository.cs @@ -66,7 +66,7 @@ public async Task GetDepartmentPlanCountsByDepartmentIdAsyn } catch (Exception ex) { - Logging.LogException(ex); + Logging.LogException(ex, extraMessage: $"GetDepartmentPlanCountsByDepartmentIdAsync DepartmentId: {departmentId}"); throw; } diff --git a/Web/Resgrid.Web.ServicesCore/Controllers/v4/PersonnelController.cs b/Web/Resgrid.Web.ServicesCore/Controllers/v4/PersonnelController.cs index b05631cb..a11b13bc 100644 --- a/Web/Resgrid.Web.ServicesCore/Controllers/v4/PersonnelController.cs +++ b/Web/Resgrid.Web.ServicesCore/Controllers/v4/PersonnelController.cs @@ -141,6 +141,9 @@ public async Task> 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(); diff --git a/Web/Resgrid.Web.ServicesCore/Program.cs b/Web/Resgrid.Web.ServicesCore/Program.cs index 48f86bff..763b7df7 100644 --- a/Web/Resgrid.Web.ServicesCore/Program.cs +++ b/Web/Resgrid.Web.ServicesCore/Program.cs @@ -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; @@ -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 => diff --git a/Web/Resgrid.Web.ServicesCore/Properties/PublishProfiles/FolderProfile1.pubxml b/Web/Resgrid.Web.ServicesCore/Properties/PublishProfiles/FolderProfile1.pubxml index 649a84a3..c3336b5d 100644 --- a/Web/Resgrid.Web.ServicesCore/Properties/PublishProfiles/FolderProfile1.pubxml +++ b/Web/Resgrid.Web.ServicesCore/Properties/PublishProfiles/FolderProfile1.pubxml @@ -4,16 +4,16 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - True - False - True - Release + true + false + true + Debug Any CPU FileSystem - bin\Release\netcoreapp3.1\publish\ + G:\Resgrid\_RGApi FileSystem - net5.0 + net8.0 win-x64 24e2241d-d82c-443d-9613-f900e44c003e true diff --git a/Web/Resgrid.Web.ServicesCore/appsettings.Development.json b/Web/Resgrid.Web.ServicesCore/appsettings.Development.json index 925dacdc..704633ff 100644 --- a/Web/Resgrid.Web.ServicesCore/appsettings.Development.json +++ b/Web/Resgrid.Web.ServicesCore/appsettings.Development.json @@ -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, diff --git a/Web/Resgrid.Web.ServicesCore/appsettings.Production.json b/Web/Resgrid.Web.ServicesCore/appsettings.Production.json index 77cdf49d..75b14501 100644 --- a/Web/Resgrid.Web.ServicesCore/appsettings.Production.json +++ b/Web/Resgrid.Web.ServicesCore/appsettings.Production.json @@ -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, diff --git a/Web/Resgrid.Web.ServicesCore/appsettings.Staging.json b/Web/Resgrid.Web.ServicesCore/appsettings.Staging.json index bed3323f..75b14501 100644 --- a/Web/Resgrid.Web.ServicesCore/appsettings.Staging.json +++ b/Web/Resgrid.Web.ServicesCore/appsettings.Staging.json @@ -1,16 +1,15 @@ { - "AppOptions": { - "ConfigPath": null - }, + "AppOptions": { + "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, - "LogLevel": { - "Default": "Debug", - "System": "Information", - "Microsoft": "Information" - } + "Logging": { + "IncludeScopes": false, + "LogLevel": { + "Default": "Debug", + "System": "Information", + "Microsoft": "Information" } + } } diff --git a/Web/Resgrid.Web.ServicesCore/appsettings.json b/Web/Resgrid.Web.ServicesCore/appsettings.json index 3bc0d755..56d6530d 100644 --- a/Web/Resgrid.Web.ServicesCore/appsettings.json +++ b/Web/Resgrid.Web.ServicesCore/appsettings.json @@ -1,6 +1,8 @@ { + "AppOptions": { + "ConfigPath": "C:\\Resgrid\\Config\\ResgridConfig.json" + }, "ConnectionStrings": { - "AuthorizationDbContext": "Server=rgdevserver;Database=ResgridOIDC;User Id=resgrid_odic;Password=resgrid123;MultipleActiveResultSets=True;TrustServerCertificate=True;" }, "Logging": { "LogLevel": { diff --git a/Web/Resgrid.WebCore/Areas/User/Controllers/HomeController.cs b/Web/Resgrid.WebCore/Areas/User/Controllers/HomeController.cs index 47467771..b359b8de 100644 --- a/Web/Resgrid.WebCore/Areas/User/Controllers/HomeController.cs +++ b/Web/Resgrid.WebCore/Areas/User/Controllers/HomeController.cs @@ -163,6 +163,9 @@ public async Task GetUserStatusTable() foreach (var u in membersToProcess) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(u.UserId, UserId, DepartmentId)) + continue; + if (allUsers.Any(x => x.UserId == u.UserId)) { groupedUserIds.Add(u.UserId); @@ -240,6 +243,9 @@ public async Task GetUserStatusTable() unGroupedUsersGroup.Group = null; foreach (var u in ungroupedUsers) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(u.UserId, UserId, DepartmentId)) + continue; + model.UnGroupedUsers.Add(u.UserId); UserState state = userStates.FirstOrDefault(x => x.UserId == u.UserId); @@ -735,9 +741,6 @@ public async Task EditUserProfile(EditProfileModel model, IFormCo await _departmentsService.SaveDepartmentMemberAsync(depMember, cancellationToken); } - if (!model.Profile.DoNotRecieveNewsletters) - await Unsubscribe(model.Email); - _usersService.UpdateEmail(model.User.Id, model.Email); if (model.IsOwnProfile) @@ -878,21 +881,5 @@ public async Task SetActionForUser(string userId, int actionType) return RedirectToAction("Dashboard", "Home", new { area = "User" }); } #endregion User Actions - - private async Task Unsubscribe(string emailAddress) - { - //try - //{ - // var client = new RestClient("https://app.mailerlite.com"); - // var request = new RestRequest("/api/v1/subscribers/unsubscribe/", Method.Post); - // request.AddObject(new - // { - // apiKey = "QDrnoEf6hBONlGye26aZFh5Iv1KEgdJM", - // email = emailAddress - // }); - // var response = await client.ExecuteAsync(request); - //} - //catch { } - } } } diff --git a/Web/Resgrid.WebCore/Areas/User/Controllers/PersonnelController.cs b/Web/Resgrid.WebCore/Areas/User/Controllers/PersonnelController.cs index b8f50e94..18afec61 100644 --- a/Web/Resgrid.WebCore/Areas/User/Controllers/PersonnelController.cs +++ b/Web/Resgrid.WebCore/Areas/User/Controllers/PersonnelController.cs @@ -124,6 +124,9 @@ public async Task Index() foreach (var user in users) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(user.UserId, UserId, DepartmentId)) + continue; + var person = new PersonnelForListJson(); person.UserId = user.UserId.ToString(); diff --git a/Web/Resgrid.WebCore/Areas/User/Controllers/ReportsController.cs b/Web/Resgrid.WebCore/Areas/User/Controllers/ReportsController.cs index 1a36895f..47826343 100644 --- a/Web/Resgrid.WebCore/Areas/User/Controllers/ReportsController.cs +++ b/Web/Resgrid.WebCore/Areas/User/Controllers/ReportsController.cs @@ -3,6 +3,7 @@ using System.Globalization; using System.Linq; using System.Text; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; @@ -289,10 +290,19 @@ public async Task PersonnelHoursReportParams() department); var profiles = new List(); - profiles.Add(new UserProfile() { UserId = String.Empty, FirstName = "All", LastName = "Users" }); - profiles.AddRange( - (await _userProfileService.GetAllProfilesForDepartmentAsync(DepartmentId)).Select(x => x.Value)); + if (await _authorizationService.CanUserViewAllPeopleAsync(UserId, DepartmentId)) + profiles.Add(new UserProfile() { UserId = String.Empty, FirstName = "All", LastName = "Users" }); + + var users = await _userProfileService.GetAllProfilesForDepartmentAsync(DepartmentId); + foreach (var u in users) + { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(u.Key, UserId, DepartmentId)) + continue; + + profiles.Add(u.Value); + } + model.Users = new SelectList(profiles, "UserId", "FullName.AsFirstNameLastName", Guid.Empty); return View(model); @@ -322,14 +332,30 @@ public async Task PersonnelStaffingHistoryReportParams() department); var profiles = new List(); - profiles.Add(new UserProfile() { UserId = String.Empty, FirstName = "All", LastName = "Users" }); - profiles.AddRange( - (await _userProfileService.GetAllProfilesForDepartmentAsync(DepartmentId)).Select(x => x.Value)); + if (await _authorizationService.CanUserViewAllPeopleAsync(UserId, DepartmentId)) + profiles.Add(new UserProfile() { UserId = String.Empty, FirstName = "All", LastName = "Users" }); + + var users = await _userProfileService.GetAllProfilesForDepartmentAsync(DepartmentId); + foreach (var u in users) + { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(u.Key, UserId, DepartmentId)) + continue; + + profiles.Add(u.Value); + } + model.Users = new SelectList(profiles, "UserId", "FullName.AsFirstNameLastName", Guid.Empty); - var groups = await _departmentGroupsService.GetAllGroupsForDepartmentAsync(DepartmentId); - model.Groups = new SelectList(groups, "DepartmentGroupId", "Name", 0); + if (await _authorizationService.CanUserViewAllPeopleAsync(UserId, DepartmentId)) + { + var groups = await _departmentGroupsService.GetAllGroupsForDepartmentAsync(DepartmentId); + model.Groups = new SelectList(groups, "DepartmentGroupId", "Name", 0); + } + else + { + model.Groups = new SelectList(new List(), "DepartmentGroupId", "Name", 0); + } return View(model); } @@ -406,14 +432,29 @@ public async Task ActionLogsParams() department); var profiles = new List(); - profiles.Add(new UserProfile() { UserId = String.Empty, FirstName = "All", LastName = "Users" }); + if (await _authorizationService.CanUserViewAllPeopleAsync(UserId, DepartmentId)) + profiles.Add(new UserProfile() { UserId = String.Empty, FirstName = "All", LastName = "Users" }); + + var users = await _userProfileService.GetAllProfilesForDepartmentAsync(DepartmentId); + foreach (var u in users) + { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(u.Key, UserId, DepartmentId)) + continue; + + profiles.Add(u.Value); + } - profiles.AddRange( - (await _userProfileService.GetAllProfilesForDepartmentAsync(DepartmentId)).Select(x => x.Value)); model.Users = new SelectList(profiles, "UserId", "FullName.AsFirstNameLastName", Guid.Empty); - var groups = await _departmentGroupsService.GetAllGroupsForDepartmentAsync(DepartmentId); - model.Groups = new SelectList(groups, "DepartmentGroupId", "Name", 0); + if (await _authorizationService.CanUserViewAllPeopleAsync(UserId, DepartmentId)) + { + var groups = await _departmentGroupsService.GetAllGroupsForDepartmentAsync(DepartmentId); + model.Groups = new SelectList(groups, "DepartmentGroupId", "Name", 0); + } + else + { + model.Groups = new SelectList(new List(), "DepartmentGroupId", "Name", 0); + } return View(model); } @@ -499,6 +540,9 @@ private async Task CreateStaffingReportModel(int departmentI foreach (var user in users) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(user.UserId, UserId, DepartmentId)) + continue; + var person = new StaffingReportRow(); var group = await _departmentGroupsService.GetGroupForUserAsync(user.UserId, DepartmentId); var staffing = await _userStateService.GetLastUserStateByUserIdAsync(user.UserId); @@ -626,6 +670,9 @@ private async Task CreatePersonnelReportModel(int departmen { var departmentUser = await _departmentsService.GetDepartmentMemberAsync(user.UserId, DepartmentId, false); + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(user.UserId, UserId, DepartmentId)) + continue; + if (departmentUser != null) { var person = new PersonnelReportRow(); @@ -707,6 +754,9 @@ private async Task CreateCertificationsReportModel(int foreach (var user in users) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(user.UserId, UserId, DepartmentId)) + continue; + var person = new CertificationsReportRow(); person.SubRows = new List(); @@ -762,6 +812,9 @@ private async Task CreateLogReportModel(int logId) foreach (var user in model.Log.Users) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(user.UserId, UserId, DepartmentId)) + continue; + var profile = await _userProfileService.GetProfileByUserIdAsync(user.UserId); var station = await _departmentGroupsService.GetGroupForUserAsync(user.UserId, DepartmentId); @@ -952,6 +1005,9 @@ await _workLogsService.GetAllLogsByDepartmentDateRangeAsync(DepartmentId, LogTyp foreach (var person in personnel) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(person.UserId, UserId, DepartmentId)) + continue; + var response = new PersonnelResponse(); var training = new PersonnelTraining(); @@ -1076,6 +1132,9 @@ await _workLogsService.GetAllLogsByDepartmentDateRangeAsync(DepartmentId, LogTyp foreach (var person in personnel) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(person.UserId, UserId, DepartmentId)) + continue; + var callHours = new PersonnelCallHours(); var workHours = new PersonnelWorkHours(); var trainingHours = new PersonnelTrainingHours(); @@ -1337,6 +1396,9 @@ into g { if (profiles.ContainsKey(group.UserId)) { + if (!await _authorizationService.CanUserViewPersonViaMatrixAsync(group.UserId, UserId, DepartmentId)) + continue; + var summary = new PersonnelStaffingSummary(); var profile = profiles[group.UserId]; @@ -1768,7 +1830,7 @@ private async Task ActiveCallsResourcesReportModel(int dep } model.Calls.Add(summary); - } + } } return model; diff --git a/Web/Resgrid.WebCore/Program.cs b/Web/Resgrid.WebCore/Program.cs index 3abc239b..a56368b6 100644 --- a/Web/Resgrid.WebCore/Program.cs +++ b/Web/Resgrid.WebCore/Program.cs @@ -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; @@ -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.ExternalErrorServiceUrlForWebsite)) { webBuilder.UseSentry(options => @@ -60,8 +70,7 @@ public static IHostBuilder CreateHostBuilder(string[] args) => if (samplingContext != null && samplingContext.CustomSamplingContext != null) { if (samplingContext.CustomSamplingContext.ContainsKey("__HttpPath") && - samplingContext.CustomSamplingContext["__HttpPath"].ToString().ToLower() == - "/health/getcurrent") + samplingContext.CustomSamplingContext["__HttpPath"].ToString().ToLower() == "/health/getcurrent") { return 0; } diff --git a/Web/Resgrid.WebCore/wwwroot/js/app/internal/security/resgrid.security.permissions.js b/Web/Resgrid.WebCore/wwwroot/js/app/internal/security/resgrid.security.permissions.js index 90e913ea..87280a5a 100644 --- a/Web/Resgrid.WebCore/wwwroot/js/app/internal/security/resgrid.security.permissions.js +++ b/Web/Resgrid.WebCore/wwwroot/js/app/internal/security/resgrid.security.permissions.js @@ -624,6 +624,7 @@ var resgrid; }); // Create message + //////////////////////////////////////////////////////// $('#CreateMessage').change(function () { var val = this.value; $.ajax({ @@ -648,6 +649,50 @@ var resgrid; $('#createMessagesRolesSpan').show(); $('#createMessagesRolesDiv').hide(); } + + $("#createMessagesRoles").kendoMultiSelect({ + placeholder: "Select roles...", + dataTextField: "Name", + dataValueField: "RoleId", + change: function () { + var multiSelect = $("#createMessagesRoles").data("kendoMultiSelect"); + $.ajax({ + url: resgrid.absoluteBaseUrl + '/User/Security/SetPermissionData?type=13&data=' + encodeURIComponent(multiSelect.value()), + type: 'GET' + }).done(function (results) { + }); + }, + autoBind: false, + dataSource: { + transport: { + read: resgrid.absoluteBaseUrl + '/User/Personnel/GetRoles' + } + } + }); + $.ajax({ + url: resgrid.absoluteBaseUrl + '/User/Security/GetRolesForPermission?type=13', + contentType: 'application/json', + type: 'GET' + }).done(function (data) { + if (data) { + var multiSelect = $("#createMessagesRoles").data("kendoMultiSelect"); + multiSelect.value(data.split(",")); + } + }); + $.ajax({ + url: resgrid.absoluteBaseUrl + '/User/Security/GetRolesForPermission?type=13', + contentType: 'application/json', + type: 'GET' + }).done(function (data) { + if (data) { + var multiSelect = $("#createMessagesRoles").data("kendoMultiSelect"); + multiSelect.value(data.split(",")); + } + }); + //////////////////////////////////////////////////////// + + // View Group Users + //////////////////////////////////////////////////////// $('#ViewGroupsUsers').change(function () { var val = this.value; $.ajax({ @@ -679,15 +724,15 @@ var resgrid; }).done(function (results) { }); }); - // Create message - $("#createMessagesRoles").kendoMultiSelect({ + + $("#viewUsersRoles").kendoMultiSelect({ placeholder: "Select roles...", dataTextField: "Name", dataValueField: "RoleId", change: function () { - var multiSelect = $("#createMessagesRoles").data("kendoMultiSelect"); + var multiSelect = $("#viewUsersRoles").data("kendoMultiSelect"); $.ajax({ - url: resgrid.absoluteBaseUrl + '/User/Security/SetPermissionData?type=13&data=' + encodeURIComponent(multiSelect.value()), + url: resgrid.absoluteBaseUrl + '/User/Security/SetPermissionData?type=14&data=' + encodeURIComponent(multiSelect.value()), type: 'GET' }).done(function (results) { }); @@ -700,12 +745,12 @@ var resgrid; } }); $.ajax({ - url: resgrid.absoluteBaseUrl + '/User/Security/GetRolesForPermission?type=13', + url: resgrid.absoluteBaseUrl + '/User/Security/GetRolesForPermission?type=14', contentType: 'application/json', type: 'GET' }).done(function (data) { if (data) { - var multiSelect = $("#createMessagesRoles").data("kendoMultiSelect"); + var multiSelect = $("#viewUsersRoles").data("kendoMultiSelect"); multiSelect.value(data.split(",")); } }); @@ -719,6 +764,7 @@ var resgrid; multiSelect.value(data.split(",")); } }); + //////////////////////////////////////////////////////// // Delete Call ////////////////////////////////////////////////////////