mirror of
https://github.com/bitwarden/server.git
synced 2025-07-01 16:12:49 -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:
@ -30,6 +30,7 @@ public class OrganizationsController : Controller
|
|||||||
private readonly GlobalSettings _globalSettings;
|
private readonly GlobalSettings _globalSettings;
|
||||||
private readonly IReferenceEventService _referenceEventService;
|
private readonly IReferenceEventService _referenceEventService;
|
||||||
private readonly IUserService _userService;
|
private readonly IUserService _userService;
|
||||||
|
private readonly IProviderRepository _providerRepository;
|
||||||
private readonly ILogger<OrganizationsController> _logger;
|
private readonly ILogger<OrganizationsController> _logger;
|
||||||
|
|
||||||
public OrganizationsController(
|
public OrganizationsController(
|
||||||
@ -47,6 +48,7 @@ public class OrganizationsController : Controller
|
|||||||
GlobalSettings globalSettings,
|
GlobalSettings globalSettings,
|
||||||
IReferenceEventService referenceEventService,
|
IReferenceEventService referenceEventService,
|
||||||
IUserService userService,
|
IUserService userService,
|
||||||
|
IProviderRepository providerRepository,
|
||||||
ILogger<OrganizationsController> logger)
|
ILogger<OrganizationsController> logger)
|
||||||
{
|
{
|
||||||
_organizationRepository = organizationRepository;
|
_organizationRepository = organizationRepository;
|
||||||
@ -63,6 +65,7 @@ public class OrganizationsController : Controller
|
|||||||
_globalSettings = globalSettings;
|
_globalSettings = globalSettings;
|
||||||
_referenceEventService = referenceEventService;
|
_referenceEventService = referenceEventService;
|
||||||
_userService = userService;
|
_userService = userService;
|
||||||
|
_providerRepository = providerRepository;
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,6 +105,7 @@ public class OrganizationsController : Controller
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var provider = await _providerRepository.GetByOrganizationIdAsync(id);
|
||||||
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(id);
|
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(id);
|
||||||
var collections = await _collectionRepository.GetManyByOrganizationIdAsync(id);
|
var collections = await _collectionRepository.GetManyByOrganizationIdAsync(id);
|
||||||
IEnumerable<Group> groups = null;
|
IEnumerable<Group> groups = null;
|
||||||
@ -116,7 +120,7 @@ public class OrganizationsController : Controller
|
|||||||
}
|
}
|
||||||
var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
|
var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
|
||||||
var billingSyncConnection = _globalSettings.EnableCloudCommunication ? await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(id, OrganizationConnectionType.CloudBillingSync) : null;
|
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)]
|
[SelfHosted(NotSelfHostedOnly = true)]
|
||||||
@ -128,6 +132,7 @@ public class OrganizationsController : Controller
|
|||||||
return RedirectToAction("Index");
|
return RedirectToAction("Index");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var provider = await _providerRepository.GetByOrganizationIdAsync(id);
|
||||||
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(id);
|
var ciphers = await _cipherRepository.GetManyByOrganizationIdAsync(id);
|
||||||
var collections = await _collectionRepository.GetManyByOrganizationIdAsync(id);
|
var collections = await _collectionRepository.GetManyByOrganizationIdAsync(id);
|
||||||
IEnumerable<Group> groups = null;
|
IEnumerable<Group> groups = null;
|
||||||
@ -143,7 +148,7 @@ public class OrganizationsController : Controller
|
|||||||
var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
|
var users = await _organizationUserRepository.GetManyDetailsByOrganizationAsync(id);
|
||||||
var billingInfo = await _paymentService.GetBillingAsync(organization);
|
var billingInfo = await _paymentService.GetBillingAsync(organization);
|
||||||
var billingSyncConnection = _globalSettings.EnableCloudCommunication ? await _organizationConnectionRepository.GetByOrganizationIdTypeAsync(id, OrganizationConnectionType.CloudBillingSync) : null;
|
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));
|
billingInfo, billingSyncConnection, _globalSettings));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Entities.Provider;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Business;
|
using Bit.Core.Models.Business;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
@ -12,11 +13,11 @@ public class OrganizationEditModel : OrganizationViewModel
|
|||||||
{
|
{
|
||||||
public OrganizationEditModel() { }
|
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<Cipher> ciphers, IEnumerable<Collection> collections, IEnumerable<Group> groups,
|
||||||
IEnumerable<Policy> policies, BillingInfo billingInfo, IEnumerable<OrganizationConnection> connections,
|
IEnumerable<Policy> policies, BillingInfo billingInfo, IEnumerable<OrganizationConnection> connections,
|
||||||
GlobalSettings globalSettings)
|
GlobalSettings globalSettings)
|
||||||
: base(org, connections, orgUsers, ciphers, collections, groups, policies)
|
: base(org, provider, connections, orgUsers, ciphers, collections, groups, policies)
|
||||||
{
|
{
|
||||||
BillingInfo = billingInfo;
|
BillingInfo = billingInfo;
|
||||||
BraintreeMerchantId = globalSettings.Braintree.MerchantId;
|
BraintreeMerchantId = globalSettings.Braintree.MerchantId;
|
||||||
@ -59,7 +60,7 @@ public class OrganizationEditModel : OrganizationViewModel
|
|||||||
public string BraintreeMerchantId { get; set; }
|
public string BraintreeMerchantId { get; set; }
|
||||||
|
|
||||||
[Required]
|
[Required]
|
||||||
[Display(Name = "Name")]
|
[Display(Name = "Organization Name")]
|
||||||
public string Name { get; set; }
|
public string Name { get; set; }
|
||||||
[Display(Name = "Business Name")]
|
[Display(Name = "Business Name")]
|
||||||
public string BusinessName { get; set; }
|
public string BusinessName { get; set; }
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using Bit.Core.Entities;
|
using Bit.Core.Entities;
|
||||||
|
using Bit.Core.Entities.Provider;
|
||||||
using Bit.Core.Enums;
|
using Bit.Core.Enums;
|
||||||
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
using Bit.Core.Models.Data.Organizations.OrganizationUsers;
|
||||||
|
|
||||||
@ -8,11 +9,12 @@ public class OrganizationViewModel
|
|||||||
{
|
{
|
||||||
public 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<OrganizationUserUserDetails> orgUsers, IEnumerable<Cipher> ciphers, IEnumerable<Collection> collections,
|
||||||
IEnumerable<Group> groups, IEnumerable<Policy> policies)
|
IEnumerable<Group> groups, IEnumerable<Policy> policies)
|
||||||
{
|
{
|
||||||
Organization = org;
|
Organization = org;
|
||||||
|
Provider = provider;
|
||||||
Connections = connections ?? Enumerable.Empty<OrganizationConnection>();
|
Connections = connections ?? Enumerable.Empty<OrganizationConnection>();
|
||||||
HasPublicPrivateKeys = org.PublicKey != null && org.PrivateKey != null;
|
HasPublicPrivateKeys = org.PublicKey != null && org.PrivateKey != null;
|
||||||
UserInvitedCount = orgUsers.Count(u => u.Status == OrganizationUserStatusType.Invited);
|
UserInvitedCount = orgUsers.Count(u => u.Status == OrganizationUserStatusType.Invited);
|
||||||
@ -34,6 +36,7 @@ public class OrganizationViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Organization Organization { get; set; }
|
public Organization Organization { get; set; }
|
||||||
|
public Provider Provider { get; set; }
|
||||||
public IEnumerable<OrganizationConnection> Connections { get; set; }
|
public IEnumerable<OrganizationConnection> Connections { get; set; }
|
||||||
public string Owners { get; set; }
|
public string Owners { get; set; }
|
||||||
public string Admins { get; set; }
|
public string Admins { get; set; }
|
||||||
|
@ -117,6 +117,11 @@
|
|||||||
|
|
||||||
<h1>Organization <small>@Model.Organization.Name</small></h1>
|
<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>
|
<h2>Organization Information</h2>
|
||||||
@await Html.PartialAsync("_ViewInformation", Model)
|
@await Html.PartialAsync("_ViewInformation", Model)
|
||||||
<h2>Billing Information</h2>
|
<h2>Billing Information</h2>
|
||||||
@ -283,7 +288,14 @@
|
|||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label asp-for="BillingEmail"></label>
|
<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>
|
</div>
|
||||||
<div class="col-sm">
|
<div class="col-sm">
|
||||||
|
@ -6,6 +6,11 @@
|
|||||||
|
|
||||||
<h1>Organization <small>@Model.Organization.Name</small></h1>
|
<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>
|
<h2>Information</h2>
|
||||||
@await Html.PartialAsync("_ViewInformation", Model)
|
@await Html.PartialAsync("_ViewInformation", Model)
|
||||||
@if(GlobalSettings.SelfHosted)
|
@if(GlobalSettings.SelfHosted)
|
||||||
|
@ -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>
|
@ -5,6 +5,7 @@ namespace Bit.Core.Repositories;
|
|||||||
|
|
||||||
public interface IProviderRepository : IRepository<Provider, Guid>
|
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<Provider>> SearchAsync(string name, string userEmail, int skip, int take);
|
||||||
Task<ICollection<ProviderAbility>> GetManyAbilitiesAsync();
|
Task<ICollection<ProviderAbility>> GetManyAbilitiesAsync();
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,19 @@ public class ProviderRepository : Repository<Provider, Guid>, IProviderRepositor
|
|||||||
: base(connectionString, readOnlyConnectionString)
|
: 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)
|
public async Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take)
|
||||||
{
|
{
|
||||||
using (var connection = new SqlConnection(ReadOnlyConnectionString))
|
using (var connection = new SqlConnection(ReadOnlyConnectionString))
|
||||||
|
@ -25,6 +25,20 @@ public class ProviderRepository : Repository<Provider, Models.Provider, Guid>, I
|
|||||||
await base.DeleteAsync(provider);
|
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)
|
public async Task<ICollection<Provider>> SearchAsync(string name, string userEmail, int skip, int take)
|
||||||
{
|
{
|
||||||
using (var scope = ServiceScopeFactory.CreateScope())
|
using (var scope = ServiceScopeFactory.CreateScope())
|
||||||
|
@ -282,6 +282,7 @@
|
|||||||
<Build Include="dbo\Stored Procedures\Policy_ReadByUserId.sql" />
|
<Build Include="dbo\Stored Procedures\Policy_ReadByUserId.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\Policy_Update.sql" />
|
<Build Include="dbo\Stored Procedures\Policy_Update.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganizationOrganizationDetails_ReadByProviderId.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_Create.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_DeleteById.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderOrganization_DeleteById.sql" />
|
||||||
<Build Include="dbo\Stored Procedures\ProviderOrganization_ReadById.sql" />
|
<Build Include="dbo\Stored Procedures\ProviderOrganization_ReadById.sql" />
|
||||||
|
@ -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
|
@ -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
|
Reference in New Issue
Block a user