Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
C
ClientServer
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
YAPEX
ClientServer
Commits
2173544c
Commit
2173544c
authored
5 years ago
by
Janis Daniel Dähne
Browse files
Options
Downloads
Patches
Plain Diff
- ensured that only the right users can download the right assets
- formatting
parent
34932efb
No related branches found
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
src/ClientServer/Controllers/Core/Exercises/DownloadAssetController.cs
+108
-55
108 additions, 55 deletions
...ver/Controllers/Core/Exercises/DownloadAssetController.cs
with
108 additions
and
55 deletions
src/ClientServer/Controllers/Core/Exercises/DownloadAssetController.cs
+
108
−
55
View file @
2173544c
...
...
@@ -15,14 +15,26 @@ using Microsoft.Extensions.Primitives;
namespace
ClientServer.Controllers.Core.Exercises
{
[
Route
(
Constants
.
ApiPrefix
+
"assets"
)]
public
class
Test
AssetController
:
ControllerWithDb
public
class
Download
AssetController
:
ControllerWithDb
{
public
TestAssetController
(
SyndromDbContext
context
)
:
base
(
context
)
/*
* no participation --> not allowed to download asset
* if we set this the browser will not download the json response as a file?? (TODO check that)
* Response.StatusCode = 406;
*
*
* we don't need methods to download exercise description or custom project description assets
* because the frontend already loads the content and thus can locally "download" the file (via blobs)
*/
public
DownloadAssetController
(
SyndromDbContext
context
)
:
base
(
context
)
{
}
/// <summary>
/// gets (downloads) the test asset
/// gets (downloads) the
normal/submit
test asset
/// </summary>
/// <param name="generatedCode">the release code</param>
/// <param name="testId">the test id</param>
...
...
@@ -37,17 +49,27 @@ namespace ClientServer.Controllers.Core.Exercises
int
userId
=
GetUserId
();
int
exerciseId
;
if
(
asTutor
)
{
//check if the user is really a tutor for this exercise (group)
var
targetUserGroupId
=
var
exerciseDataTuple
=
await
_context
.
ExerciseReleases
.
Where
(
p
=>
p
.
GeneratedCode
==
generatedCode
)
.
Select
(
p
=>
p
.
Exercise
.
UserGroupId
)
.
Select
(
p
=>
new
{
p
.
Exercise
.
UserGroupId
,
p
.
ExerciseId
}
)
.
FirstOrDefaultAsync
();
if
(!
await
base
.
HasGroupPermission
(
targetUserGroupId
,
if
(
exerciseDataTuple
==
null
)
{
Response
.
StatusCode
=
406
;
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"participation not found"
)));
return
;
}
if
(!
await
base
.
HasGroupPermission
(
exerciseDataTuple
.
UserGroupId
,
permission
=>
permission
!=
null
&&
permission
.
CanAssessExercises
))
{
Response
.
StatusCode
=
406
;
...
...
@@ -56,6 +78,8 @@ namespace ClientServer.Controllers.Core.Exercises
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NoPermission
,
"no permission"
)));
return
;
}
exerciseId
=
exerciseDataTuple
.
ExerciseId
;
}
else
{
...
...
@@ -76,6 +100,15 @@ namespace ClientServer.Controllers.Core.Exercises
return
;
}
if
(
participation
.
ExerciseRelease
==
null
)
{
Response
.
StatusCode
=
406
;
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"exercise release not found"
)));
return
;
}
if
(
isSubmitTest
)
{
//submit tests are only displayed when the release is finished...
...
...
@@ -93,14 +126,17 @@ namespace ClientServer.Controllers.Core.Exercises
return
;
}
}
exerciseId
=
participation
.
ExerciseRelease
.
ExerciseId
;
}
var
asset
=
await
this
.
GetTestNormalOrSubmitTestAsset
(
testId
,
assetId
,
isSubmitTest
);
var
asset
=
await
this
.
_
GetTestNormalOrSubmitTestAsset
(
testId
,
assetId
,
exerciseId
,
isSubmitTest
);
if
(
asset
==
null
)
{
//already handled
return
;
}
else
if
(
asset
.
Content
==
null
)
{
...
...
@@ -129,24 +165,28 @@ namespace ClientServer.Controllers.Core.Exercises
/// </summary>
/// <param name="testId">the test id</param>
/// <param name="assetId">the asset id</param>
/// <param name="exerciseId"></param>
/// <param name="isSubmitTest">true: submit test, false: not</param>
/// <returns>the asset or null if not found or error</returns>
private
async
Task
<
TempTestAsset
>
GetTestNormalOrSubmitTestAsset
(
int
testId
,
int
assetId
,
bool
isSubmitTest
)
private
async
Task
<
TempTestAsset
>
_GetTestNormalOrSubmitTestAsset
(
int
testId
,
int
assetId
,
int
exerciseId
,
bool
isSubmitTest
)
{
//ensure that this is the right asset (check testId too)
//calling method ensured that the user has access to the test
var
connection
=
await
_context
.
TestWithFileAsAssetReferences
.
Include
(
p
=>
p
.
FileReferenceTestAsset
)
.
FirstOrDefaultAsync
(
p
=>
p
.
TestId
==
testId
&&
p
.
FileReferenceTestAssetId
==
assetId
);
.
FirstOrDefaultAsync
(
p
=>
p
.
TestId
==
testId
&&
p
.
Test
.
ExerciseId
==
exerciseId
&&
p
.
FileReferenceTestAssetId
==
assetId
);
if
(
connection
==
null
)
if
(
connection
==
null
)
{
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference connection not found"
)));
return
null
;
}
if
(
connection
.
FileReferenceTestAsset
==
null
)
{
await
...
...
@@ -154,12 +194,12 @@ namespace ClientServer.Controllers.Core.Exercises
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference not found"
)));
return
null
;
}
var
testAssetsBasePath
=
Files
.
GetUploadFilePath
(
UploadDirType
.
TestAssets
);
var
testFilesDict
=
await
Files
.
ReadUploadedFilesAsArray
(
testAssetsBasePath
,
connection
.
FileReferenceTestAsset
.
Id
);
var
testFilesDict
=
await
Files
.
ReadUploadedFilesAsArray
(
testAssetsBasePath
,
connection
.
FileReferenceTestAsset
.
Id
);
var
fileName
=
"asset"
;
if
(
Files
.
ValidFileName
(
connection
.
FileReferenceTestAsset
.
OriginalName
))
...
...
@@ -170,7 +210,8 @@ namespace ClientServer.Controllers.Core.Exercises
{
//just try to get a file extension...
var
lastIndex
=
connection
.
FileReferenceTestAsset
.
OriginalName
.
LastIndexOf
(
"."
,
StringComparison
.
Ordinal
);
var
lastIndex
=
connection
.
FileReferenceTestAsset
.
OriginalName
.
LastIndexOf
(
"."
,
StringComparison
.
Ordinal
);
if
(
lastIndex
==
-
1
)
{
//no file extension...
...
...
@@ -224,30 +265,33 @@ namespace ClientServer.Controllers.Core.Exercises
var
connection
=
await
_context
.
CustomTestWithFileAsAssetReferences
.
Include
(
p
=>
p
.
FileReferenceUserFileAsset
)
.
FirstOrDefaultAsync
(
p
=>
p
.
CustomTestId
==
customTestId
&&
p
.
CustomTest
.
UserId
==
userId
&&
p
.
CustomTestId
==
customTestId
&&
p
.
CustomTest
.
ExerciseReleaseId
==
participation
.
ExerciseReleaseId
&&
p
.
CustomTest
.
UserId
==
userId
&&
p
.
FileReferenceUserFileAssetId
==
assetId
)
;
if
(
connection
==
null
)
{
Response
.
StatusCode
=
406
;
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset connection not found"
)));
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset connection not found"
)));
return
;
}
var
testAsset
=
connection
.
FileReferenceUserFileAsset
;
if
(
testAsset
==
null
)
{
Response
.
StatusCode
=
406
;
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference not found"
)));
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference not found"
)));
return
;
}
var
fileName
=
"asset"
;
if
(
Files
.
ValidFileName
(
testAsset
.
OriginalName
))
...
...
@@ -271,8 +315,8 @@ namespace ClientServer.Controllers.Core.Exercises
}
}
var
filesIdsToRead
=
new
int
[]
{
connection
.
FileReferenceUserFileAssetId
};
var
filesIdsToRead
=
new
int
[]
{
connection
.
FileReferenceUserFileAssetId
};
var
basePath
=
Files
.
GetUploadFilePath
(
UploadDirType
.
UserAssets
);
var
filesDict
=
await
Files
.
ReadUploadedFilesAsArray
(
basePath
,
filesIdsToRead
);
...
...
@@ -282,22 +326,22 @@ namespace ClientServer.Controllers.Core.Exercises
if
(
content
==
null
)
{
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset content not found"
)));
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset content not found"
)));
return
;
}
//see https://stackoverflow.com/questions/20508788/do-i-need-content-type-application-octet-stream-for-file-download
Response
.
ContentType
=
"application/octet-stream"
;
//overwrite global json response
Response
.
Headers
.
Add
(
new
KeyValuePair
<
string
,
StringValues
>(
"Content-Disposition"
,
"attachment; filename=\""
+
fileName
+
"\""
));
await
Response
.
Body
.
WriteAsync
(
content
,
0
,
content
.
Length
);
await
Response
.
Body
.
FlushAsync
();
}
/// <summary>
/// gets (downloads) the custom project custom test asset
/// </summary>
...
...
@@ -311,7 +355,7 @@ namespace ClientServer.Controllers.Core.Exercises
if
(!
await
base
.
IsLoggedIn
(
null
,
false
,
false
))
return
;
int
userId
=
GetUserId
();
var
customProject
=
await
_context
.
CustomProjects
.
FirstOrDefaultAsync
(
p
=>
p
.
UserId
==
userId
&&
//just ensure the project is from the current user
p
.
Id
==
customProjectId
)
...
...
@@ -324,9 +368,8 @@ namespace ClientServer.Controllers.Core.Exercises
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"custom project not found"
)));
return
;
}
var
oldTest
=
await
_context
.
CustomProjectTests
.
Where
(
p
=>
p
.
Id
==
customTestId
&&
p
.
CustomProjectId
==
customProjectId
)
...
...
@@ -340,35 +383,37 @@ namespace ClientServer.Controllers.Core.Exercises
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"test not found"
)));
return
;
}
var
connection
=
await
_context
.
CustomProjectTestWithFileAsAssetReferences
var
connection
=
await
_context
.
CustomProjectTestWithFileAsAssetReferences
.
Include
(
p
=>
p
.
FileReferenceUserFileAsset
)
.
FirstOrDefaultAsync
(
p
=>
p
.
CustomProjectTestId
==
customTestId
&&
p
.
CustomProjectTest
.
CustomProjectId
==
customProject
.
Id
&&
p
.
CustomProjectTestId
==
customTestId
&&
p
.
CustomProjectTest
.
CustomProjectId
==
customProject
.
Id
&&
p
.
FileReferenceUserFileAssetId
==
assetId
)
;
if
(
connection
==
null
)
{
Response
.
StatusCode
=
406
;
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset connection not found"
)));
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset connection not found"
)));
return
;
}
var
testAsset
=
connection
.
FileReferenceUserFileAsset
;
if
(
testAsset
==
null
)
{
Response
.
StatusCode
=
406
;
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference not found"
)));
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference not found"
)));
return
;
}
var
fileName
=
"asset"
;
if
(
Files
.
ValidFileName
(
testAsset
.
OriginalName
))
...
...
@@ -392,8 +437,8 @@ namespace ClientServer.Controllers.Core.Exercises
}
}
var
filesIdsToRead
=
new
int
[]
{
connection
.
FileReferenceUserFileAssetId
};
var
filesIdsToRead
=
new
int
[]
{
connection
.
FileReferenceUserFileAssetId
};
var
basePath
=
Files
.
GetUploadFilePath
(
UploadDirType
.
UserAssets
);
var
filesDict
=
await
Files
.
ReadUploadedFilesAsArray
(
basePath
,
filesIdsToRead
);
...
...
@@ -403,20 +448,19 @@ namespace ClientServer.Controllers.Core.Exercises
if
(
content
==
null
)
{
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset content not found"
)));
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset content not found"
)));
return
;
}
//see https://stackoverflow.com/questions/20508788/do-i-need-content-type-application-octet-stream-for-file-download
Response
.
ContentType
=
"application/octet-stream"
;
//overwrite global json response
Response
.
Headers
.
Add
(
new
KeyValuePair
<
string
,
StringValues
>(
"Content-Disposition"
,
"attachment; filename=\""
+
fileName
+
"\""
));
await
Response
.
Body
.
WriteAsync
(
content
,
0
,
content
.
Length
);
await
Response
.
Body
.
FlushAsync
();
}
/// <summary>
...
...
@@ -426,14 +470,15 @@ namespace ClientServer.Controllers.Core.Exercises
/// <param name="testId">the test id</param>
/// <param name="assetId">the asset reference id</param>
[
HttpGet
(
"editor/{exerciseId}/{testId}/{assetId}"
)]
public
async
Task
GetTestAssetWithoutReleaseCode
(
int
exerciseId
,
int
testId
,
int
assetId
)
public
async
Task
Get
ExerciseEditor
TestAssetWithoutReleaseCode
(
int
exerciseId
,
int
testId
,
int
assetId
)
{
if
(!
await
base
.
IsLoggedIn
(
null
,
false
,
false
))
return
;
int
userId
=
GetUserId
();
int
managingGroupId
=
await
_context
.
Exercises
.
Where
(
p
=>
p
.
Id
==
exerciseId
).
Select
(
p
=>
p
.
UserGroupId
)
.
Where
(
p
=>
p
.
Id
==
exerciseId
)
.
Select
(
p
=>
p
.
UserGroupId
)
.
FirstOrDefaultAsync
();
if
(
managingGroupId
==
default
(
int
))
...
...
@@ -447,6 +492,7 @@ namespace ClientServer.Controllers.Core.Exercises
//the user group that WILL manages the exercise (after the change)
var
targetUserGroup
=
await
_context
.
UserGroups
.
FirstOrDefaultAsync
(
p
=>
p
.
Id
==
managingGroupId
);
if
(
targetUserGroup
==
null
)
{
Response
.
StatusCode
=
406
;
...
...
@@ -475,17 +521,19 @@ namespace ClientServer.Controllers.Core.Exercises
//ensure that this is the right asset (check testId too)
var
connection
=
await
_context
.
TestWithFileAsAssetReferences
.
Include
(
p
=>
p
.
FileReferenceTestAsset
)
.
FirstOrDefaultAsync
(
p
=>
p
.
TestId
==
testId
&&
p
.
FileReferenceTestAssetId
==
assetId
);
.
FirstOrDefaultAsync
(
p
=>
p
.
TestId
==
testId
&&
p
.
Test
.
ExerciseId
==
exerciseId
&&
p
.
FileReferenceTestAssetId
==
assetId
);
if
(
connection
==
null
)
if
(
connection
==
null
)
{
await
Response
.
WriteAsync
(
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference connection not found"
)));
return
;
}
if
(
connection
.
FileReferenceTestAsset
==
null
)
{
await
...
...
@@ -493,10 +541,11 @@ namespace ClientServer.Controllers.Core.Exercises
Jc
.
Serialize
(
new
BasicResponse
(
ResponseCode
.
NotFound
,
"asset reference not found"
)));
return
;
}
var
testAssetsBasePath
=
Files
.
GetUploadFilePath
(
UploadDirType
.
TestAssets
);
var
testFilesDict
=
await
Files
.
ReadUploadedFilesAsArray
(
testAssetsBasePath
,
connection
.
FileReferenceTestAsset
.
Id
);
var
testFilesDict
=
await
Files
.
ReadUploadedFilesAsArray
(
testAssetsBasePath
,
connection
.
FileReferenceTestAsset
.
Id
);
var
fileName
=
"asset"
;
...
...
@@ -508,7 +557,8 @@ namespace ClientServer.Controllers.Core.Exercises
{
//just try to get a file extension...
var
lastIndex
=
connection
.
FileReferenceTestAsset
.
OriginalName
.
LastIndexOf
(
"."
,
StringComparison
.
Ordinal
);
var
lastIndex
=
connection
.
FileReferenceTestAsset
.
OriginalName
.
LastIndexOf
(
"."
,
StringComparison
.
Ordinal
);
if
(
lastIndex
==
-
1
)
{
//no file extension...
...
...
@@ -539,14 +589,17 @@ namespace ClientServer.Controllers.Core.Exercises
internal
class
TempTestAsset
{
public
int
Id
{
get
;
set
;
}
/// <summary>
/// the name of the file/asset
/// </summary>
public
string
DisplayName
{
get
;
set
;
}
/// <summary>
/// the content of the asset (binary)
/// </summary>
public
byte
[]
Content
{
get
;
set
;
}
/// <summary>
/// the mime type (maybe we need to know what content is stored)
/// </summary>
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment