Skip to content
31 changes: 15 additions & 16 deletions src/Api/Dirt/Controllers/OrganizationIntegrationController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using Bit.Api.Dirt.Models.Response;
using Bit.Core.Context;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
using Bit.Core.Exceptions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

Expand All @@ -18,17 +17,17 @@ public class OrganizationIntegrationController(
IGetOrganizationIntegrationsQuery getQuery) : Controller
{
[HttpGet("")]
public async Task<List<OrganizationIntegrationResponseModel>> GetAsync(Guid organizationId)
public async Task<ActionResult<List<OrganizationIntegrationResponseModel>>> GetAsync(Guid organizationId)
{
if (!await HasPermission(organizationId))
{
throw new NotFoundException();
return NotFound();
}

var integrations = await getQuery.GetManyByOrganizationAsync(organizationId);
return integrations
return Ok(integrations
.Select(integration => new OrganizationIntegrationResponseModel(integration))
.ToList();
.ToList());
}

/// <summary>
Expand All @@ -38,7 +37,7 @@ public async Task<List<OrganizationIntegrationResponseModel>> GetAsync(Guid orga
/// <param name="organizationId"></param>
/// <param name="model"></param>
/// <returns></returns>
/// <exception cref="NotFoundException">Not enough permissions to access the organization.</exception>
/// <exception cref="NotFoundResult">Not enough permissions to access the organization.</exception>
/// <exception cref="ConflictResult">When an integration of the same type already exists for the organization.</exception>
[HttpPost("")]
public async Task<ActionResult<OrganizationIntegrationResponseModel>> CreateAsync(Guid organizationId, [FromBody] OrganizationIntegrationRequestModel model)
Expand All @@ -50,7 +49,7 @@ public async Task<ActionResult<OrganizationIntegrationResponseModel>> CreateAsyn

if (!await HasPermission(organizationId))
{
throw new NotFoundException();
return NotFound();
}

var integration = model.ToOrganizationIntegration(organizationId);
Expand All @@ -62,40 +61,40 @@ public async Task<ActionResult<OrganizationIntegrationResponseModel>> CreateAsyn
}

var created = await createCommand.CreateAsync(integration);

return Ok(new OrganizationIntegrationResponseModel(created));

}

[HttpPut("{integrationId:guid}")]
public async Task<OrganizationIntegrationResponseModel> UpdateAsync(Guid organizationId, Guid integrationId, [FromBody] OrganizationIntegrationRequestModel model)
public async Task<ActionResult<OrganizationIntegrationResponseModel>> UpdateAsync(Guid organizationId, Guid integrationId, [FromBody] OrganizationIntegrationRequestModel model)
{
if (!await HasPermission(organizationId))
{
throw new NotFoundException();
return NotFound();
}

var integration = model.ToOrganizationIntegration(organizationId);
var updated = await updateCommand.UpdateAsync(organizationId, integrationId, integration);

return new OrganizationIntegrationResponseModel(updated);
return Ok(new OrganizationIntegrationResponseModel(updated));
}

[HttpDelete("{integrationId:guid}")]
public async Task DeleteAsync(Guid organizationId, Guid integrationId)
public async Task<IActionResult> DeleteAsync(Guid organizationId, Guid integrationId)
{
if (!await HasPermission(organizationId))
{
throw new NotFoundException();
return NotFound();
}

await deleteCommand.DeleteAsync(organizationId, integrationId);
return NoContent();
}

[HttpPost("{integrationId:guid}/delete")]
[Obsolete("This endpoint is deprecated. Use DELETE method instead")]
public async Task PostDeleteAsync(Guid organizationId, Guid integrationId)
public async Task<IActionResult> PostDeleteAsync(Guid organizationId, Guid integrationId)
{
await DeleteAsync(organizationId, integrationId);
return await DeleteAsync(organizationId, integrationId);
}

private async Task<bool> HasPermission(Guid organizationId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task<OrganizationIntegrationConfiguration> CreateAsync(
var integration = await integrationRepository.GetByIdAsync(integrationId);
if (integration == null || integration.OrganizationId != organizationId)
{
throw new NotFoundException();
throw new BadRequestException();
}
if (!validator.ValidateConfiguration(integration.Type, configuration))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ public async Task DeleteAsync(Guid organizationId, Guid integrationId, Guid conf
var integration = await integrationRepository.GetByIdAsync(integrationId);
if (integration == null || integration.OrganizationId != organizationId)
{
throw new NotFoundException();
throw new BadRequestException("Integration not found for this organization.");
}
var configuration = await configurationRepository.GetByIdAsync(configurationId);
if (configuration is null || configuration.OrganizationIntegrationId != integrationId)
{
throw new NotFoundException();
throw new BadRequestException("Configuration not found for this integration.");
}

await configurationRepository.DeleteAsync(configuration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface ICreateOrganizationIntegrationConfigurationCommand
/// <param name="integrationId">The unique identifier of the integration.</param>
/// <param name="configuration">The configuration to create.</param>
/// <returns>The created configuration.</returns>
/// <exception cref="Exceptions.NotFoundException">Thrown when the integration does not exist
/// <exception cref="Exceptions.BadRequestException">Thrown when the integration does not exist
/// or does not belong to the specified organization.</exception>
/// <exception cref="Exceptions.BadRequestException">Thrown when the configuration or filters
/// are invalid for the integration type.</exception>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public interface IUpdateOrganizationIntegrationConfigurationCommand
/// <param name="configurationId">The unique identifier of the configuration to update.</param>
/// <param name="updatedConfiguration">The updated configuration data.</param>
/// <returns>The updated configuration.</returns>
/// <exception cref="Exceptions.NotFoundException">
/// <exception cref="Exceptions.BadRequestException">Thrown when the integration or the configuration does not exist,
/// Thrown when the integration or the configuration does not exist,
/// or the integration does not belong to the specified organization,
/// or the configuration does not belong to the specified integration.</exception>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@ public async Task<OrganizationIntegrationConfiguration> UpdateAsync(
var integration = await integrationRepository.GetByIdAsync(integrationId);
if (integration == null || integration.OrganizationId != organizationId)
{
throw new NotFoundException();
throw new BadRequestException("Integration not found for this organization.");
}
var configuration = await configurationRepository.GetByIdAsync(configurationId);
if (configuration is null || configuration.OrganizationIntegrationId != integrationId)
{
throw new NotFoundException();
throw new BadRequestException("Configuration not found for this integration.");
}
if (!validator.ValidateConfiguration(integration.Type, updatedConfiguration))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ public async Task DeleteAsync(Guid organizationId, Guid integrationId)
var integration = await integrationRepository.GetByIdAsync(integrationId);
if (integration is null || integration.OrganizationId != organizationId)
{
throw new NotFoundException();
throw new BadRequestException("Integration not found for this organization.");
}

await integrationRepository.DeleteAsync(integration);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface IDeleteOrganizationIntegrationCommand
/// </summary>
/// <param name="organizationId">The unique identifier of the organization.</param>
/// <param name="integrationId">The unique identifier of the integration to delete.</param>
/// <exception cref="Exceptions.NotFoundException">Thrown when the integration does not exist
/// <exception cref="Exceptions.BadRequestException">Thrown when the integration does not exist
/// or does not belong to the specified organization.</exception>
Task DeleteAsync(Guid organizationId, Guid integrationId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public interface IUpdateOrganizationIntegrationCommand
/// <param name="integrationId">The unique identifier of the integration to update.</param>
/// <param name="updatedIntegration">The updated organization integration data.</param>
/// <returns>The updated organization integration.</returns>
/// <exception cref="Exceptions.NotFoundException">Thrown when the integration does not exist,
/// <exception cref="Exceptions.BadRequestException">Thrown when the integration does not exist,
/// does not belong to the specified organization, or the integration type does not match.</exception>
Task<OrganizationIntegration> UpdateAsync(Guid organizationId, Guid integrationId, OrganizationIntegration updatedIntegration);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public async Task<OrganizationIntegration> UpdateAsync(
integration.OrganizationId != organizationId ||
integration.Type != updatedIntegration.Type)
{
throw new NotFoundException();
throw new BadRequestException("Integration not found for this organization with the specified type.");
}

updatedIntegration.Id = integration.Id;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
using Bit.Core.Dirt.Entities;
using Bit.Core.Dirt.Enums;
using Bit.Core.Dirt.EventIntegrations.OrganizationIntegrations.Interfaces;
using Bit.Core.Exceptions;
using Bit.Test.Common.AutoFixture;
using Bit.Test.Common.AutoFixture.Attributes;
using Microsoft.AspNetCore.Mvc;
Expand Down Expand Up @@ -34,7 +33,8 @@ public async Task GetAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
.OrganizationOwner(organizationId)
.Returns(false);

await Assert.ThrowsAsync<NotFoundException>(() => sutProvider.Sut.GetAsync(organizationId));
var result = await sutProvider.Sut.GetAsync(organizationId);
Assert.IsType<NotFoundResult>(result.Result);
}

[Theory, BitAutoData]
Expand All @@ -56,8 +56,11 @@ public async Task GetAsync_IntegrationsExist_ReturnsIntegrations(
await sutProvider.GetDependency<IGetOrganizationIntegrationsQuery>().Received(1)
.GetManyByOrganizationAsync(organizationId);

Assert.Equal(integrations.Count, result.Count);
Assert.All(result, r => Assert.IsType<OrganizationIntegrationResponseModel>(r));
Assert.IsType<OkObjectResult>(result.Result);
var okResult = result.Result as OkObjectResult;
var returnedIntegrations = okResult.Value as List<OrganizationIntegrationResponseModel>;
Assert.Equal(integrations.Count, returnedIntegrations.Count);
Assert.All(returnedIntegrations, r => Assert.IsType<OrganizationIntegrationResponseModel>(r));
}

[Theory, BitAutoData]
Expand All @@ -71,11 +74,13 @@ public async Task GetAsync_NoIntegrations_ReturnsEmptyList(
.Returns(true);
sutProvider.GetDependency<IGetOrganizationIntegrationsQuery>()
.GetManyByOrganizationAsync(organizationId)
.Returns([]);
.Returns(new List<OrganizationIntegration>());

var result = await sutProvider.Sut.GetAsync(organizationId);

Assert.Empty(result);
var okResult = result.Result as OkObjectResult;
var returnedIntegrations = okResult.Value as List<OrganizationIntegrationResponseModel>;
Assert.Empty(returnedIntegrations);
}

[Theory, BitAutoData]
Expand Down Expand Up @@ -129,7 +134,7 @@ public async Task CreateAsync_TheTypeAlreadyExists_ThrowsConflict(
}

[Theory, BitAutoData]
public async Task CreateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
public async Task CreateAsync_UserIsNotOrganizationAdmin_ReturnsNotFound(
SutProvider<OrganizationIntegrationController> sutProvider,
Guid organizationId)
{
Expand All @@ -138,8 +143,9 @@ public async Task CreateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
.OrganizationOwner(organizationId)
.Returns(false);

await Assert.ThrowsAsync<NotFoundException>(async () =>
await sutProvider.Sut.CreateAsync(organizationId, _webhookRequestModel));
var response = await sutProvider.Sut.CreateAsync(organizationId, _webhookRequestModel);

Assert.IsType<NotFoundResult>(response.Result);
}

[Theory, BitAutoData]
Expand Down Expand Up @@ -178,7 +184,7 @@ await sutProvider.GetDependency<IDeleteOrganizationIntegrationCommand>().Receive
}

[Theory, BitAutoData]
public async Task DeleteAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
public async Task DeleteAsync_UserIsNotOrganizationAdmin_ReturnsNotFound(
SutProvider<OrganizationIntegrationController> sutProvider,
Guid organizationId,
Guid integrationId)
Expand All @@ -188,8 +194,9 @@ public async Task DeleteAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
.OrganizationOwner(organizationId)
.Returns(false);

await Assert.ThrowsAsync<NotFoundException>(async () =>
await sutProvider.Sut.DeleteAsync(organizationId, integrationId));
var response = await sutProvider.Sut.DeleteAsync(organizationId, integrationId);

Assert.IsType<NotFoundResult>(response);
}

[Theory, BitAutoData]
Expand Down Expand Up @@ -217,12 +224,16 @@ await sutProvider.GetDependency<IUpdateOrganizationIntegrationCommand>().Receive
.UpdateAsync(organizationId, integrationId, Arg.Is<OrganizationIntegration>(i =>
i.OrganizationId == organizationId &&
i.Type == IntegrationType.Webhook));
Assert.IsType<OrganizationIntegrationResponseModel>(response);
Assert.Equal(IntegrationType.Webhook, response.Type);
Assert.IsType<OkObjectResult>(response.Result);
var okResult = response.Result as OkObjectResult;
Assert.NotNull(okResult);
var resultValue = okResult!.Value as OrganizationIntegrationResponseModel;
Assert.NotNull(resultValue);
Assert.Equal(IntegrationType.Webhook, resultValue!.Type);
}

[Theory, BitAutoData]
public async Task UpdateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
public async Task UpdateAsync_UserIsNotOrganizationAdmin_ReturnsNotFound(
SutProvider<OrganizationIntegrationController> sutProvider,
Guid organizationId,
Guid integrationId)
Expand All @@ -232,7 +243,8 @@ public async Task UpdateAsync_UserIsNotOrganizationAdmin_ThrowsNotFound(
.OrganizationOwner(organizationId)
.Returns(false);

await Assert.ThrowsAsync<NotFoundException>(async () =>
await sutProvider.Sut.UpdateAsync(organizationId, integrationId, _webhookRequestModel));
var response = await sutProvider.Sut.UpdateAsync(organizationId, integrationId, _webhookRequestModel);

Assert.IsType<NotFoundResult>(response.Result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ await sutProvider.GetDependency<IFusionCache>().DidNotReceive()
}

[Theory, BitAutoData]
public async Task CreateAsync_IntegrationDoesNotExist_ThrowsNotFound(
public async Task CreateAsync_IntegrationDoesNotExist_ThrowsBadRequest(
SutProvider<CreateOrganizationIntegrationConfigurationCommand> sutProvider,
Guid organizationId,
Guid integrationId,
Expand All @@ -109,7 +109,7 @@ public async Task CreateAsync_IntegrationDoesNotExist_ThrowsNotFound(
.GetByIdAsync(integrationId)
.Returns((OrganizationIntegration)null);

await Assert.ThrowsAsync<NotFoundException>(
await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.CreateAsync(organizationId, integrationId, configuration));

await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().DidNotReceive()
Expand All @@ -121,7 +121,7 @@ await sutProvider.GetDependency<IFusionCache>().DidNotReceive()
}

[Theory, BitAutoData]
public async Task CreateAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFound(
public async Task CreateAsync_IntegrationDoesNotBelongToOrganization_ThrowsBadRequest(
SutProvider<CreateOrganizationIntegrationConfigurationCommand> sutProvider,
Guid organizationId,
Guid integrationId,
Expand All @@ -135,7 +135,7 @@ public async Task CreateAsync_IntegrationDoesNotBelongToOrganization_ThrowsNotFo
.GetByIdAsync(integrationId)
.Returns(integration);

await Assert.ThrowsAsync<NotFoundException>(
await Assert.ThrowsAsync<BadRequestException>(
() => sutProvider.Sut.CreateAsync(organizationId, integrationId, configuration));

await sutProvider.GetDependency<IOrganizationIntegrationConfigurationRepository>().DidNotReceive()
Expand Down
Loading
Loading