33using LantanaGroup . Link . DMRP . Data . Entities ;
44using LantanaGroup . Link . DMRP . Models ;
55using LantanaGroup . Link . Shared . Application . Enums ;
6+ using LantanaGroup . Link . Shared . Application . Filters ;
67using LantanaGroup . Link . Shared . Application . Models ;
78using LantanaGroup . Link . Shared . Application . Models . Integration . DMRP ;
89using LantanaGroup . Link . Shared . Application . Services . Security ;
10+ using LantanaGroup . Link . Sdk . Clients ;
911using Link . Authorization . Policies ;
1012using Microsoft . AspNetCore . Authorization ;
1113using Microsoft . AspNetCore . Mvc ;
1214using OpenTelemetry . Trace ;
1315using System . Diagnostics ;
16+ using System . Net ;
1417
1518namespace LantanaGroup . Link . DMRP . Controllers
1619{
@@ -22,12 +25,18 @@ public class MeasureMappingsController : ControllerBase
2225 private readonly ILogger < MeasureMappingsController > _logger ;
2326 private readonly IMeasureMappingManager _manager ;
2427 private readonly IMeasureMappingQueries _queries ;
28+ private readonly IMeasureEvalServiceClient _measureEvalClient ;
2529
26- public MeasureMappingsController ( ILogger < MeasureMappingsController > logger , IMeasureMappingManager manager , IMeasureMappingQueries queries )
30+ public MeasureMappingsController (
31+ ILogger < MeasureMappingsController > logger ,
32+ IMeasureMappingManager manager ,
33+ IMeasureMappingQueries queries ,
34+ IMeasureEvalServiceClient measureEvalClient )
2735 {
2836 _logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
2937 _manager = manager ?? throw new ArgumentNullException ( nameof ( manager ) ) ;
3038 _queries = queries ?? throw new ArgumentNullException ( nameof ( queries ) ) ;
39+ _measureEvalClient = measureEvalClient ?? throw new ArgumentNullException ( nameof ( measureEvalClient ) ) ;
3140 }
3241
3342 /// <summary>
@@ -36,26 +45,14 @@ public MeasureMappingsController(ILogger<MeasureMappingsController> logger, IMea
3645 [ ProducesResponseType ( StatusCodes . Status200OK , Type = typeof ( PagedMeasureMappingDto ) ) ]
3746 [ ProducesResponseType ( StatusCodes . Status204NoContent ) ]
3847 [ ProducesResponseType ( StatusCodes . Status500InternalServerError ) ]
39- [ HttpGet ( Name = "GetMeasureMappings" ) ]
40- public async Task < IActionResult > GetMeasureMappings ( string ? sortBy , SortOrder ? sortOrder ,
41- int pageSize = 10 , int pageNumber = 1 , CancellationToken cancellationToken = default )
48+ [ HttpGet ( "search" ) ]
49+ public async Task < IActionResult > GetMeasureMappings ( [ FromQuery ] SearchMeasureMappingDto searchDto , CancellationToken cancellationToken = default )
4250 {
43- sortBy = sortBy ? . Sanitize ( ) ;
44-
45- if ( pageSize < 1 || pageSize > 100 )
46- {
47- pageSize = 10 ;
48- }
49-
50- if ( pageNumber < 1 )
51- {
52- pageNumber = 1 ;
53- }
51+ searchDto . Sanitize ( ) ;
5452
5553 using Activity ? activity = ServiceActivitySource . Instance . StartActivity ( "Get Measure Mappings" ) ;
5654
57- var result = await _queries . PagedSearchAsync ( sortBy ?? "Id" , sortOrder ?? SortOrder . Descending ,
58- pageSize , pageNumber , cancellationToken ) ;
55+ var result = await _queries . PagedSearchAsync ( searchDto , cancellationToken ) ;
5956
6057 if ( result . Records . Count == 0 )
6158 {
@@ -91,30 +88,47 @@ public async Task<IActionResult> GetMeasureMapping(string id, CancellationToken
9188 /// </summary>
9289 [ ProducesResponseType ( StatusCodes . Status201Created , Type = typeof ( MeasureMappingModel ) ) ]
9390 [ ProducesResponseType ( StatusCodes . Status400BadRequest ) ]
91+ [ ProducesResponseType ( StatusCodes . Status502BadGateway , Type = typeof ( ProblemDetails ) ) ]
9492 [ ProducesResponseType ( StatusCodes . Status500InternalServerError ) ]
93+ [ ValidateAntiForgeryOrBearerToken ]
9594 [ HttpPost ]
9695 public async Task < IActionResult > CreateMeasureMapping ( MeasureMappingModel request , CancellationToken cancellationToken )
9796 {
9897 MeasureMapping created ;
9998
10099 try
101100 {
102- var entity = new MeasureMapping ( ) ;
103- // TODO: Map `request` to `entity`
101+ var entity = ToEntity ( request ) ;
102+ if ( ! await DqmExistsAsync ( entity . DQM , cancellationToken ) )
103+ {
104+ return BadRequest ( $ "DQM '{ entity . DQM } ' was not found in MeasureEval.") ;
105+ }
106+
104107 created = await _manager . CreateAsync ( entity , cancellationToken ) ;
105108 }
106- catch ( ApplicationException ex )
109+ catch ( DuplicateMeasureMappingException )
110+ {
111+ return ValidationProblem ( new ValidationProblemDetails ( new Dictionary < string , string [ ] >
112+ {
113+ [ "measure" ] = [ "A measure mapping for this measure and dQM already exists." ]
114+ } ) ) ;
115+ }
116+ catch ( ApplicationException )
117+ {
118+ return BadRequest ( ) ;
119+ }
120+ catch ( HttpRequestException ex )
107121 {
108- return BadRequest ( ex . Message ) ;
122+ _logger . LogError ( ex , "MeasureEval failed while verifying the DQM for a measure mapping." ) ;
123+ return Problem ( "Unable to verify the DQM in MeasureEval." , statusCode : StatusCodes . Status502BadGateway ) ;
109124 }
110125 catch ( Exception ex )
111126 {
112127 _logger . LogError ( ex , "Exception encountered in MeasureMappingsController.CreateMeasureMapping" ) ;
113128 return Problem ( "An error occurred while creating the measure mapping" , null , 500 ) ;
114129 }
115130
116- var model = new MeasureMappingModel { Id = created . Id } ;
117- // TODO: Map `created` to `model`
131+ var model = ToModel ( created ) ;
118132
119133 return Created ( $ "/api/dmrp/measure-mappings/{ model . Id } ", model ) ;
120134 }
@@ -125,7 +139,9 @@ public async Task<IActionResult> CreateMeasureMapping(MeasureMappingModel reques
125139 [ ProducesResponseType ( StatusCodes . Status202Accepted , Type = typeof ( MeasureMappingModel ) ) ]
126140 [ ProducesResponseType ( StatusCodes . Status400BadRequest ) ]
127141 [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
142+ [ ProducesResponseType ( StatusCodes . Status502BadGateway , Type = typeof ( ProblemDetails ) ) ]
128143 [ ProducesResponseType ( StatusCodes . Status500InternalServerError ) ]
144+ [ ValidateAntiForgeryOrBearerToken ]
129145 [ HttpPut ( "{id}" ) ]
130146 public async Task < IActionResult > UpdateMeasureMapping ( string id , MeasureMappingModel request , CancellationToken cancellationToken )
131147 {
@@ -138,12 +154,32 @@ public async Task<IActionResult> UpdateMeasureMapping(string id, MeasureMappingM
138154
139155 try
140156 {
141- await _manager . UpdateAsync ( id , new MeasureMapping { Id = id } , cancellationToken ) ;
157+ var entity = ToEntity ( request ) ;
158+ entity . Id = id ;
159+
160+ if ( ! await DqmExistsAsync ( entity . DQM , cancellationToken ) )
161+ {
162+ return BadRequest ( $ "DQM '{ entity . DQM } ' was not found in MeasureEval.") ;
163+ }
164+
165+ await _manager . UpdateAsync ( id , entity , cancellationToken ) ;
166+ }
167+ catch ( DuplicateMeasureMappingException )
168+ {
169+ return ValidationProblem ( new ValidationProblemDetails ( new Dictionary < string , string [ ] >
170+ {
171+ [ "measure" ] = [ "A measure mapping for this measure and dQM already exists." ]
172+ } ) ) ;
142173 }
143174 catch ( ApplicationException ex )
144175 {
145176 return NotFound ( ex . Message ) ;
146177 }
178+ catch ( HttpRequestException ex )
179+ {
180+ _logger . LogError ( ex , "MeasureEval failed while verifying the DQM for a measure mapping." ) ;
181+ return Problem ( "Unable to verify the DQM in MeasureEval." , statusCode : StatusCodes . Status502BadGateway ) ;
182+ }
147183 catch ( Exception ex )
148184 {
149185 _logger . LogError ( ex , "Exception encountered in MeasureMappingsController.UpdateMeasureMapping" ) ;
@@ -182,5 +218,60 @@ public async Task<IActionResult> DeleteMeasureMapping(string id, CancellationTok
182218
183219 return NoContent ( ) ;
184220 }
221+
222+ /// <summary>
223+ /// Deletes all measure mappings.
224+ /// </summary>
225+ [ ProducesResponseType ( StatusCodes . Status204NoContent ) ]
226+ [ ProducesResponseType ( StatusCodes . Status404NotFound ) ]
227+ [ ProducesResponseType ( StatusCodes . Status500InternalServerError ) ]
228+ [ ValidateAntiForgeryOrBearerToken ]
229+ [ HttpDelete ]
230+ public async Task < IActionResult > DeleteAllMeasureMappings ( CancellationToken cancellationToken )
231+ {
232+ try
233+ {
234+ await _manager . DeleteAllAsync ( cancellationToken ) ;
235+ }
236+ catch ( Exception ex )
237+ {
238+ _logger . LogError ( ex , "Exception encountered in MeasureMappingsController.DeleteAllMeasureMappings" ) ;
239+ return Problem ( "An error occurred while deleting the measure mappings" , null , 500 ) ;
240+ }
241+
242+ return NoContent ( ) ;
243+ }
244+
245+ private static MeasureMapping ToEntity ( MeasureMappingModel model ) => new ( )
246+ {
247+ Measure = model . Measure ? . Sanitize ( ) ?? "" ,
248+ DQM = model . DQM ? . Sanitize ( ) ?? "" ,
249+ Frequency = model . Frequency ?? Frequency . Adhoc
250+ } ;
251+
252+ private static MeasureMappingModel ToModel ( MeasureMapping entity ) => new ( )
253+ {
254+ Id = entity . Id ,
255+ Measure = entity . Measure ,
256+ DQM = entity . DQM ,
257+ Frequency = entity . Frequency
258+ } ;
259+
260+ private async Task < bool > DqmExistsAsync ( string dqm , CancellationToken cancellationToken )
261+ {
262+ var response = await _measureEvalClient . GetMeasureDefinitionAsync ( dqm , cancellationToken ) ;
263+
264+ if ( response . StatusCode == StatusCodes . Status404NotFound )
265+ {
266+ return false ;
267+ }
268+
269+ if ( ! response . IsSuccessStatusCode )
270+ {
271+ throw new HttpRequestException ( $ "MeasureEval returned status code { response . StatusCode } while verifying a DQM.", null , ( HttpStatusCode ) response . StatusCode ) ;
272+ }
273+
274+ return true ;
275+ }
185276 }
186277}
0 commit comments