1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 23:52:50 -05:00

[EC-430] Admin portal: Update organization information screen (#2672)

* [EC-430] Added ProviderOrganizationProviderDetailsView to get Provider details for an Organization

* [EC-430] Added Provider information to Organization Edit/View on Admin panel

* [EC-430] Remove "Add to Reseller" button

* [EC-430] Removed unused property OrganizationEditModel.ClientOwnerEmail

* [EC-430] Replaced IProviderOrganizationRepository.GetProviderDetailsByOrganizationAsync with IProviderRepository.GetByOrganizationIdAsync

* [EC-430] Deleted ProviderOrganizationProviderDetails and ProviderOrganizationProviderDetailsReadByOrganizationIdQuery
This commit is contained in:
Rui Tomé
2023-02-13 10:26:58 +00:00
committed by GitHub
parent f331188763
commit 624df49698
12 changed files with 102 additions and 7 deletions

View File

@ -30,6 +30,7 @@ public class OrganizationsController : Controller
private readonly GlobalSettings _globalSettings;
private readonly IReferenceEventService _referenceEventService;
private readonly IUserService _userService;
private readonly IProviderRepository _providerRepository;
private readonly ILogger<OrganizationsController> _logger;
public OrganizationsController(
@ -47,6 +48,7 @@ public class OrganizationsController : Controller
GlobalSettings globalSettings,
IReferenceEventService referenceEventService,
IUserService userService,
IProviderRepository providerRepository,
ILogger<OrganizationsController> logger)
{
_organizationRepository = organizationRepository;
@ -63,6 +65,7 @@ public class OrganizationsController : Controller
_globalSettings = globalSettings;
_referenceEventService = referenceEventService;
_userService = userService;
_providerRepository = providerRepository;
_logger = logger;
}
@ -102,6 +105,7 @@ public class OrganizationsController : Controller
return RedirectToAction("Index");
}
var provider = await _providerRepository.GetByOrganizationIdAsync(id);
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(id);
var collections = await _collectionRepository.GetManyByOrganizationIdAsync(id);
IEnumerable<Group> groups = null;
@ -116,7 +120,7 @@ public class OrganizationsController : Controller
}
var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
var billingSyncConnection = _globalSettings.EnableCloudCommunication ? await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(id, OrganizationConnectionType.CloudBillingSync) : null;
return View(new OrganizationViewModel(organization, billingSyncConnection, users, ciphers, collections, groups, policies));
return View(new OrganizationViewModel(organization, provider, billingSyncConnection, users, ciphers, collections, groups, policies));
}
[SelfHosted(NotSelfHostedOnly = true)]
@ -128,6 +132,7 @@ public class OrganizationsController : Controller
return RedirectToAction("Index");
}
var provider = await _providerRepository.GetByOrganizationIdAsync(id);
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(id);
var collections = await _collectionRepository.GetManyByOrganizationIdAsync(id);
IEnumerable<Group> groups = null;
@ -143,7 +148,7 @@ public class OrganizationsController : Controller
var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
var billingInfo = await _paymentService.GetBillingAsync(organization);
var billingSyncConnection = _globalSettings.EnableCloudCommunication ? await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(id, OrganizationConnectionType.CloudBillingSync) : null;
return View(new OrganizationEditModel(organization, users, ciphers, collections, groups, policies,
return View(new OrganizationEditModel(organization, provider, users, ciphers, collections, groups, policies,
billingInfo, billingSyncConnection, _globalSettings));
}

View File

@ -1,5 +1,6 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
using Bit.Core.Entities.Provider;
using Bit.Core.Enums;
using Bit.Core.Models.Business;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
@ -12,11 +13,11 @@ public class OrganizationEditModel : OrganizationViewModel
{
public OrganizationEditModel() { }
public OrganizationEditModel(Organization org, IEnumerable<OrganizationUserUserDetails> orgUsers,
public OrganizationEditModel(Organization org, Provider provider, IEnumerable<OrganizationUserUserDetails> orgUsers,
IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections, IEnumerable<Group> groups,
IEnumerable<Policy> policies, BillingInfo billingInfo, IEnumerable<OrganizationConnection> connections,
GlobalSettings globalSettings)
: base(org, connections, orgUsers, ciphers, collections, groups, policies)
: base(org, provider, connections, orgUsers, ciphers, collections, groups, policies)
{
BillingInfo = billingInfo;
BraintreeMerchantId = globalSettings.Braintree.MerchantId;
@ -59,7 +60,7 @@ public class OrganizationEditModel : OrganizationViewModel
public string BraintreeMerchantId { get; set; }
[Required]
[Display(Name = "Name")]
[Display(Name = "Organization Name")]
public string Name { get; set; }
[Display(Name = "Business Name")]
public string BusinessName { get; set; }

View File

@ -1,4 +1,5 @@
using Bit.Core.Entities;
using Bit.Core.Entities.Provider;
using Bit.Core.Enums;
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
@ -8,11 +9,12 @@ public class OrganizationViewModel
{
public OrganizationViewModel() { }
public OrganizationViewModel(Organization org, IEnumerable<OrganizationConnection> connections,
public OrganizationViewModel(Organization org, Provider provider, IEnumerable<OrganizationConnection> connections,
IEnumerable<OrganizationUserUserDetails> orgUsers, IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
IEnumerable<Group> groups, IEnumerable<Policy> policies)
{
Organization = org;
Provider = provider;
Connections = connections ?? Enumerable.Empty<OrganizationConnection>();
HasPublicPrivateKeys = org.PublicKey != null && org.PrivateKey != null;
UserInvitedCount = orgUsers.Count(u => u.Status == OrganizationUserStatusType.Invited);
@ -34,6 +36,7 @@ public class OrganizationViewModel
}
public Organization Organization { get; set; }
public Provider Provider { get; set; }
public IEnumerable<OrganizationConnection> Connections { get; set; }
public string Owners { get; set; }
public string Admins { get; set; }

View File

@ -117,6 +117,11 @@
<h1>Organization <small>@Model.Organization.Name</small></h1>
@if (Model.Provider != null)
{
<h2>Provider Relationship</h2>
@await Html.PartialAsync("_ProviderInformation", Model.Provider)
}
<h2>Organization Information</h2>
@await Html.PartialAsync("_ViewInformation", Model)
<h2>Billing Information</h2>
@ -283,7 +288,14 @@
<div class="col-sm">
<div class="form-group">
<label asp-for="BillingEmail"></label>
<input type="email" class="form-control" asp-for="BillingEmail">
@if (Model.Provider?.Type == ProviderType.Reseller)
{
<input type="email" class="form-control" asp-for="Provider.BillingEmail" readonly="readonly">
}
else
{
<input type="email" class="form-control" asp-for="BillingEmail">
}
</div>
</div>
<div class="col-sm">

View File

@ -6,6 +6,11 @@
<h1>Organization <small>@Model.Organization.Name</small></h1>
@if (Model.Provider != null)
{
<h2>Provider Relationship</h2>
@await Html.PartialAsync("_ProviderInformation", Model.Provider)
}
<h2>Information</h2>
@await Html.PartialAsync("_ViewInformation", Model)
@if(GlobalSettings.SelfHosted)

View File

@ -0,0 +1,9 @@
@using Bit.SharedWeb.Utilities
@model Bit.Core.Entities.Provider.Provider
<dl class="row">
<dt class="col-sm-4 col-lg-3">Provider Name</dt>
<dd class="col-sm-8 col-lg-9">@Model.Name</dd>
<dt class="col-sm-4 col-lg-3">Provider Type</dt>
<dd class="col-sm-8 col-lg-9">@(Model.Type.GetDisplayAttribute()?.GetName())</dd>
</dl>

View File

@ -5,6 +5,7 @@ namespace Bit.Core.Repositories;
public interface IProviderRepository : IRepository<Provider, Guid>
{
Task<Provider> GetByOrganizationIdAsync(Guid organizationId);
Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take);
Task<ICollection<ProviderAbility>> GetManyAbilitiesAsync();
}

View File

@ -18,6 +18,19 @@ public class ProviderRepository : Repository<Provider, Guid>, IProviderRepositor
: base(connectionString, readOnlyConnectionString)
{ }
public async Task<Provider> GetByOrganizationIdAsync(Guid organizationId)
{
using (var connection = new SqlConnection(ConnectionString))
{
var results = await connection.QueryAsync<Provider>(
"[dbo].[Provider_ReadByOrganizationId]",
new { OrganizationId = organizationId },
commandType: CommandType.StoredProcedure);
return results.FirstOrDefault();
}
}
public async Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take)
{
using (var connection = new SqlConnection(ReadOnlyConnectionString))

View File

@ -25,6 +25,20 @@ public class ProviderRepository : Repository<Provider, Models.Provider, Guid>, I
await base.DeleteAsync(provider);
}
public async Task<Provider> GetByOrganizationIdAsync(Guid organizationId)
{
using (var scope = ServiceScopeFactory.CreateScope())
{
var dbContext = GetDatabaseContext(scope);
var query = from p in dbContext.Providers
join po in dbContext.ProviderOrganizations
on p.Id equals po.ProviderId
where po.OrganizationId == organizationId
select p;
return await query.FirstOrDefaultAsync();
}
}
public async Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take)
{
using (var scope = ServiceScopeFactory.CreateScope())

View File

@ -282,6 +282,7 @@
<Build Include="dbo\Stored Procedures\Policy_ReadByUserId.sql" />
<Build Include="dbo\Stored Procedures\Policy_Update.sql" />
<Build Include="dbo\Stored Procedures\ProviderOrganizationOrganizationDetails_ReadByProviderId.sql" />
<Build Include="dbo\Stored Procedures\Provider_ReadByOrganizationId.sql" />
<Build Include="dbo\Stored Procedures\ProviderOrganization_Create.sql" />
<Build Include="dbo\Stored Procedures\ProviderOrganization_DeleteById.sql" />
<Build Include="dbo\Stored Procedures\ProviderOrganization_ReadById.sql" />

View File

@ -0,0 +1,15 @@
CREATE PROCEDURE [dbo].[Provider_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
P.*
FROM
[dbo].[ProviderView] P
INNER JOIN
[dbo].[ProviderOrganization] PO ON PO.[ProviderId] = P.[Id]
WHERE
PO.[OrganizationId] = @OrganizationId
END

View File

@ -0,0 +1,16 @@
CREATE OR ALTER PROCEDURE [dbo].[Provider_ReadByOrganizationId]
@OrganizationId UNIQUEIDENTIFIER
AS
BEGIN
SET NOCOUNT ON
SELECT
P.*
FROM
[dbo].[ProviderView] P
INNER JOIN
[dbo].[ProviderOrganization] PO ON PO.[ProviderId] = P.[Id]
WHERE
PO.[OrganizationId] = @OrganizationId
END
GO