1+ using UvA . Workflow . Api . Infrastructure ;
2+ using UvA . Workflow . Api . Submissions . Dtos ;
3+ using UvA . Workflow . Infrastructure ;
4+ using UvA . Workflow . Submissions ;
5+
6+ namespace UvA . Workflow . Api . Submissions ;
7+
8+ public class AnswersController ( AnswerService answerService , RightsService rightsService , ArtifactTokenService artifactTokenService , SubmissionDtoFactory submissionDtoFactory ) : ApiControllerBase
9+ {
10+ [ HttpPost ( "{instanceId}/{submissionId}/{questionName}" ) ]
11+ public async Task < ActionResult < SaveAnswerResponse > > SaveAnswer ( string instanceId , string submissionId , string questionName ,
12+ [ FromBody ] AnswerInput input , CancellationToken ct )
13+ {
14+ var context = await answerService . GetQuestionContext ( instanceId , submissionId , questionName , ct ) ;
15+ await EnsureAuthorizedToEdit ( context ) ;
16+ var answers = await answerService . SaveAnswer ( context , input . Value , ct ) ;
17+ var updatedSubmission = submissionDtoFactory . Create ( context . Instance , context . Form , context . Submission ) ;
18+ return Ok ( new SaveAnswerResponse ( true , answers , updatedSubmission ) ) ;
19+ }
20+
21+ [ HttpPost ( "{instanceId}/{submissionId}/{questionName}/artifacts" ) ]
22+ [ Consumes ( "multipart/form-data" ) ]
23+ [ Produces ( "application/json" ) ]
24+ public async Task < ActionResult < SaveAnswerResponse > > SaveAnswerFile ( string instanceId , string submissionId , string questionName ,
25+ [ FromForm ] SaveAnswerFileRequest request , CancellationToken ct )
26+ {
27+ var context = await answerService . GetQuestionContext ( instanceId , submissionId , questionName , ct ) ;
28+ await EnsureAuthorizedToEdit ( context ) ;
29+ await using var contents = request . File . OpenReadStream ( ) ;
30+ await answerService . SaveArtifact ( context , request . File . FileName , contents , ct ) ;
31+ return Ok ( new SaveAnswerFileResponse ( true ) ) ;
32+ }
33+
34+ [ HttpDelete ( "{instanceId}/{submissionId}/{questionName}/artifacts/{artifactId}" ) ]
35+ public async Task < IActionResult > DeleteAnswerFile ( string instanceId , string submissionId , string questionName , string artifactId , CancellationToken ct )
36+ {
37+ var context = await answerService . GetQuestionContext ( instanceId , submissionId , questionName , ct ) ;
38+ await EnsureAuthorizedToEdit ( context ) ;
39+ await answerService . DeleteArtifact ( context , artifactId , ct ) ;
40+ return Ok ( new SaveAnswerFileResponse ( true ) ) ;
41+ }
42+
43+ [ HttpGet ( "{instanceId}/{submissionId}/{questionName}/artifacts/{artifactId}" ) ]
44+ public async Task < IActionResult > GetAnswerFile ( string instanceId , string submissionId , string questionName ,
45+ string artifactId , [ FromQuery ] string token , CancellationToken ct )
46+ {
47+ if ( ! await artifactTokenService . ValidateAccessToken ( artifactId , token ) )
48+ {
49+ await Task . Delay ( TimeSpan . FromMilliseconds ( 100 ) , ct ) ;
50+ return Unauthorized ( ) ;
51+ }
52+
53+ var context = await answerService . GetQuestionContext ( instanceId , submissionId , questionName , ct ) ;
54+ var file = await answerService . GetArtifact ( context , artifactId , ct ) ;
55+ if ( file == null ) return NotFound ( ) ;
56+ return File ( file . Content , "application/pdf" , file . Info . Name ) ;
57+ }
58+
59+ private async Task EnsureAuthorizedToEdit ( QuestionContext context )
60+ {
61+ var action = context . Submission ? . Date == null ? RoleAction . Submit : RoleAction . Edit ;
62+ if ( ! await rightsService . Can ( context . Instance , action , context . Form . Name ) )
63+ throw new ForbiddenWorkflowActionException ( context . Instance . Id , action , context . Form . Name ) ;
64+ }
65+ }
0 commit comments