11using System ;
22using System . Collections . Generic ;
3- using System . Linq ;
4- using System . Security . Claims ;
3+ using System . IO ;
54using System . Threading . Tasks ;
6- using Hellang . Middleware . ProblemDetails ;
75using Microsoft . AspNetCore . Http ;
86using Microsoft . AspNetCore . Mvc ;
9- using Nesteo . Server . Data ;
10- using Nesteo . Server . Data . Enums ;
11- using Nesteo . Server . IdGeneration ;
7+ using Microsoft . AspNetCore . StaticFiles ;
8+ using Microsoft . Extensions . Logging ;
9+ using Microsoft . Extensions . Options ;
10+ using Nesteo . Server . Filters ;
1211using Nesteo . Server . Models ;
12+ using Nesteo . Server . Options ;
1313using Nesteo . Server . Services ;
1414
1515namespace Nesteo . Server . Controllers . Api
@@ -19,18 +19,18 @@ public class NestingBoxesController : ApiControllerBase
1919 {
2020 private readonly INestingBoxService _nestingBoxService ;
2121 private readonly IInspectionService _inspectionService ;
22- private readonly INestingBoxIdGenerator _nestingBoxIdGenerator ;
23- private readonly IUserService _userService ;
22+ private readonly IOptions < StorageOptions > _storageOptions ;
23+ private readonly ILogger < NestingBoxesController > _logger ;
2424
2525 public NestingBoxesController ( INestingBoxService nestingBoxService ,
2626 IInspectionService inspectionService ,
27- INestingBoxIdGenerator nestingBoxIdGenerator ,
28- IUserService userService )
27+ IOptions < StorageOptions > storageOptions ,
28+ ILogger < NestingBoxesController > logger )
2929 {
3030 _nestingBoxService = nestingBoxService ?? throw new ArgumentNullException ( nameof ( nestingBoxService ) ) ;
3131 _inspectionService = inspectionService ?? throw new ArgumentNullException ( nameof ( inspectionService ) ) ;
32- _nestingBoxIdGenerator = nestingBoxIdGenerator ?? throw new ArgumentNullException ( nameof ( nestingBoxIdGenerator ) ) ;
33- _userService = userService ?? throw new ArgumentNullException ( nameof ( userService ) ) ;
32+ _storageOptions = storageOptions ?? throw new ArgumentNullException ( nameof ( storageOptions ) ) ;
33+ _logger = logger ?? throw new ArgumentNullException ( nameof ( logger ) ) ;
3434 }
3535
3636 /// <summary>
@@ -86,12 +86,17 @@ public async Task<ActionResult<NestingBox>> CreateNestingBoxAsync([FromBody] Nes
8686 /// <param name="nestingBox">The modified nesting box</param>
8787 [ HttpPatch ( "{id}" ) ]
8888 [ ProducesResponseType ( StatusCodes . Status204NoContent ) ]
89- public async Task < ActionResult > EditNestingBoxAsync ( string id , [ FromBody ] NestingBox nestingBox )
89+ public async Task < IActionResult > EditNestingBoxAsync ( string id , [ FromBody ] NestingBox nestingBox )
9090 {
9191 if ( nestingBox . Id == null )
92+ {
9293 nestingBox . Id = id ;
94+ }
9395 else if ( nestingBox . Id != id )
94- return BadRequest ( ) ;
96+ {
97+ ModelState . AddModelError ( "NestingBox.Id" , "Nesting box ID is set but different from the resource URL." ) ;
98+ return BadRequest ( ModelState ) ;
99+ }
95100
96101 // Edit nesting box
97102 nestingBox = await _nestingBoxService . UpdateAsync ( nestingBox , HttpContext . RequestAborted ) . ConfigureAwait ( false ) ;
@@ -101,6 +106,54 @@ public async Task<ActionResult> EditNestingBoxAsync(string id, [FromBody] Nestin
101106 return NoContent ( ) ;
102107 }
103108
109+ /// <summary>
110+ /// Upload a new nesting box image
111+ /// </summary>
112+ /// <remarks>
113+ /// Replaces the old one, when existing.
114+ /// </remarks>
115+ /// <param name="id">Nesting box id</param>
116+ [ HttpPost ( "{id}/upload-image" ) ]
117+ [ DisableFormValueModelBinding ]
118+ [ Consumes ( "multipart/form-data" ) ]
119+ [ ProducesResponseType ( StatusCodes . Status204NoContent ) ]
120+ public async Task < IActionResult > UploadNestingBoxImageAsync ( string id )
121+ {
122+ if ( ! await _nestingBoxService . ExistsIdAsync ( id , HttpContext . RequestAborted ) . ConfigureAwait ( false ) )
123+ return NotFound ( ) ;
124+
125+ string imageFileName = await ReceiveMultipartImageFileUploadAsync ( id , HttpContext . RequestAborted ) . ConfigureAwait ( false ) ;
126+ if ( imageFileName == null )
127+ return BadRequest ( ModelState ) ;
128+
129+ await _nestingBoxService . SetImageFileNameAsync ( id , imageFileName , HttpContext . RequestAborted ) . ConfigureAwait ( false ) ;
130+
131+ return NoContent ( ) ;
132+ }
133+
134+ /// <summary>
135+ /// Download a nesting box image
136+ /// </summary>
137+ /// <param name="id">Nesting box id</param>
138+ [ HttpGet ( "{id}/image" ) ]
139+ [ ProducesResponseType ( StatusCodes . Status200OK ) ]
140+ public async Task < IActionResult > GetNestingBoxImageAsync ( string id )
141+ {
142+ string imageFileName = await _nestingBoxService . GetImageFileNameAsync ( id , HttpContext . RequestAborted ) . ConfigureAwait ( false ) ;
143+ if ( imageFileName == null )
144+ return NotFound ( ) ;
145+
146+ string imageFilePath = Path . Join ( _storageOptions . Value . ImageUploadsDirectoryPath , imageFileName ) ;
147+ var fileInfo = new FileInfo ( imageFilePath ) ;
148+ if ( ! fileInfo . Exists )
149+ return NotFound ( ) ;
150+
151+ string contentType = new FileExtensionContentTypeProvider ( ) . TryGetContentType ( imageFilePath , out string result ) ? result : "application/octet-stream" ;
152+ FileStream fileStream = fileInfo . OpenRead ( ) ;
153+
154+ return File ( fileStream , contentType , true ) ;
155+ }
156+
104157 /// <summary>
105158 /// Preview all nesting boxes with a reduced set of data
106159 /// </summary>
0 commit comments