Skip to content

Commit bef638b

Browse files
committed
refactor: separate methods in privacy filter
1 parent bd83fa9 commit bef638b

8 files changed

Lines changed: 72 additions & 71 deletions

File tree

HwProj.APIGateway/HwProj.APIGateway.API/Controllers/FilesController.cs

Lines changed: 24 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System.Linq;
12
using System.Net;
23
using System.Threading.Tasks;
34
using HwProj.APIGateway.API.Filters;
@@ -29,15 +30,14 @@ public FilesController(IAuthServiceClient authServiceClient,
2930

3031
[HttpPost("process")]
3132
[ProducesResponseType((int)HttpStatusCode.OK)]
32-
[ProducesResponseType(typeof(string), (int)HttpStatusCode.Forbidden)]
33+
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
3334
[ProducesResponseType(typeof(string[]), (int)HttpStatusCode.ServiceUnavailable)]
3435
public async Task<IActionResult> Process([FromForm] ProcessFilesDTO processFilesDto)
3536
{
36-
var checkRights = await _privacyFilter.CheckRights(User,
37-
processFilesDto.FilesScope,
38-
FilesPrivacyFilter.Method.Upload
39-
);
40-
if (!checkRights) return StatusCode((int)HttpStatusCode.Forbidden, "Недостаточно прав для загрузки файлов");
37+
var checkRights = await _privacyFilter.CheckUploadRights(
38+
User.Claims.FirstOrDefault(claim => claim.Type.ToString() == "_id")?.Value,
39+
processFilesDto.FilesScope);
40+
if (!checkRights) return Forbid("Недостаточно прав для загрузки файлов");
4141

4242
var checkCountLimit = await _countFilter.CheckCountLimit(processFilesDto);
4343
if (!checkCountLimit) return StatusCode((int)HttpStatusCode.Forbidden, "Слишком много файлов в решении."
@@ -50,16 +50,15 @@ public async Task<IActionResult> Process([FromForm] ProcessFilesDTO processFiles
5050
}
5151

5252
[HttpPost("statuses")]
53+
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
5354
[ProducesResponseType(typeof(FileInfoDTO[]), (int)HttpStatusCode.OK)]
54-
[ProducesResponseType(typeof(string), (int)HttpStatusCode.Forbidden)]
5555
[ProducesResponseType(typeof(string[]), (int)HttpStatusCode.ServiceUnavailable)]
5656
public async Task<IActionResult> GetStatuses(ScopeDTO filesScope)
5757
{
58-
var checkRights = await _privacyFilter.CheckRights(User,
59-
filesScope,
60-
FilesPrivacyFilter.Method.Upload
61-
);
62-
if (!checkRights) return StatusCode((int)HttpStatusCode.Forbidden, "Недостаточно прав для получения информации о файлах");
58+
var checkRights = await _privacyFilter.CheckUploadRights(
59+
User.Claims.FirstOrDefault(claim => claim.Type.ToString() == "_id")?.Value,
60+
filesScope);
61+
if (!checkRights) return Forbid("Недостаточно прав для получения информации о файлах");
6362

6463
var filesStatusesResult = await _contentServiceClient.GetFilesStatuses(filesScope);
6564
return filesStatusesResult.Succeeded
@@ -68,22 +67,28 @@ public async Task<IActionResult> GetStatuses(ScopeDTO filesScope)
6867
}
6968

7069
[HttpGet("downloadLink")]
70+
[ProducesResponseType((int)HttpStatusCode.Forbidden)]
7171
[ProducesResponseType(typeof(string), (int)HttpStatusCode.OK)]
72-
[ProducesResponseType(typeof(string[]), (int)HttpStatusCode.Forbidden)]
7372
[ProducesResponseType(typeof(string[]), (int)HttpStatusCode.NotFound)]
7473
public async Task<IActionResult> GetDownloadLink([FromQuery] long fileId)
7574
{
7675
var linkDto = await _contentServiceClient.GetDownloadLinkAsync(fileId);
7776
if(!linkDto.Succeeded) return StatusCode((int)HttpStatusCode.ServiceUnavailable, linkDto.Errors);
7877

79-
var checkRights = await _privacyFilter.CheckRights(User,
80-
linkDto.Value.fileScope,
81-
FilesPrivacyFilter.Method.Download
82-
);
78+
var userId = User.Claims.FirstOrDefault(claim => claim.Type.ToString() == "_id")?.Value;
79+
var hasRights = false;
80+
foreach (var scope in linkDto.Value.fileScopes)
81+
{
82+
if (await _privacyFilter.CheckDownloadRights(userId, scope))
83+
{
84+
hasRights = true;
85+
break;
86+
}
87+
}
8388

84-
return checkRights
89+
return hasRights
8590
? Ok(linkDto.Value.DownloadUrl)
86-
: StatusCode((int)HttpStatusCode.Forbidden, "Недостаточно прав для получения ссылки на файл");
91+
: Forbid("Недостаточно прав для получения ссылки на файл");
8792
}
8893

8994
[HttpGet("info/course/{courseId}")]

HwProj.APIGateway/HwProj.APIGateway.API/Filters/FilesPrivacyFilter.cs

Lines changed: 35 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
using System.Collections.Generic;
22
using System.Linq;
3-
using System.Security.Claims;
43
using System.Threading.Tasks;
54
using HwProj.CoursesService.Client;
65
using HwProj.Models.ContentService.DTO;
7-
using HwProj.Models.Roles;
86
using HwProj.SolutionsService.Client;
97

108
namespace HwProj.APIGateway.API.Filters;
119

1210
public class FilesPrivacyFilter
1311
{
14-
public enum Method
15-
{
16-
Upload,
17-
Download
18-
}
19-
2012
private readonly ICoursesServiceClient _coursesServiceClient;
2113
private readonly ISolutionsServiceClient _solutionsServiceClient;
2214

@@ -26,45 +18,47 @@ public FilesPrivacyFilter(ICoursesServiceClient coursesServiceClient, ISolutions
2618
_solutionsServiceClient = solutionsServiceClient;
2719
}
2820

29-
public async Task<bool> CheckRights(ClaimsPrincipal user, ScopeDTO fileScope, Method method)
21+
public async Task<bool> CheckDownloadRights(string? userId, ScopeDTO fileScope)
3022
{
31-
var userId = user.Claims
32-
.FirstOrDefault(claim => claim.Type.ToString() == "_id")?.Value;
33-
if (userId == null) return false;
34-
35-
var userRole = user.Claims
36-
.FirstOrDefault(claim => claim.Type.ToString().EndsWith("role"))?.Value;
37-
if (userRole == null) return false;
23+
if (fileScope.CourseUnitType == "Homework") return true;
24+
if (fileScope.CourseUnitType == "Solution")
25+
{
26+
if(userId == null) return false;
27+
var studentIds = new HashSet<string>();
28+
var solution = await _solutionsServiceClient.GetSolutionById(fileScope.CourseUnitId);
29+
studentIds.Add(solution.StudentId);
30+
var groupIds = await _coursesServiceClient.GetGroupsById(solution.GroupId ?? 0);
31+
32+
var mentorIds = await _coursesServiceClient.GetCourseLecturersIds(fileScope.CourseId);
33+
if (!mentorIds.Contains(userId)) return false;
34+
studentIds.UnionWith(groupIds.FirstOrDefault()?.StudentsIds.ToHashSet() ?? new());
35+
36+
if (!studentIds.Contains(userId) && !mentorIds.Contains(userId)) return false;
37+
38+
return true;
39+
}
40+
41+
return false;
42+
}
3843

44+
public async Task<bool> CheckUploadRights(string? userId, ScopeDTO fileScope)
45+
{
46+
if(userId == null) return false;
3947
if (fileScope.CourseUnitType == "Homework")
4048
{
41-
if (method == Method.Download) return true;
42-
if (method == Method.Upload)
43-
{
44-
var mentorIds = await _coursesServiceClient.GetCourseLecturersIds(fileScope.CourseId);
45-
if (!mentorIds.Contains(userId))
46-
{
47-
return false;
48-
}
49-
return true;
50-
}
51-
} else if (fileScope.CourseUnitType == "Solution")
49+
var mentorIds = await _coursesServiceClient.GetCourseLecturersIds(fileScope.CourseId);
50+
if (!mentorIds.Contains(userId)) return false;
51+
return true;
52+
}
53+
if (fileScope.CourseUnitType == "Solution")
5254
{
55+
var studentIds = new HashSet<string>();
56+
var solution = await _solutionsServiceClient.GetSolutionById(fileScope.CourseUnitId);
57+
studentIds.Add(solution.StudentId);
58+
var group = await _coursesServiceClient.GetGroupsById(solution.GroupId ?? 0);
59+
studentIds.UnionWith(group.FirstOrDefault()?.StudentsIds.ToHashSet() ?? new());
5360

54-
if (userRole == Roles.StudentRole)
55-
{
56-
var studentIds = new HashSet<string>();
57-
var solution = await _solutionsServiceClient.GetSolutionById(fileScope.CourseUnitId);
58-
studentIds.Add(solution.StudentId);
59-
var group = await _coursesServiceClient.GetGroupsById(solution.GroupId ?? 0);
60-
studentIds.UnionWith(group.FirstOrDefault()?.StudentsIds.ToHashSet() ?? new());
61-
62-
if (!studentIds.Contains(userId)) return false;
63-
} else if(method == Method.Download)
64-
{
65-
var mentorIds = await _coursesServiceClient.GetCourseLecturersIds(fileScope.CourseId);
66-
if (!mentorIds.Contains(userId)) return false;
67-
}
61+
if (!studentIds.Contains(userId)) return false;
6862

6963
return true;
7064
}
Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
using System.Collections.Generic;
2+
13
namespace HwProj.Models.ContentService.DTO
24
{
35

46
public class FileLinkDTO
57
{
68
public string DownloadUrl { get; set; }
7-
public ScopeDTO fileScope { get; set; }
9+
public List<ScopeDTO> fileScopes { get; set; }
810
}
911
}

HwProj.ContentService/HwProj.ContentService.API/Controllers/FilesController.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,22 +81,22 @@ public async Task<IActionResult> GetStatuses(ScopeDTO scopeDto)
8181
}
8282

8383
[HttpGet("downloadLink")]
84-
[ProducesResponseType(typeof(FileLinkDTO), (int)HttpStatusCode.OK)]
84+
[ProducesResponseType(typeof(FileLinkDTO[]), (int)HttpStatusCode.OK)]
8585
public async Task<IActionResult> GetDownloadLink([FromQuery] long fileId)
8686
{
8787
var externalKey = await _filesInfoService.GetFileExternalKeyAsync(fileId);
8888
if (externalKey is null) return Ok(Result<FileLinkDTO>.Failed("Файл не найден"));
8989

90-
var fileScope = await _filesInfoService.GetFileScopeAsync(fileId);
91-
if (fileScope is null) return Ok(Result<FileLinkDTO>.Failed("Файл не найден"));
90+
var fileScopes = await _filesInfoService.GetFileScopesAsync(fileId);
91+
if (fileScopes is null) return Ok(Result<FileLinkDTO>.Failed("Файл не найден"));
9292

9393
var downloadUrl = await _s3FilesService.GetDownloadUrl(externalKey);
9494
if (!downloadUrl.Succeeded) return Ok(Result<FileLinkDTO>.Failed(downloadUrl.Errors));
9595

9696
var result = new FileLinkDTO
9797
{
9898
DownloadUrl = downloadUrl.Value,
99-
fileScope = fileScope.ToScopeDTO()
99+
fileScopes = fileScopes.Select(fs => fs.ToScopeDTO()).ToList()
100100
};
101101

102102
return Ok(result);

HwProj.ContentService/HwProj.ContentService.API/Repositories/FileRecordRepository.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ public async Task UpdateStatusAsync(List<long> fileRecordIds, FileStatus newStat
5252
.AsNoTracking()
5353
.SingleOrDefaultAsync(fr => fr.Id == fileRecordId);
5454

55-
public async Task<Scope?> GetScopeByRecordIdAsync(long fileRecordId)
55+
public async Task<List<Scope>?> GetScopesAsync(long fileRecordId)
5656
=> await _contentContext.FileToCourseUnits
5757
.AsNoTracking()
5858
.Where(fr => fr.FileRecordId == fileRecordId)
5959
.Select(fc => fc.ToScope())
60-
.SingleOrDefaultAsync();
60+
.ToListAsync();
6161

6262
public async Task<List<FileRecord>> GetByScopeAsync(Scope scope)
6363
=> await _contentContext.FileToCourseUnits

HwProj.ContentService/HwProj.ContentService.API/Repositories/IFileRecordRepository.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public interface IFileRecordRepository
1313
public Task UpdateAsync(long id,
1414
Expression<Func<SetPropertyCalls<FileRecord>, SetPropertyCalls<FileRecord>>> setPropertyCalls);
1515
public Task<FileRecord?> GetFileRecordByIdAsync(long fileRecordId);
16-
public Task<Scope?> GetScopeByRecordIdAsync(long fileRecordId);
16+
public Task<List<Scope>?> GetScopesAsync(long fileRecordId);
1717
public Task<List<FileRecord>> GetByScopeAsync(Scope scope);
1818
public Task<List<FileToCourseUnit>> GetByCourseIdAsync(long courseId);
1919
public Task<List<FileToCourseUnit>> GetByCourseIdAndStatusAsync(long courseId, FileStatus filesStatus);

HwProj.ContentService/HwProj.ContentService.API/Services/FilesInfoService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ public async Task<List<FileInfoDTO>> GetFilesStatusesAsync(Scope filesScope)
3737
return fileRecord?.ExternalKey;
3838
}
3939

40-
public async Task<Scope?> GetFileScopeAsync(long fileId)
40+
public async Task<List<Scope>?> GetFileScopesAsync(long fileId)
4141
{
42-
var fileToCourseUnit = await _fileRecordRepository.GetScopeByRecordIdAsync(fileId);
42+
var fileToCourseUnit = await _fileRecordRepository.GetScopesAsync(fileId);
4343
return fileToCourseUnit;
4444
}
4545

HwProj.ContentService/HwProj.ContentService.API/Services/Interfaces/IFilesInfoService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public interface IFilesInfoService
99
{
1010
public Task<List<FileInfoDTO>> GetFilesStatusesAsync(Scope filesScope);
1111
public Task<string?> GetFileExternalKeyAsync(long fileId);
12-
public Task<Scope?> GetFileScopeAsync(long fileId);
12+
public Task<List<Scope>?> GetFileScopesAsync(long fileId);
1313
public Task<List<FileInfoDTO>> GetFilesInfoAsync(long courseId);
1414
public Task<List<FileInfoDTO>> GetFilesInfoAsync(long courseId, FileStatus filesStatus);
1515
public Task TransferFilesFromCourse(CourseFilesTransferDto filesTransfer);

0 commit comments

Comments
 (0)