Files
2026-06-23 11:18:54 -05:00

241 lines
11 KiB
C#

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Strata.Analytics.Api.Authorization;
using Strata.Analytics.Biz.DataQuery;
using Strata.Analytics.Biz.DataSources.Models;
using Strata.Analytics.Biz.DataSources.Services;
using Strata.Analytics.Biz.Export.Models;
using Strata.Analytics.Biz.Export.Services;
using Strata.Analytics.Models.Utils;
using Strata.DataSchema.Models.Query;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Strata.Analytics.Api.Controllers
{
[ApiController]
[ApiVersion("1.0")]
[Route("api/v{api-version:apiVersion}/[controller]")]
public class DataSourcesController : ControllerBase
{
private readonly IDataSourceService _dataSourceService;
private readonly IDataQueryService _dataQueryService;
private readonly IExportService _exportService;
private readonly ILogger<DataSourcesController> _logger;
public DataSourcesController(IDataSourceService dataSourceService, IDataQueryService dataQueryService, IExportService exportService, ILogger<DataSourcesController> logger)
{
_dataSourceService = dataSourceService;
_dataQueryService = dataQueryService;
_exportService = exportService;
_logger = logger;
}
[HttpGet]
public async Task<IEnumerable<DataSource>> GetDataSourcesAsync(CancellationToken cancellationToken)
{
return await _dataSourceService.GetAllAsync(cancellationToken);
}
[HttpGet("{dataSourceId}")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<DataSource>> GetById(int dataSourceId, CancellationToken cancellationToken)
{
var dataSource = await _dataSourceService.GetByIdAsync(dataSourceId, cancellationToken);
if (dataSource == null)
{
return NotFound();
}
return Ok(dataSource);
}
[HttpPut("{dataSourceId}")]
[Authorize(Policy = Policies.DataSourceEditor)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<DataSource>> Update(int dataSourceId, DataSourceSaveInfo dataSourceSaveInfo, CancellationToken cancellationToken)
{
var isFound = await _dataSourceService.ContainsAsync(dataSourceId, cancellationToken);
if (!isFound)
{
return NotFound();
}
var updatedDataSource = await _dataSourceService.UpdateAsync(dataSourceId, dataSourceSaveInfo, cancellationToken);
return Ok(updatedDataSource);
}
[HttpPut("")]
[Authorize(Policy = Policies.DataSourceEditor)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<DataSource>> Save(DataSourceSaveInfo dataSourceSaveInfo, CancellationToken cancellationToken)
{
var isFound = await _dataSourceService.ContainsAsync(dataSourceSaveInfo.DataSourceId, cancellationToken);
if (!isFound)
{
return NotFound();
}
var updatedDataSource = await _dataSourceService.SaveAsync(dataSourceSaveInfo, cancellationToken);
return Ok(updatedDataSource);
}
[HttpDelete("{dataSourceId}")]
[Authorize(Policy = Policies.DataSourceEditor)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<IActionResult> Delete(int dataSourceId, CancellationToken cancellationToken)
{
await _dataSourceService.DeleteAsync(dataSourceId, cancellationToken);
return NoContent();
}
[HttpPost("")]
[Authorize(Policy = Policies.StrataOnly)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
public async Task<ActionResult<DataSource>> Create(DataSourceSaveInfo dataSourceSaveInfo, CancellationToken cancellationToken)
{
return await _dataSourceService.CreateAsync(dataSourceSaveInfo, cancellationToken);
}
[HttpPost("{dataSourceId}/tables/{dataTableId}")]
[Authorize(Policy = Policies.DataSourceEditor)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult<DataSourceTable>> AddDataTableLink([FromRoute] int dataSourceId, [FromRoute] int dataTableId, CancellationToken cancellationToken)
{
return await _dataSourceService.AddDataTableAsync(dataSourceId, dataTableId, cancellationToken);
}
[HttpDelete("{dataSourceId}/tables/{dataTableId}")]
[Authorize(Policy = Policies.DataSourceEditor)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult> DeleteDataTableLink([FromRoute] int dataSourceId, [FromRoute] int dataTableId, CancellationToken cancellationToken)
{
await _dataSourceService.DeleteDataTableAsync(dataSourceId, dataTableId, cancellationToken);
return NoContent();
}
[HttpGet("{dataSourceId}/role-assignments")]
[Authorize(Policy = Policies.DataSourceViewer)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult<IEnumerable<DataSourceRoleAssignment>>> GetRoleAssignments([FromRoute] int dataSourceId, CancellationToken cancellationToken)
{
return Ok(await _dataSourceService.GetRoleAssignmentsAsync(new List<int> { dataSourceId }, cancellationToken));
}
[HttpPost("{dataSourceId}/role-assignments/batch")]
[Authorize(Policy = Policies.DataSourceEditor)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult<IEnumerable<DataSourceRoleAssignment>>> SaveRoleAssignments([FromRoute] int dataSourceId, [FromBody] Batch<DataSourceRoleAssignmentSaveInfo, Guid> roleAssignments, CancellationToken cancellationToken)
{
return Ok(await _dataSourceService.SaveRoleAssignmentsAsync(dataSourceId, roleAssignments, cancellationToken));
}
[HttpPost("{dataSourceId}/datacolumn/values")]
[Authorize(Policy = Policies.DataSourceViewer)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult<IEnumerable<dynamic>>> GetColumnValues([FromRoute] int dataSourceId, [FromBody] ColumnQueryConfig columnQueryConfig, CancellationToken cancellationToken)
{
try
{
return Ok(await _dataQueryService.GetColumnValues(columnQueryConfig, cancellationToken));
}
catch (UnauthorizedAccessException)
{
var dataColumnIds = new List<int> { columnQueryConfig.DataColumnId };
if (columnQueryConfig.Filter != null)
dataColumnIds.Add(columnQueryConfig.Filter.DataColumnId);
_logger.LogWarning(
"Attempted to {method} for data source {dataSourceId} with the following data column ids {dataColumnIds}",
nameof(GetColumnValues),
dataSourceId,
dataColumnIds);
return Forbid();
}
}
[HttpPost("{dataSourceId}/query")]
[Authorize(Policy = Policies.DataSourceViewer)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult<IEnumerable<dynamic>>> QueryData([FromRoute] int dataSourceId, [FromBody] QueryConfig query, CancellationToken cancellationToken)
{
try
{
return Ok(await _dataQueryService.QueryData(query, cancellationToken));
}
catch (UnauthorizedAccessException)
{
_logger.LogWarning(
"Attempted to {method} for data source {dataSourceId} with the following data column ids {dataColumnIds}",
nameof(QueryData),
dataSourceId,
query.GetAllColumnIds());
return Forbid();
}
}
[HttpPost("query")]
[Authorize(Policy = Policies.StrataOnly)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesDefaultResponseType]
public async Task<ActionResult<SqlResponse>> GetSqlQuery(QueryConfig queryConfig, CancellationToken cancellationToken)
{
try
{
return Ok(await _dataQueryService.BuildSqlQuery(queryConfig, cancellationToken));
}
catch (UnauthorizedAccessException)
{
_logger.LogWarning(
"Attempted to {method} with the following data column ids {dataColumnIds}",
nameof(GetSqlQuery),
queryConfig.GetAllColumnIds());
return Forbid();
}
}
[HttpPost("{dataSourceId}/download")]
[Authorize(Policy = Policies.DataSourceViewer)]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesDefaultResponseType]
public async Task<ActionResult> DownloadDataSheet([FromRoute] int dataSourceId, [FromBody] ExportDataSheetRequest request, CancellationToken cancellationToken)
{
var stream = await _exportService.DownloadDataSheet(request, cancellationToken);
return File(stream, "application/octet-stream");
}
}
}