Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ jobs:
java-version: '23'
distribution: 'temurin'

- name: Up docker compose
run: docker compose up -d

- name: Grant execute permission for gradlew
run: chmod +x gradlew

Expand Down
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ build/
.classpath
.factorypath
.project
.settings
.authSettings
.springBeans
.sts4-cache
bin/
Expand Down
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-webmvc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'software.amazon.awssdk:s3:2.20.0'
runtimeOnly 'org.postgresql:postgresql'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
Expand Down
40 changes: 39 additions & 1 deletion compose.yaml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
services:
postgres:
container_name: codzilla_postgres
container_name: codzilla-postgres
image: postgres:15
ports:
- "5433:5432"
Expand All @@ -16,5 +16,43 @@ services:
timeout: 5s
retries: 5

redis:
image: redis:7.2-alpine
container_name: codzilla-redis
restart: always
ports:
- "6379:6379"
command: >
redis-server
--requirepass redis-password
--maxmemory 512mb
--maxmemory-policy allkeys-lru
--appendonly yes
volumes:
- redis_data:/data

redis-insight:
image: redis/redisinsight:latest
container_name: codzilla-redis-insight
restart: always
environment:
- RDI_PORT=5540
ports:
- "8001:5540"
depends_on:
- redis

minio:
image: minio/minio
container_name: codzilla-minio
ports:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: minio-user
MINIO_ROOT_PASSWORD: minio-password
command: server /data --console-address ":9001"

volumes:
redis_data:
postgres_data:
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.codzilla.backend.Submissions;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;
import tools.jackson.databind.ObjectMapper;

import java.util.Optional;

@Repository
public class RedisSubmissionRepository implements SubmissionRepository {

@Autowired
protected ObjectMapper objectMapper;

@Autowired
RedisTemplate<String, Object> redisTemplate;

@Override
public void save(Submission submission) {
redisTemplate.opsForValue().set("submission:" + submission.id(), submission);
}

@Override
public Optional<Submission> get(String id) {
Object value = redisTemplate.opsForValue().get("submission:"+id);
if (value == null) return Optional.empty();
return Optional.of(objectMapper.convertValue(value, Submission.class));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.codzilla.backend.Submissions;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;


@Slf4j
@Component
public class S3Initialization {

@Autowired
SubmissionSettings settings;

@Autowired
S3Client s3Client;

@EventListener(ApplicationReadyEvent.class)
public void initBucket() {
try {
s3Client.headBucket(HeadBucketRequest.builder().bucket(settings.s3().bucketName()).build());
log.info("Already have bucket: " + settings.s3().bucketName());
} catch (NoSuchBucketException e) {
s3Client.createBucket(CreateBucketRequest.builder().bucket(settings.s3().bucketName()).build());
log.info("Create bucket: " + settings.s3().bucketName());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.codzilla.backend.Submissions;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.core.sync.ResponseTransformer;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;
import software.amazon.awssdk.services.s3.model.NoSuchKeyException;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;

import java.util.Optional;


@Repository
public class S3SubmissionRepository implements SubmissionRepository {
@Autowired
S3Client s3Client;

@Autowired
SubmissionSettings settings;

@Override
public void save(Submission submission) {
s3Client.putObject(
PutObjectRequest.builder()
.contentType("text/plain")
.bucket(settings.s3().bucketName())
.key("submissions/" + submission.id() + ".cpp")
.build(),
RequestBody.fromString(submission.code())
);
}

@Override
public Optional<Submission> get(String id) {
try {
String code = s3Client.getObject(
GetObjectRequest.builder()
.bucket(settings.s3().bucketName())
.key("submissions/" + id + ".cpp")
.build(),
ResponseTransformer.toBytes()

).asUtf8String();
Submission result = new Submission(id, code, "");
return Optional.of(result);
} catch (NoSuchKeyException ex) {
return Optional.empty();
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.codzilla.backend.Submissions;

public record Submission(
String id,
String code,
String userEmail
) {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package com.codzilla.backend.Submissions;


import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JacksonJsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.CreateBucketRequest;
import software.amazon.awssdk.services.s3.model.HeadBucketRequest;
import software.amazon.awssdk.services.s3.model.NoSuchBucketException;

import java.net.URI;


@Slf4j
@Configuration
@EnableConfigurationProperties(SubmissionSettings.class)
public class SubmissionConfiguration {

@Autowired
SubmissionSettings settings;

@Bean
RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
var redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory);

redisTemplate.setKeySerializer(new StringRedisSerializer());

JacksonJsonRedisSerializer<Object> serializer = new JacksonJsonRedisSerializer<>(Object.class);

redisTemplate.setValueSerializer(serializer);
return redisTemplate;
}


@Bean
public S3Client s3Client() {
log.info(settings.toString());
return S3Client.builder()
.endpointOverride(URI.create(settings.s3().endpoint()))
.credentialsProvider(StaticCredentialsProvider.create(
AwsBasicCredentials.create(
settings.s3().accessKey(),
settings.s3().secretKey())))
.region(Region.of(settings.s3().region()))
.forcePathStyle(true)
.build();
}


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.codzilla.backend.Submissions;

import java.util.Optional;

public interface SubmissionRepository {


void save(Submission submission); // returns id
Optional<Submission> get(String id);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
package com.codzilla.backend.Submissions;

public class SubmissionService {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.codzilla.backend.Submissions;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@ConfigurationProperties(prefix = "app.submission")
public record SubmissionSettings (S3 s3) {
public record S3(
String endpoint,
String accessKey,
String secretKey,
String region,
String bucketName
) {}
}

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import com.codzilla.backend.auth.JWTUtils.JWTUtils;
import com.codzilla.backend.auth.User;
import com.codzilla.backend.auth.UserService;
import com.codzilla.backend.auth.config.Settings;
import com.codzilla.backend.auth.config.AuthSettings;
import com.codzilla.backend.auth.dto.LoginRequestDTO;
import com.codzilla.backend.auth.dto.LoginResponseDTO;
import com.codzilla.backend.auth.dto.RegisterRequestDTO;
Expand All @@ -26,16 +26,16 @@
public class AuthController {
private final AuthenticationManager authManager;
private final JWTUtils jwtUtils;
private final Settings settings;
private final AuthSettings authSettings;
private final UserService userService;

@Autowired
public AuthController(AuthenticationManager authManager,
JWTUtils jwtUtils, Settings settings, UserService userService) {
JWTUtils jwtUtils, AuthSettings authSettings, UserService userService) {
this.userService = userService;
this.authManager = authManager;
this.jwtUtils = jwtUtils;
this.settings = settings;
this.authSettings = authSettings;
}

@PostMapping("/login")
Expand All @@ -51,14 +51,14 @@ public ResponseEntity<?> login(@RequestBody LoginRequestDTO request, HttpServlet
jwtCookie.setHttpOnly(true);
jwtCookie.setSecure(false);
jwtCookie.setPath("/");
jwtCookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds());
jwtCookie.setMaxAge((int) authSettings.getRefreshTokenTtl().toSeconds());
response.addCookie(jwtCookie);

var refreshToken = jwtUtils.generateRefreshToken(auth);
Cookie refreshCookie = new Cookie("refresh_jwt", refreshToken);
refreshCookie.setPath("/");
refreshCookie.setHttpOnly(true);
refreshCookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds());
refreshCookie.setMaxAge((int) authSettings.getRefreshTokenTtl().toSeconds());
refreshCookie.setSecure(false);
response.addCookie(refreshCookie);

Expand Down Expand Up @@ -115,7 +115,7 @@ public ResponseEntity<?> refreshToken(HttpServletRequest request, HttpServletRes
cookie.setHttpOnly(true);
cookie.setSecure(false);
cookie.setPath("/");
cookie.setMaxAge((int) settings.getRefreshTokenTtl().toSeconds());
cookie.setMaxAge((int) authSettings.getRefreshTokenTtl().toSeconds());
response.addCookie(cookie);
return ResponseEntity.ok("Jwt access was updated.");

Expand Down
Loading
Loading