d9d68405ab
«Редактирование заявок» и «Заявки по согласующему» раньше читали списки SharePoint напрямую с фронтенда (PnP от имени залогиненного администратора), из-за чего видимые заявки молча урезались правами САМОГО администратора на списки. Добавлен RequestManageService/RequestManageController на бэкенде (app-only SharePointClient, по образцу ReminderService) — теперь чтение (поиск заявки, матрица маршрута, строки по согласующему) идёт через него, а правка (переназначить/удалить/переставить/уведомить) остаётся на PnP. Заодно кнопка уведомления в таблице маршрута включена и для строк в статусе «Возвращена на доработку» — по клику поток Power Automate уведомляет автора заявки, что её вернули на доработку. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
58 lines
3.1 KiB
C#
58 lines
3.1 KiB
C#
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Tnsu.ApprovalRoute.Api.Common;
|
|
using Tnsu.ApprovalRoute.Application.RequestManage;
|
|
|
|
namespace Tnsu.ApprovalRoute.Api.Controllers;
|
|
|
|
/// <summary>
|
|
/// Чтение заявок и маршрутов согласования от имени приложения (см.
|
|
/// RequestManageService) — для вкладок «Редактирование заявок» и «Заявки по
|
|
/// согласующему»: результат не зависит от прав вызывающего пользователя на
|
|
/// списки SharePoint, в отличие от прежнего прямого PnP-чтения с фронтенда.
|
|
/// </summary>
|
|
[ApiController]
|
|
[Authorize]
|
|
[Route("api/request-manage")]
|
|
[Produces("application/json")]
|
|
public sealed class RequestManageController(RequestManageService service) : ControllerBase
|
|
{
|
|
/// <summary>Заявки типа requestTypeId по всем партициям (архив + текущая), постранично.</summary>
|
|
[HttpGet("search")]
|
|
[ProducesResponseType(typeof(ApiResponse<ManagedRequestPageDto>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
|
|
public async Task<IActionResult> Search(
|
|
[FromQuery] int requestTypeId,
|
|
[FromQuery] string query,
|
|
[FromQuery] int page,
|
|
[FromQuery] int? pageSize,
|
|
CancellationToken ct) =>
|
|
(await service.SearchAsync(requestTypeId, query ?? string.Empty, page < 1 ? 1 : page, pageSize, ct)).ToActionResult();
|
|
|
|
/// <summary>Заявка + полный маршрут согласования (обе фазы, по StepOrder).</summary>
|
|
[HttpGet("matrix")]
|
|
[ProducesResponseType(typeof(ApiResponse<ManagedRequestMatrixDto>), StatusCodes.Status200OK)]
|
|
[ProducesResponseType(typeof(ApiError), StatusCodes.Status404NotFound)]
|
|
[ProducesResponseType(typeof(ApiError), StatusCodes.Status400BadRequest)]
|
|
public async Task<IActionResult> Matrix(
|
|
[FromQuery] int requestTypeId, [FromQuery] string listId, [FromQuery] int requestId, CancellationToken ct) =>
|
|
(await service.GetMatrixAsync(requestTypeId, listId, requestId, ct)).ToActionResult();
|
|
|
|
/// <summary>
|
|
/// Активные строки согласования одного человека сразу по всем типам заявок и
|
|
/// партициям. statuses — через запятую (см. REQUEST_STATUS во фронтенде).
|
|
/// </summary>
|
|
[HttpGet("by-approver")]
|
|
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<UserApprovalRowDto>>), StatusCodes.Status200OK)]
|
|
public async Task<IActionResult> ByApprover(
|
|
[FromQuery] string approverEmail, [FromQuery] string statuses, CancellationToken ct)
|
|
{
|
|
var activeStatuses = (statuses ?? string.Empty)
|
|
.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
|
|
.ToList();
|
|
|
|
return (await service.FindActiveApprovalRowsForApproverAsync(approverEmail ?? string.Empty, activeStatuses, ct))
|
|
.ToActionResult();
|
|
}
|
|
}
|