From e920c8e9d2d963e98533341bd50bf7c3972507ae Mon Sep 17 00:00:00 2001 From: Kyle Spearrin Date: Thu, 22 Mar 2018 21:10:10 -0400 Subject: [PATCH] org and user info --- .../Controllers/OrganizationsController.cs | 7 ++- src/Admin/Controllers/UsersController.cs | 7 ++- src/Admin/Models/OrganizationEditModel.cs | 17 ++++- src/Admin/Models/UserEditModel.cs | 6 +- src/Admin/Views/Organizations/Edit.cshtml | 24 ++++++- src/Admin/Views/Users/Edit.cshtml | 21 ++++++- .../SqlServer/OrganizationRepository.cs | 6 +- .../Stored Procedures/Organization_Search.sql | 63 +++++++++++++------ .../DbScripts/2018-03-21_00_AdminPortal.sql | 63 +++++++++++++------ 9 files changed, 159 insertions(+), 55 deletions(-) diff --git a/src/Admin/Controllers/OrganizationsController.cs b/src/Admin/Controllers/OrganizationsController.cs index 8646659b9..2f8f64b2d 100644 --- a/src/Admin/Controllers/OrganizationsController.cs +++ b/src/Admin/Controllers/OrganizationsController.cs @@ -14,13 +14,16 @@ namespace Bit.Admin.Controllers public class OrganizationsController : Controller { private readonly IOrganizationRepository _organizationRepository; + private readonly IOrganizationUserRepository _organizationUserRepository; private readonly GlobalSettings _globalSettings; public OrganizationsController( IOrganizationRepository organizationRepository, + IOrganizationUserRepository organizationUserRepository, GlobalSettings globalSettings) { _organizationRepository = organizationRepository; + _organizationUserRepository = organizationUserRepository; _globalSettings = globalSettings; } @@ -58,10 +61,12 @@ namespace Bit.Admin.Controllers return RedirectToAction("Index"); } - return View(new OrganizationEditModel(organization, _globalSettings)); + var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id); + return View(new OrganizationEditModel(organization, users, _globalSettings)); } [HttpPost] + [ValidateAntiForgeryToken] public async Task Edit(Guid id, OrganizationEditModel model) { var organization = await _organizationRepository.GetByIdAsync(id); diff --git a/src/Admin/Controllers/UsersController.cs b/src/Admin/Controllers/UsersController.cs index 49f7c2749..08d7a3757 100644 --- a/src/Admin/Controllers/UsersController.cs +++ b/src/Admin/Controllers/UsersController.cs @@ -14,13 +14,16 @@ namespace Bit.Admin.Controllers public class UsersController : Controller { private readonly IUserRepository _userRepository; + private readonly ICipherRepository _cipherRepository; private readonly GlobalSettings _globalSettings; public UsersController( IUserRepository userRepository, + ICipherRepository cipherRepository, GlobalSettings globalSettings) { _userRepository = userRepository; + _cipherRepository = cipherRepository; _globalSettings = globalSettings; } @@ -55,10 +58,12 @@ namespace Bit.Admin.Controllers return RedirectToAction("Index"); } - return View(new UserEditModel(user, _globalSettings)); + var ciphers = await _cipherRepository.GetManyByUserIdAsync(id); + return View(new UserEditModel(user, ciphers, _globalSettings)); } [HttpPost] + [ValidateAntiForgeryToken] public async Task Edit(Guid id, UserEditModel model) { var user = await _userRepository.GetByIdAsync(id); diff --git a/src/Admin/Models/OrganizationEditModel.cs b/src/Admin/Models/OrganizationEditModel.cs index 10f19346d..62f120bcf 100644 --- a/src/Admin/Models/OrganizationEditModel.cs +++ b/src/Admin/Models/OrganizationEditModel.cs @@ -1,6 +1,10 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using Bit.Core; +using Bit.Core.Enums; +using Bit.Core.Models.Data; using Bit.Core.Models.Table; using Bit.Core.Utilities; @@ -10,9 +14,13 @@ namespace Bit.Admin.Models { public OrganizationEditModel() { } - public OrganizationEditModel(Organization org, GlobalSettings globalSettings) + public OrganizationEditModel(Organization org, IEnumerable orgUsers, + GlobalSettings globalSettings) { Organization = org; + UserCount = orgUsers.Count(); + Owners = string.Join(", ", orgUsers.Where(u => u.Type == OrganizationUserType.Owner).Select(u => u.Email)); + Admins = string.Join(", ", orgUsers.Where(u => u.Type == OrganizationUserType.Admin).Select(u => u.Email)); BraintreeMerchantId = globalSettings.Braintree.MerchantId; Name = org.Name; @@ -43,6 +51,9 @@ namespace Bit.Admin.Models } public Organization Organization { get; set; } + public string Owners { get; set; } + public string Admins { get; set; } + public int UserCount { get; set; } public string RandomLicenseKey => CoreHelpers.SecureRandomString(20); public string FourteenDayExpirationDate => DateTime.Now.AddDays(14).ToString("yyyy-MM-ddTHH:mm"); public string BraintreeMerchantId { get; set; } @@ -66,7 +77,7 @@ namespace Bit.Admin.Models public string BillingEmail { get; set; } [Required] [Display(Name = "Plan")] - public Core.Enums.PlanType? PlanType { get; set; } + public PlanType? PlanType { get; set; } [Required] [Display(Name = "Plan Name")] public string Plan { get; set; } @@ -89,7 +100,7 @@ namespace Bit.Admin.Models [Display(Name = "Max. Storage GB")] public short? MaxStorageGb { get; set; } [Display(Name = "Gateway")] - public Core.Enums.GatewayType? Gateway { get; set; } + public GatewayType? Gateway { get; set; } [Display(Name = "Gateway Customer Id")] public string GatewayCustomerId { get; set; } [Display(Name = "Gateway Subscription Id")] diff --git a/src/Admin/Models/UserEditModel.cs b/src/Admin/Models/UserEditModel.cs index 76ac508b3..981e09290 100644 --- a/src/Admin/Models/UserEditModel.cs +++ b/src/Admin/Models/UserEditModel.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations; +using System.Linq; using Bit.Core; using Bit.Core.Models.Table; using Bit.Core.Utilities; @@ -10,9 +12,10 @@ namespace Bit.Admin.Models { public UserEditModel() { } - public UserEditModel(User user, GlobalSettings globalSettings) + public UserEditModel(User user, IEnumerable ciphers, GlobalSettings globalSettings) { User = user; + CipherCount = ciphers.Count(); BraintreeMerchantId = globalSettings.Braintree.MerchantId; Name = user.Name; @@ -28,6 +31,7 @@ namespace Bit.Admin.Models } public User User { get; set; } + public int CipherCount { get; set; } public string RandomLicenseKey => CoreHelpers.SecureRandomString(20); public string OneYearExpirationDate => DateTime.Now.AddYears(1).ToString("yyyy-MM-ddTHH:mm"); public string BraintreeMerchantId { get; set; } diff --git a/src/Admin/Views/Organizations/Edit.cshtml b/src/Admin/Views/Organizations/Edit.cshtml index d23e4a938..d6e4db730 100644 --- a/src/Admin/Views/Organizations/Edit.cshtml +++ b/src/Admin/Views/Organizations/Edit.cshtml @@ -1,6 +1,6 @@ @model OrganizationEditModel @{ - ViewData["Title"] = "Organization Edit: " + Model.Organization.Name; + ViewData["Title"] = "Organization: " + Model.Organization.Name; } @section Scripts { @@ -71,8 +71,28 @@ } -

Edit Organization @Model.Organization.Name

+

Organization @Model.Organization.Name

+

Information

+
+
Id
+
@Model.Organization.Id
+ +
Users
+
@Model.UserCount
+ +
Owners
+
@(string.IsNullOrWhiteSpace(Model.Owners) ? "None" : Model.Owners)
+ +
Admins
+
@(string.IsNullOrWhiteSpace(Model.Admins) ? "None" : Model.Admins)
+ +
Created
+
@Model.Organization.CreationDate.ToString()
+ +
Modified
+
@Model.Organization.RevisionDate.ToString()
+

General

diff --git a/src/Admin/Views/Users/Edit.cshtml b/src/Admin/Views/Users/Edit.cshtml index 8300fdd7b..a8bd8b5fc 100644 --- a/src/Admin/Views/Users/Edit.cshtml +++ b/src/Admin/Views/Users/Edit.cshtml @@ -1,6 +1,6 @@ @model UserEditModel @{ - ViewData["Title"] = "User Edit: " + Model.User.Email; + ViewData["Title"] = "User: " + Model.User.Email; } @section Scripts { @@ -54,8 +54,25 @@ } -

Edit User @Model.User.Email

+

User @Model.User.Email

+

Information

+
+
Id
+
@Model.User.Id
+ +
Items
+
@Model.CipherCount
+ +
Created
+
@Model.User.CreationDate.ToString()
+ +
Modified
+
@Model.User.RevisionDate.ToString()
+ +
Account Modified
+
@Model.User.AccountRevisionDate.ToString()
+

General

diff --git a/src/Core/Repositories/SqlServer/OrganizationRepository.cs b/src/Core/Repositories/SqlServer/OrganizationRepository.cs index 7610f9c3f..a00efdce4 100644 --- a/src/Core/Repositories/SqlServer/OrganizationRepository.cs +++ b/src/Core/Repositories/SqlServer/OrganizationRepository.cs @@ -55,11 +55,7 @@ namespace Bit.Core.Repositories.SqlServer new { Name = name, UserEmail = userEmail, Paid = paid, Skip = skip, Take = take }, commandType: CommandType.StoredProcedure); - // Select distinct results by Id - return results - .GroupBy(c => c.Id) - .Select(g => g.First()) - .ToList(); + return results.ToList(); } } diff --git a/src/Sql/dbo/Stored Procedures/Organization_Search.sql b/src/Sql/dbo/Stored Procedures/Organization_Search.sql index 5ffa07507..998180865 100644 --- a/src/Sql/dbo/Stored Procedures/Organization_Search.sql +++ b/src/Sql/dbo/Stored Procedures/Organization_Search.sql @@ -9,26 +9,49 @@ BEGIN SET NOCOUNT ON DECLARE @NameLikeSearch NVARCHAR(55) = '%' + @Name + '%' - SELECT - O.* - FROM - [dbo].[OrganizationView] O - INNER JOIN - [dbo].[OrganizationUser] OU ON O.[Id] = OU.[OrganizationId] - INNER JOIN - [dbo].[User] U ON U.[Id] = OU.[UserId] - WHERE - (@Name IS NULL OR O.[Name] LIKE @NameLikeSearch) - AND (@UserEmail IS NULL OR U.[Email] = @UserEmail) - AND - ( - @Paid IS NULL OR + IF @UserEmail IS NOT NULL + BEGIN + SELECT + O.* + FROM + [dbo].[OrganizationView] O + INNER JOIN + [dbo].[OrganizationUser] OU ON O.[Id] = OU.[OrganizationId] + INNER JOIN + [dbo].[User] U ON U.[Id] = OU.[UserId] + WHERE + (@Name IS NULL OR O.[Name] LIKE @NameLikeSearch) + AND (@UserEmail IS NULL OR U.[Email] = @UserEmail) + AND ( - (@Paid = 1 AND O.[GatewaySubscriptionId] IS NOT NULL) OR - (@Paid = 0 AND O.[GatewaySubscriptionId] IS NULL) + @Paid IS NULL OR + ( + (@Paid = 1 AND O.[GatewaySubscriptionId] IS NOT NULL) OR + (@Paid = 0 AND O.[GatewaySubscriptionId] IS NULL) + ) ) - ) - ORDER BY O.[CreationDate] DESC - OFFSET @Skip ROWS - FETCH NEXT @Take ROWS ONLY + ORDER BY O.[CreationDate] DESC + OFFSET @Skip ROWS + FETCH NEXT @Take ROWS ONLY + END + ELSE + BEGIN + SELECT + O.* + FROM + [dbo].[OrganizationView] O + WHERE + (@Name IS NULL OR O.[Name] LIKE @NameLikeSearch) + AND + ( + @Paid IS NULL OR + ( + (@Paid = 1 AND O.[GatewaySubscriptionId] IS NOT NULL) OR + (@Paid = 0 AND O.[GatewaySubscriptionId] IS NULL) + ) + ) + ORDER BY O.[CreationDate] DESC + OFFSET @Skip ROWS + FETCH NEXT @Take ROWS ONLY + END END diff --git a/util/Setup/DbScripts/2018-03-21_00_AdminPortal.sql b/util/Setup/DbScripts/2018-03-21_00_AdminPortal.sql index 3adb5958e..563c54b75 100644 --- a/util/Setup/DbScripts/2018-03-21_00_AdminPortal.sql +++ b/util/Setup/DbScripts/2018-03-21_00_AdminPortal.sql @@ -42,27 +42,50 @@ BEGIN SET NOCOUNT ON DECLARE @NameLikeSearch NVARCHAR(55) = '%' + @Name + '%' - SELECT - O.* - FROM - [dbo].[OrganizationView] O - INNER JOIN - [dbo].[OrganizationUser] OU ON O.[Id] = OU.[OrganizationId] - INNER JOIN - [dbo].[User] U ON U.[Id] = OU.[UserId] - WHERE - (@Name IS NULL OR O.[Name] LIKE @NameLikeSearch) - AND (@UserEmail IS NULL OR U.[Email] = @UserEmail) - AND - ( - @Paid IS NULL OR + IF @UserEmail IS NOT NULL + BEGIN + SELECT + O.* + FROM + [dbo].[OrganizationView] O + INNER JOIN + [dbo].[OrganizationUser] OU ON O.[Id] = OU.[OrganizationId] + INNER JOIN + [dbo].[User] U ON U.[Id] = OU.[UserId] + WHERE + (@Name IS NULL OR O.[Name] LIKE @NameLikeSearch) + AND (@UserEmail IS NULL OR U.[Email] = @UserEmail) + AND ( - (@Paid = 1 AND O.[GatewaySubscriptionId] IS NOT NULL) OR - (@Paid = 0 AND O.[GatewaySubscriptionId] IS NULL) + @Paid IS NULL OR + ( + (@Paid = 1 AND O.[GatewaySubscriptionId] IS NOT NULL) OR + (@Paid = 0 AND O.[GatewaySubscriptionId] IS NULL) + ) ) - ) - ORDER BY O.[CreationDate] DESC - OFFSET @Skip ROWS - FETCH NEXT @Take ROWS ONLY + ORDER BY O.[CreationDate] DESC + OFFSET @Skip ROWS + FETCH NEXT @Take ROWS ONLY + END + ELSE + BEGIN + SELECT + O.* + FROM + [dbo].[OrganizationView] O + WHERE + (@Name IS NULL OR O.[Name] LIKE @NameLikeSearch) + AND + ( + @Paid IS NULL OR + ( + (@Paid = 1 AND O.[GatewaySubscriptionId] IS NOT NULL) OR + (@Paid = 0 AND O.[GatewaySubscriptionId] IS NULL) + ) + ) + ORDER BY O.[CreationDate] DESC + OFFSET @Skip ROWS + FETCH NEXT @Take ROWS ONLY + END END GO