Skip to content

Commit 45116c7

Browse files
committed
Merge branch 'main' of https://github.com/CapstoneProjectCMC/backend into post-service
2 parents 2498952 + 6aab5b9 commit 45116c7

File tree

33 files changed

+707
-291
lines changed

33 files changed

+707
-291
lines changed

.env

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ QUIZ_DATABASE=quiz_db
1717
CODING_USERNAME=postgres_coding
1818
CODING_DB_PASSWORD=dinhanst2832004
1919
CODING_DATABASE=coding_db
20+
DOCKER_GID=999
2021
AI_USERNAME=postgres_ai
2122
AI_DB_PASSWORD=dinhanst2832004
2223
AI_DATABASE=ai_db
@@ -48,4 +49,4 @@ CHAT_ROOT_PASSWORD=dinhanst2832004
4849
CHAT_DATABASE=chat_db
4950
CHAT_PASSWORD=dinhanst2832004
5051
#GeminiKey
51-
OPENAI_API_KEY=AIzaSyDeZ3rEpzrleMCvvwLK3xHnqXYyTdxVhFs
52+
OPENAI_API_KEY=AIzaSyDeZ3rEpzrleMCvvwLK3xHnqXYyTdxVhFs

FileService/FileService.Api/Controllers/FileDocumentController.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
using FileService.Service.ApiModels.FileDocumentModels;
33
using FileService.Service.Dtos.FileDocumentDtos;
44
using FileService.Service.Interfaces;
5+
using Microsoft.AspNetCore.Authorization;
56
using Microsoft.AspNetCore.Mvc;
67

78
namespace FileService.Api.Controllers
89
{
10+
// [Authorize]
11+
// [Authorize(Policy = "Permission")]
12+
// [Authorize(Roles = "ADMIN")]
913
[Route("file/api/[controller]")]
1014
[ApiController]
1115
public class FileDocumentController : BaseApiController

FileService/FileService.Api/Middlewares/AuthenMiddleware.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,20 @@
11
using FileService.Core.ApiModels;
2+
using System.Security.Claims;
23

34
namespace FileService.Api.Middlewares
45
{
56
public class AuthenMiddleware
67
{
78
private readonly RequestDelegate _next;
9+
10+
811
public AuthenMiddleware(RequestDelegate next)
912
{
1013
_next = next;
1114
}
1215
public async Task InvokeAsync(HttpContext httpContext)
1316
{
17+
//lấy userId và sessionId từ claims
1418
var userId = httpContext.User.Claims.FirstOrDefault(c => c.Type == "userId")?.Value;
1519
var sessionId = httpContext.User.Claims.FirstOrDefault(c => c.Type == "sessionId")?.Value;
1620

FileService/FileService.Api/Program.cs

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
using FileService.Service.Implementation;
1919
using FileService.Service.Interfaces;
2020
using Microsoft.Extensions.FileProviders;
21+
using System.Security.Claims;
2122

2223
BsonSerializer.RegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));
2324

@@ -39,7 +40,7 @@
3940

4041
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
4142
Console.WriteLine($"ASPNETCORE_ENVIRONMENT: {env}");
42-
builder.Services.Configure<MinioConfig>(builder.Configuration.GetSection("MinioConfig"));
43+
//builder.Services.Configure<MinioConfig>(builder.Configuration.GetSection("MinioConfig"));
4344

4445
builder.Services.Configure<MongoDbSettings>(builder.Configuration.GetSection("MongoDbSettings"));
4546
builder.Services.Configure<FfmpegSettings>(builder.Configuration.GetSection("FfmpegSettings"));
@@ -98,7 +99,11 @@
9899
ValidateIssuerSigningKey = true,
99100
ValidIssuer = appSettings.Jwt.Issuer,
100101
ValidAudience = appSettings.Jwt.Audience,
101-
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.Jwt.Key))
102+
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(appSettings.Jwt.Key)),
103+
104+
// Cấu hình claim để nhận Role
105+
RoleClaimType = ClaimTypes.Role
106+
102107
};
103108
});
104109

@@ -173,12 +178,6 @@
173178
app.UseSwaggerUI();
174179
}
175180

176-
using (var scope = app.Services.CreateScope())
177-
{
178-
var minioService = scope.ServiceProvider.GetRequiredService<IMinioService>();
179-
await minioService.EnsureBucketExistsAsync();
180-
}
181-
182181
//kích hoạt CORS policy
183182
app.UseCors(MyAllowSpecificOrigins);
184183

@@ -192,6 +191,5 @@
192191

193192
app.MapControllers();
194193

195-
196-
await app.RunAsync();
194+
app.Run();
197195

FileService/FileService.Api/appsettings.Development.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@
2121
"OtpHoursAvailable": 24
2222
},
2323
"Jwt": {
24-
"Key": "uifhjcnsqbhwbAMKXjdt123gdritocet",
25-
"Issuer": "http://localhost:38946",
26-
"Audience": "http://localhost:38946",
24+
"Key": "1TjXchw5FloESb63Kc+DFhTARvpWL4jUGCwfGWxuG5SIf/1y/LgJxHnMqaF6A/ij",
25+
"Issuer": "Code Campus",
26+
"Audience": "Code Campus",
2727
"AccessTokenExpiresTime": 60,
28-
"RefreshTokenExpiresTime": 3
28+
"RefreshTokenExpiresTime": 300
2929
},
3030
"Admin": {
3131
"OtpMaxAttempted": 3,

FileService/FileService.Api/appsettings.Staging.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@
2121
"OtpHoursAvailable": 24
2222
},
2323
"Jwt": {
24-
"Key": "uifhjcnsqbhwbAMKXjdt123gdritocet",
25-
"Issuer": "http://localhost:38946",
26-
"Audience": "http://localhost:38946",
24+
"Key": "1TjXchw5FloESb63Kc+DFhTARvpWL4jUGCwfGWxuGSSIf/1y/LgJxHnMqaF6A/ij",
25+
"Issuer": "Code Campus",
26+
"Audience": "Code Campus",
2727
"AccessTokenExpiresTime": 60,
2828
"RefreshTokenExpiresTime": 3
2929
},

FileService/FileService.Service/Implementation/MinioService.cs

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,25 +22,60 @@ public class MinioService : BaseService, IMinioService
2222
private readonly IMinioClient _minioClient;
2323
private readonly MinioConfig _config;
2424

25-
public MinioService(AppSettings appSettings, UserContext userContext) : base(appSettings, userContext)
25+
public MinioService(IOptions<MinioConfig> options, AppSettings appSettings, UserContext userContext) : base(appSettings, userContext)
2626
{
27-
_config = appSettings.MinioConfig ?? throw new ArgumentNullException(nameof(appSettings.MinioConfig));
27+
_config = options.Value ?? throw new ArgumentNullException(nameof(options.Value));
2828

29-
_minioClient = new MinioClient()
30-
.WithEndpoint(_config.Endpoint, _config.Port)
31-
.WithCredentials(_config.AccessKey, _config.SecretKey)
32-
.WithSSL(_config.Secure)
33-
.Build();
29+
Console.WriteLine($"MinioConfig: Endpoint={_config.Endpoint}, Port={_config.Port}, AccessKey length={_config.AccessKey?.Length ?? 0}, Secure={_config.Secure}");
30+
31+
if (string.IsNullOrWhiteSpace(_config.Endpoint) || _config.Port <= 0 || string.IsNullOrWhiteSpace(_config.AccessKey) || string.IsNullOrWhiteSpace(_config.SecretKey))
32+
{
33+
throw new InvalidOperationException("Minio configuration is invalid or incomplete.");
34+
}
35+
try
36+
{
37+
Console.WriteLine("Attempting to build MinioClient...");
38+
_minioClient = new MinioClient()
39+
.WithEndpoint(_config.Endpoint, _config.Port)
40+
.WithCredentials(_config.AccessKey, _config.SecretKey)
41+
.WithSSL(_config.Secure)
42+
.Build();
43+
if (_minioClient == null)
44+
{
45+
throw new InvalidOperationException("Failed to initialize MinioClient.");
46+
}
47+
// Kiểm tra kết nối thực tế
48+
Console.WriteLine("Testing MinioClient connection...");
49+
var buckets = _minioClient.ListBucketsAsync().GetAwaiter().GetResult(); // Kiểm tra nhanh
50+
Console.WriteLine("MinioClient initialized and connection tested successfully.");
51+
}
52+
catch (MinioException ex)
53+
{
54+
Console.WriteLine($"MinioException: {ex.Message}");
55+
throw new InvalidOperationException($"Minio initialization failed: {ex.Message}", ex);
56+
}
57+
catch (Exception ex)
58+
{
59+
Console.WriteLine($"Unexpected error: {ex.Message}");
60+
throw new InvalidOperationException($"Failed to initialize MinioClient: {ex.Message}", ex);
61+
}
3462
}
3563

3664
public async Task EnsureBucketExistsAsync()
3765
{
38-
var bucketExistsArgs = new BucketExistsArgs().WithBucket(_config.BucketName);
66+
if (_minioClient == null)
67+
{
68+
throw new InvalidOperationException("MinioClient is not initialized.");
69+
}
70+
3971
if (string.IsNullOrWhiteSpace(_config.BucketName))
4072
{
4173
throw new InvalidOperationException("Bucket name is not configured.");
4274
}
75+
var bucketExistsArgs = new BucketExistsArgs().WithBucket(_config.BucketName);
76+
4377
bool found = await _minioClient.BucketExistsAsync(bucketExistsArgs);
78+
4479
if (!found)
4580
{
4681
var makeBucketArgs = new MakeBucketArgs().WithBucket(_config.BucketName);

build-image.sh

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,35 +5,44 @@ export DOCKER_BUILDKIT=1
55
DOCKERHUB_USER="${DOCKERHUB_USER:-yunomix2834}"
66
IMAGE_TAG="${IMAGE_TAG:-$(date +%Y%m%d.%H%M%S)}"
77

8+
# Xác định DOCKER_GID an toàn
9+
if [[ "$OSTYPE" == "darwin"* ]]; then
10+
DOCKER_GID=999
11+
elif [ -S /var/run/docker.sock ]; then
12+
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock 2>/dev/null || echo 999)
13+
else
14+
DOCKER_GID=999
15+
fi
16+
817
login() {
9-
echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USER" --password-stdin
18+
[ -n "$DOCKERHUB_TOKEN" ] && echo "$DOCKERHUB_TOKEN" | docker login -u "$DOCKERHUB_USER" --password-stdin
1019
}
1120

1221
build_push_java() {
1322
local module=$1
23+
local build_args=("--build-arg" "MODULE=$module")
24+
25+
if [[ "$module" == "coding-service" ]]; then
26+
build_args+=(
27+
"--build-arg" "DOCKER_HOST_GID=${DOCKER_GID}"
28+
)
29+
fi
30+
1431
docker buildx build \
1532
-f docker/java-service.Dockerfile \
16-
--build-arg MODULE="$module" \
33+
"${build_args[@]}" \
1734
-t "$DOCKERHUB_USER/codecampus-$module:$IMAGE_TAG" \
1835
--push .
1936
}
2037

21-
build_push_file_service() {
22-
docker buildx build \
23-
-f docker/file-service.Dockerfile \
24-
-t "$DOCKERHUB_USER/codecampus-file-service:$IMAGE_TAG" \
25-
--push .
26-
}
27-
2838
main() {
2939
login
30-
for svc in identity-service profile-service submission-service \
31-
coding-service quiz-service ai-service search-service \
32-
notification-service chat-service gateway-service
33-
do
40+
echo "Building with DOCKER_GID=${DOCKER_GID}"
41+
42+
for svc in search-service profile-service identity-service; do
43+
echo "Building $svc..."
3444
build_push_java "$svc"
3545
done
36-
build_push_file_service
3746
}
3847

39-
main "$@"
48+
main "$@"

build-service.sh

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,11 @@ build_push_file_service() {
2727

2828
main() {
2929
login
30-
for svc in submission-service quiz-service coding-service profile-service
31-
do
32-
build_push_java "$svc"
33-
done
34-
# build_push_java "profile-service"
30+
# for svc in submission-service quiz-service coding-service profile-service
31+
# do
32+
# build_push_java "$svc"
33+
# done
34+
build_push_java "coding-service"
3535
# build_push_file_service
3636
}
3737

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
package com.codecampus.coding.helper;
2+
3+
import java.nio.file.Path;
4+
import java.util.ArrayList;
5+
import java.util.Arrays;
6+
import java.util.List;
7+
8+
/**
9+
* Helper tạo lệnh docker, tự fallback sang “sudo docker …” khi cần.
10+
*/
11+
public final class DockerHelper {
12+
private static final String SANDBOX_IMAGE =
13+
System.getenv().getOrDefault("SANDBOX_IMAGE",
14+
"capstoneprojectpythondocker:latest");
15+
private static final String RUNNER_VOLUME =
16+
System.getenv().getOrDefault("RUNNER_VOLUME", "runner_data");
17+
private static final Path RUNNER_ROOT =
18+
Path.of(System.getenv().getOrDefault("RUNNER_ROOT", "/work"));
19+
private static volatile Boolean NEEDS_SUDO = null;
20+
21+
private DockerHelper() {
22+
}
23+
24+
public static List<String> cmd(String... args) {
25+
var full = new ArrayList<String>();
26+
if (useSudo()) {
27+
full.add("sudo");
28+
}
29+
full.add("docker");
30+
full.addAll(Arrays.asList(args));
31+
return full;
32+
}
33+
34+
private static boolean useSudo() {
35+
if (NEEDS_SUDO != null) {
36+
return NEEDS_SUDO;
37+
}
38+
39+
// Cho phép ép dùng sudo qua biến môi trường (phòng hờ)
40+
String force = System.getenv("DOCKER_USE_SUDO");
41+
if (force != null &&
42+
(force.equals("1") || force.equalsIgnoreCase("true"))) {
43+
NEEDS_SUDO = true;
44+
return true;
45+
}
46+
47+
try {
48+
var p = new ProcessBuilder("docker", "system", "info")
49+
.redirectErrorStream(true)
50+
.start();
51+
52+
int code = p.waitFor();
53+
NEEDS_SUDO = (code != 0);
54+
} catch (Exception e) {
55+
NEEDS_SUDO = true;
56+
}
57+
return NEEDS_SUDO;
58+
}
59+
60+
// PlaygroundServiceImpl & DockerSandboxService
61+
public static String inVolumePath(Path p) {
62+
// p = /work/pg_xxx/... (trong coding-service)
63+
// Cần đường dẫn tương ứng bên trong sandbox: /work/pg_xxx/...
64+
Path rel = RUNNER_ROOT.relativize(p.toAbsolutePath().normalize());
65+
return "/work/" + rel.toString().replace("\\", "/");
66+
}
67+
68+
public static String selfContainer() {
69+
return System.getenv().getOrDefault("SELF_CONTAINER", "");
70+
}
71+
}

0 commit comments

Comments
 (0)