From 13f7f59989eba243760068085094a2f9538c06bc Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 31 Aug 2024 14:26:39 +0200 Subject: [PATCH 01/23] chore: add tag based event --- .github/workflows/tag-based-thing.yaml | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/tag-based-thing.yaml diff --git a/.github/workflows/tag-based-thing.yaml b/.github/workflows/tag-based-thing.yaml new file mode 100644 index 00000000..57bfb274 --- /dev/null +++ b/.github/workflows/tag-based-thing.yaml @@ -0,0 +1,38 @@ +# Setup an action to run the frontend CI for PRs + +# name of the action +name: Frontend CI + +# when should it run +on: + push: + tags: + - v** + +# what should it do +jobs: + # name of the job + build: + # what should it run on + runs-on: ubuntu-latest + permissions: + contents: read + pull-requests: write + # default values for all the steps + defaults: + run: + working-directory: frontend + steps: + - uses: actions/checkout@v4 + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + - name: Install dependencies + run: npm install + - name: Run build + run: npm run build + - name: Run tests + run: npm test + - name: Run formatter + linter + run: npm run check From e3eae98f8aa258a0c99ab76713c246ad04ffe65e Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Wed, 4 Sep 2024 20:33:36 +0200 Subject: [PATCH 02/23] chore: makes the app cacheable with Redis --- backend/pom.xml | 4 ++++ .../com/greenfoxacademy/backend/BackendApplication.java | 2 ++ backend/src/main/resources/application.properties | 7 ++++++- 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/pom.xml b/backend/pom.xml index 455b02c5..ba7641b8 100644 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -108,6 +108,10 @@ spring-boot-starter-mail 3.3.2 + + org.springframework.boot + spring-boot-starter-data-redis + diff --git a/backend/src/main/java/com/greenfoxacademy/backend/BackendApplication.java b/backend/src/main/java/com/greenfoxacademy/backend/BackendApplication.java index d4092c00..4eea1d00 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/BackendApplication.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/BackendApplication.java @@ -2,11 +2,13 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cache.annotation.EnableCaching; /** * This is the main class of the application. */ @SpringBootApplication +@EnableCaching public class BackendApplication { public static void main(String[] args) { diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 4bdc3553..cba1486c 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -25,4 +25,9 @@ spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true # Where the verification link will redirect -email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} \ No newline at end of file +email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} + +# Redis configuration +spring.data.redis.host=localhost +spring.data.redis.port=6379 +spring.cache.type=redis From eeeded76d70eefc33f5ee5023918c0e276b48ccd Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Wed, 4 Sep 2024 20:51:00 +0200 Subject: [PATCH 03/23] feat: makes login and load user cacheable --- .../backend/services/user/UserServiceImpl.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index 9a1c5602..eb2634d5 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -13,8 +13,11 @@ import com.greenfoxacademy.backend.services.auth.AuthService; import com.greenfoxacademy.backend.services.mail.EmailService; import jakarta.transaction.Transactional; + import java.util.UUID; + import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.crypto.password.PasswordEncoder; @@ -47,9 +50,9 @@ public RegisterResponseDto register(RegisterRequestDto registerRequestDto) try { User saved = userRepository.save(user); emailService.sendRegistrationEmail( - saved.getEmail(), - saved.getFirstName(), - saved.getVerificationId() + saved.getEmail(), + saved.getFirstName(), + saved.getVerificationId() ); return new RegisterResponseDto(saved.getId()); } catch (Exception e) { @@ -57,7 +60,7 @@ public RegisterResponseDto register(RegisterRequestDto registerRequestDto) } } - + @Cacheable @Override public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception { User user = userRepository.findByEmail(loginRequestDto.email()) @@ -79,7 +82,7 @@ public ProfileUpdateResponseDto profileUpdate( .orElseThrow(() -> new UsernameNotFoundException("User not found")); if ( userRepository.existsByEmail(profileUpdateRequestDto.email()) - && !email.equals(profileUpdateRequestDto.email()) + && !email.equals(profileUpdateRequestDto.email()) ) { throw new CannotUpdateUserException("Email is already taken!"); } @@ -92,6 +95,7 @@ public ProfileUpdateResponseDto profileUpdate( return new ProfileUpdateResponseDto(authService.generateToken(updatedUser)); } + @Cacheable @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByEmail(username) From b280481d552577bfb7b3f18a0218f55a0db8f4ab Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Wed, 4 Sep 2024 21:47:02 +0200 Subject: [PATCH 04/23] feat: updating and deleting the profile clears the cache --- .../greenfoxacademy/backend/services/user/UserServiceImpl.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index eb2634d5..3350af4a 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -17,6 +17,7 @@ import java.util.UUID; import lombok.RequiredArgsConstructor; +import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -73,6 +74,7 @@ public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception return new LoginResponseDto(authService.generateToken(user)); } + @CacheEvict @Override public ProfileUpdateResponseDto profileUpdate( String email, @@ -105,6 +107,7 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx /** * Delete the user by username. */ + @CacheEvict @Transactional @Override public void deleteProfile(String username) { From b69c840048cd359ca1e3bce1c33faeec926e4fb0 Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Thu, 5 Sep 2024 20:29:30 +0200 Subject: [PATCH 05/23] chore: configure TTL with Redis --- .../backend/config/RedisConfig.java | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java new file mode 100644 index 00000000..6ad316ac --- /dev/null +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java @@ -0,0 +1,33 @@ +package com.greenfoxacademy.backend.config; + +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.cache.RedisCacheConfiguration; +import org.springframework.data.redis.cache.RedisCacheManager; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.serializer.RedisSerializationContext; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +import java.time.Duration; + +/** + * RedisConfig is a configuration class that defines the cache management strategy + * for Redis in the Spring Boot application. It configures the Redis Cache Manager + * and sets key serialization and expiration policies. + */ + +@Configuration +public class RedisConfig { + + @Bean + public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { + RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig() + .entryTtl(Duration.ofMinutes(5)) // Set TTL to 5 minutes + .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); + + return RedisCacheManager.builder(redisConnectionFactory) + .cacheDefaults(cacheConfig) + .build(); + } +} \ No newline at end of file From 74df238d4fed64d204ba088bdaaab8f8c0f7600b Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Thu, 5 Sep 2024 21:47:11 +0200 Subject: [PATCH 06/23] chore: configure Redis container --- .../com/greenfoxacademy/backend/config/RedisConfig.java | 3 ++- backend/src/main/resources/application.properties | 4 ++-- docker-compose.yaml | 8 ++++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java index 6ad316ac..a7d5fd6a 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java @@ -23,7 +23,8 @@ public class RedisConfig { @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig() - .entryTtl(Duration.ofMinutes(5)) // Set TTL to 5 minutes + .entryTtl(Duration.ofMinutes(5)) // Set TTL to 5 minutes + .disableCachingNullValues() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); return RedisCacheManager.builder(redisConnectionFactory) diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index cba1486c..8482850c 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -28,6 +28,6 @@ spring.mail.properties.mail.smtp.starttls.enable=true email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} # Redis configuration -spring.data.redis.host=localhost -spring.data.redis.port=6379 +spring.data.redis.host=${CACHE_URL:localhost} +spring.data.redis.port=${CACHE_PORT:6379} spring.cache.type=redis diff --git a/docker-compose.yaml b/docker-compose.yaml index c29112e5..ae76a93b 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,6 +10,11 @@ services: POSTGRES_PASSWORD: petclinic_db_password POSTGRES_DB: petclinic_db + redis-cache: + image: redis + ports: + - 6379:6379 + frontend: build: context: ./frontend @@ -28,5 +33,8 @@ services: - DATABASE_USER=petclinic_db_user - DATABASE_PASSWORD=petclinic_db_password - CORS_URLS=http://localhost:5173 + - CACHE_PORT=6379 + - CACHE_URL=redis://redis-cache depends_on: - postgres-db + - redis-cache From a81140995316ed7765116490bef353d5c9dfab98 Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Thu, 5 Sep 2024 22:11:13 +0200 Subject: [PATCH 07/23] chore: adds key - value pair to the login cache --- .../java/com/greenfoxacademy/backend/config/RedisConfig.java | 2 +- .../com/greenfoxacademy/backend/dtos/LoginResponseDto.java | 5 ++++- .../backend/services/user/UserServiceImpl.java | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java index a7d5fd6a..899e6f40 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java @@ -23,7 +23,7 @@ public class RedisConfig { @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig() - .entryTtl(Duration.ofMinutes(5)) // Set TTL to 5 minutes + .entryTtl(Duration.ofMinutes(3)) // Set TTL to 5 minutes .disableCachingNullValues() .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); diff --git a/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java b/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java index fef2c72e..7b2207bf 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java @@ -1,12 +1,15 @@ package com.greenfoxacademy.backend.dtos; +import java.io.Serializable; + /** * This class is responsible for the response of the login endpoint. * * @param token the token that is returned to identify the user */ + public record LoginResponseDto( String token -) { +) implements Serializable { } diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index 3350af4a..066472b8 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -61,7 +61,7 @@ public RegisterResponseDto register(RegisterRequestDto registerRequestDto) } } - @Cacheable + @Cacheable (value = "login-cache", key = "#loginRequestDto.email()") @Override public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception { User user = userRepository.findByEmail(loginRequestDto.email()) From 44164818a59204d917cff6af13a39e6b59e82540 Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Thu, 5 Sep 2024 22:14:27 +0200 Subject: [PATCH 08/23] fix: eliminates cache for login due to security reasons --- .../com/greenfoxacademy/backend/dtos/LoginResponseDto.java | 4 +--- .../backend/services/user/UserServiceImpl.java | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java b/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java index 7b2207bf..2186f2c9 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/dtos/LoginResponseDto.java @@ -1,8 +1,6 @@ package com.greenfoxacademy.backend.dtos; -import java.io.Serializable; - /** * This class is responsible for the response of the login endpoint. * @@ -11,5 +9,5 @@ public record LoginResponseDto( String token -) implements Serializable { +) { } diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index 066472b8..710961ee 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -60,8 +60,7 @@ public RegisterResponseDto register(RegisterRequestDto registerRequestDto) throw new UserAlreadyExistsError("Email is already taken!"); } } - - @Cacheable (value = "login-cache", key = "#loginRequestDto.email()") + @Override public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception { User user = userRepository.findByEmail(loginRequestDto.email()) From b2242e37fe43da49569205a854898ac06b8ec16a Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Thu, 5 Sep 2024 22:35:06 +0200 Subject: [PATCH 09/23] chore: added key - value pairs to the cacheable and cacheevict annotations --- .../backend/services/user/UserServiceImpl.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index 710961ee..a21a0a15 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -60,7 +60,7 @@ public RegisterResponseDto register(RegisterRequestDto registerRequestDto) throw new UserAlreadyExistsError("Email is already taken!"); } } - + @Override public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception { User user = userRepository.findByEmail(loginRequestDto.email()) @@ -73,7 +73,7 @@ public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception return new LoginResponseDto(authService.generateToken(user)); } - @CacheEvict + @CacheEvict(value = "update-profile-cache", key = "#email") @Override public ProfileUpdateResponseDto profileUpdate( String email, @@ -96,7 +96,7 @@ public ProfileUpdateResponseDto profileUpdate( return new ProfileUpdateResponseDto(authService.generateToken(updatedUser)); } - @Cacheable + @Cacheable(value = "profile-cache", key = "#username") @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return userRepository.findByEmail(username) @@ -106,7 +106,7 @@ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundEx /** * Delete the user by username. */ - @CacheEvict + @CacheEvict(value = "delete-cache", key = "#username") @Transactional @Override public void deleteProfile(String username) { From b0fc8b1ef99f1fd32a53824b8451c1d549035302 Mon Sep 17 00:00:00 2001 From: Anna Ugrai Date: Thu, 5 Sep 2024 22:56:22 +0200 Subject: [PATCH 10/23] chore: add cache dependencies to test app properties --- backend/src/test/resources/application.properties | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index ba4ed94d..195fa5c5 100644 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -23,4 +23,9 @@ spring.mail.properties.mail.smtp.starttls.enable=true cors.urls=${CORS_URLS:http://localhost:5173} # Where the verification link will redirect -email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} \ No newline at end of file +email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} + +# Redis configuration +spring.data.redis.host=${CACHE_URL:localhost} +spring.data.redis.port=${CACHE_PORT:6379} +spring.cache.type=none \ No newline at end of file From 7d302d040831b3a82388d8018898fd79f22cd3b9 Mon Sep 17 00:00:00 2001 From: markkovari Date: Fri, 6 Sep 2024 10:34:44 +0200 Subject: [PATCH 11/23] chore: make redis connection conditional --- .../backend/config/RedisConfig.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java index 899e6f40..2a1cc2db 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/RedisConfig.java @@ -1,5 +1,7 @@ package com.greenfoxacademy.backend.config; +import java.time.Duration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.cache.CacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,23 +11,28 @@ import org.springframework.data.redis.serializer.RedisSerializationContext; import org.springframework.data.redis.serializer.StringRedisSerializer; -import java.time.Duration; - /** * RedisConfig is a configuration class that defines the cache management strategy * for Redis in the Spring Boot application. It configures the Redis Cache Manager * and sets key serialization and expiration policies. */ - @Configuration +@ConditionalOnProperty(name = "spring.cache.type", havingValue = "redis") public class RedisConfig { + /** + * The cacheManager method creates a RedisCacheManager bean that is used to manage. + */ @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(Duration.ofMinutes(3)) // Set TTL to 5 minutes .disableCachingNullValues() - .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer())); + .serializeKeysWith( + RedisSerializationContext + .SerializationPair + .fromSerializer(new StringRedisSerializer()) + ); return RedisCacheManager.builder(redisConnectionFactory) .cacheDefaults(cacheConfig) From 0851821ef900b52dc63f08a9183002a30c6f1caf Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 09:24:30 +0200 Subject: [PATCH 12/23] chore: add password for redis cache --- backend/src/main/resources/application.properties | 1 + backend/src/test/resources/application.properties | 2 -- docker-compose.yaml | 5 ++++- frontend/Dockerfile | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 8482850c..51376b05 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -30,4 +30,5 @@ email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} # Redis configuration spring.data.redis.host=${CACHE_URL:localhost} spring.data.redis.port=${CACHE_PORT:6379} +spring.data.redis.password=${CACHE_PASSWORD} spring.cache.type=redis diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index 195fa5c5..9e400d71 100644 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -26,6 +26,4 @@ cors.urls=${CORS_URLS:http://localhost:5173} email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} # Redis configuration -spring.data.redis.host=${CACHE_URL:localhost} -spring.data.redis.port=${CACHE_PORT:6379} spring.cache.type=none \ No newline at end of file diff --git a/docker-compose.yaml b/docker-compose.yaml index ae76a93b..f4c306c5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -11,7 +11,9 @@ services: POSTGRES_DB: petclinic_db redis-cache: - image: redis + image: bitnami/redis + environment: + - REDIS_PASSWORD=some_redis_password ports: - 6379:6379 @@ -35,6 +37,7 @@ services: - CORS_URLS=http://localhost:5173 - CACHE_PORT=6379 - CACHE_URL=redis://redis-cache + - CACHE_PASSWORD=some_redis_password depends_on: - postgres-db - redis-cache diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 48d50621..de382f6f 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -1,5 +1,5 @@ #create frontend container -FROM node:lts as builder +FROM node:lts AS builder WORKDIR /app COPY package*.json ./ RUN npm install From 0f2750962f1b861296747e04fb2ff6ffe6f6f777 Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 09:33:26 +0200 Subject: [PATCH 13/23] chore: add dotenv file to store secrets --- .env.sample | 2 ++ .gitignore | 1 + README.md | 13 +++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 .env.sample diff --git a/.env.sample b/.env.sample new file mode 100644 index 00000000..21df91ba --- /dev/null +++ b/.env.sample @@ -0,0 +1,2 @@ +MAIL_PASSWORD= +MAIL_USERNAME= \ No newline at end of file diff --git a/.gitignore b/.gitignore index f13774e4..28ebe5ea 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ data *.idea .DS_Store +.env \ No newline at end of file diff --git a/README.md b/README.md index c655d596..a7809a97 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,16 @@ You can find the frontend of the project in the `frontend` folder [here](./frontend/README.md). + + +## Environemnts and secrets + +The project uses a `.env` file to store the secrets and environment variables. You can find an example of the file in the `.env.example` file. The dotenv file is used to store the secrets and environment variables for the docker-compose file. + +You can copy the sample file to a new file called `.env` and fill in the values. + +```bash +cp .env.example .env +``` + +then fill in the values in the `.env` file. From 710241851eebec3ae015a04008f3d221793bc5c0 Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 09:46:55 +0200 Subject: [PATCH 14/23] chore: add FeatureFlags config --- .../greenfoxacademy/backend/config/FeatureFlags.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java b/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java new file mode 100644 index 00000000..33a7ca2a --- /dev/null +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java @@ -0,0 +1,10 @@ +package com.greenfoxacademy.backend.config; + +import lombok.Getter; +import org.springframework.context.annotation.Configuration; + +@Configuration +@Getter +public class FeatureFlags { + +} \ No newline at end of file From d03e1bb65c0257d53903a0bbf30b88b48e437edc Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 10:09:37 +0200 Subject: [PATCH 15/23] add: feature flag to disable emailverification process --- .../backend/config/FeatureFlags.java | 6 +++- .../services/mail/EmailServiceImpl.java | 1 + .../services/user/UserServiceImpl.java | 30 +++++++++++-------- .../src/main/resources/application.properties | 5 +++- .../services/user/UserServiceImplTest.java | 14 ++++++++- .../src/test/resources/application.properties | 5 +++- docker-compose.yaml | 1 + 7 files changed, 45 insertions(+), 17 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java b/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java index 33a7ca2a..d6b90e71 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java @@ -1,10 +1,14 @@ package com.greenfoxacademy.backend.config; import lombok.Getter; + +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; -@Configuration @Getter +@Configuration public class FeatureFlags { + @Value("${features.emailVerificationEnabled}") + private boolean emailVerificationEnabled; } \ No newline at end of file diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/mail/EmailServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/mail/EmailServiceImpl.java index 48b59fc7..b2044b9e 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/mail/EmailServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/mail/EmailServiceImpl.java @@ -6,6 +6,7 @@ import jakarta.mail.internet.MimeMessage; import java.util.UUID; import lombok.RequiredArgsConstructor; + import org.springframework.core.io.ClassPathResource; import org.springframework.mail.MailException; import org.springframework.mail.javamail.JavaMailSender; diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index 9a1c5602..b18a1380 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -1,5 +1,6 @@ package com.greenfoxacademy.backend.services.user; +import com.greenfoxacademy.backend.config.FeatureFlags; import com.greenfoxacademy.backend.dtos.LoginRequestDto; import com.greenfoxacademy.backend.dtos.LoginResponseDto; import com.greenfoxacademy.backend.dtos.ProfileUpdateRequestDto; @@ -13,7 +14,9 @@ import com.greenfoxacademy.backend.services.auth.AuthService; import com.greenfoxacademy.backend.services.mail.EmailService; import jakarta.transaction.Transactional; + import java.util.UUID; + import lombok.RequiredArgsConstructor; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UsernameNotFoundException; @@ -30,34 +33,37 @@ public class UserServiceImpl implements UserService { private final PasswordEncoder passwordEncoder; private final AuthService authService; private final EmailService emailService; + private final FeatureFlags featureFlags; @Override public RegisterResponseDto register(RegisterRequestDto registerRequestDto) throws UserAlreadyExistsError { + boolean isEmailEnabled = featureFlags.isEmailVerificationEnabled(); + UUID verificationId = isEmailEnabled ? UUID.randomUUID() : null; // @formatter:off User user = User.builder() .email(registerRequestDto.email()) .firstName(registerRequestDto.firstName()) .lastName(registerRequestDto.lastName()) .password(passwordEncoder.encode(registerRequestDto.password())) - .verificationId(UUID.randomUUID()) + .verificationId(verificationId) .build(); // @formatter:on try { User saved = userRepository.save(user); - emailService.sendRegistrationEmail( - saved.getEmail(), - saved.getFirstName(), - saved.getVerificationId() - ); + if (isEmailEnabled) { + emailService.sendRegistrationEmail( + saved.getEmail(), + saved.getFirstName(), + saved.getVerificationId()); + } return new RegisterResponseDto(saved.getId()); } catch (Exception e) { throw new UserAlreadyExistsError("Email is already taken!"); } } - @Override public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception { User user = userRepository.findByEmail(loginRequestDto.email()) @@ -73,14 +79,11 @@ public LoginResponseDto login(LoginRequestDto loginRequestDto) throws Exception @Override public ProfileUpdateResponseDto profileUpdate( String email, - ProfileUpdateRequestDto profileUpdateRequestDto - ) throws CannotUpdateUserException { + ProfileUpdateRequestDto profileUpdateRequestDto) throws CannotUpdateUserException { User user = userRepository.findByEmail(email) .orElseThrow(() -> new UsernameNotFoundException("User not found")); - if ( - userRepository.existsByEmail(profileUpdateRequestDto.email()) - && !email.equals(profileUpdateRequestDto.email()) - ) { + if (userRepository.existsByEmail(profileUpdateRequestDto.email()) + && !email.equals(profileUpdateRequestDto.email())) { throw new CannotUpdateUserException("Email is already taken!"); } user.setEmail(profileUpdateRequestDto.email()); @@ -111,6 +114,7 @@ public void deleteProfile(String username) { * Verify the user by id sent as email. */ public void verifyUser(UUID id) { + if (!featureFlags.isEmailVerificationEnabled()) return; User userWithId = userRepository.findByVerificationId(id).orElseThrow(); userWithId.setVerificationId(null); userRepository.save(userWithId); diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index 4bdc3553..dacd8d92 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -25,4 +25,7 @@ spring.mail.properties.mail.smtp.auth=true spring.mail.properties.mail.smtp.starttls.enable=true # Where the verification link will redirect -email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} \ No newline at end of file +email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} + +# Feature Flags +features.emailVerificationEnabled=${FEATURE_EMAIL_VERIFICATION_ENABLED:true} diff --git a/backend/src/test/java/com/greenfoxacademy/backend/services/user/UserServiceImplTest.java b/backend/src/test/java/com/greenfoxacademy/backend/services/user/UserServiceImplTest.java index b6b7d4b8..ace03a8a 100644 --- a/backend/src/test/java/com/greenfoxacademy/backend/services/user/UserServiceImplTest.java +++ b/backend/src/test/java/com/greenfoxacademy/backend/services/user/UserServiceImplTest.java @@ -4,6 +4,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.when; +import com.greenfoxacademy.backend.config.FeatureFlags; import com.greenfoxacademy.backend.dtos.LoginRequestDto; import com.greenfoxacademy.backend.dtos.ProfileUpdateRequestDto; import com.greenfoxacademy.backend.dtos.RegisterRequestDto; @@ -13,8 +14,10 @@ import com.greenfoxacademy.backend.repositories.UserRepository; import com.greenfoxacademy.backend.services.auth.AuthService; import com.greenfoxacademy.backend.services.mail.EmailService; + import java.util.Optional; import java.util.UUID; + import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -23,6 +26,7 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; @@ -39,12 +43,19 @@ class UserServiceImplTest { private AuthService authService; @Mock private EmailService emailService; + @Mock + private FeatureFlags featureFlags; @BeforeEach void setUp() { Mockito.reset(userRepository); - userService = new UserServiceImpl(userRepository, passwordEncoder, authService, emailService); + userService = new UserServiceImpl( + userRepository, + passwordEncoder, + authService, + emailService, + featureFlags); } @DisplayName("Register a new user if email not taken") @@ -214,6 +225,7 @@ void loadUserByUsername() { @Test void verifyUserById() { + when(featureFlags.isEmailVerificationEnabled()).thenReturn(true); UUID id = UUID.randomUUID(); User user = User.builder() .id(1) diff --git a/backend/src/test/resources/application.properties b/backend/src/test/resources/application.properties index ba4ed94d..b3e490db 100644 --- a/backend/src/test/resources/application.properties +++ b/backend/src/test/resources/application.properties @@ -23,4 +23,7 @@ spring.mail.properties.mail.smtp.starttls.enable=true cors.urls=${CORS_URLS:http://localhost:5173} # Where the verification link will redirect -email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} \ No newline at end of file +email.baseUrl=${EMAIL_BASEURL:http://localhost:8080} + +# Feature Flags +features.emailVerificationEnabled=${FEATURE_EMAIL_VERIFICATION_ENABLED:true} diff --git a/docker-compose.yaml b/docker-compose.yaml index c29112e5..ec69b6f5 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -28,5 +28,6 @@ services: - DATABASE_USER=petclinic_db_user - DATABASE_PASSWORD=petclinic_db_password - CORS_URLS=http://localhost:5173 + - FEATURE_EMAIL_VERIFICATION_ENABLED=false depends_on: - postgres-db From 7a313a33d691fb69799f3e2b739d16c998eb7fa4 Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 10:18:49 +0200 Subject: [PATCH 16/23] fix: checkstyle issues --- .../com/greenfoxacademy/backend/config/FeatureFlags.java | 7 ++++++- .../backend/services/user/UserServiceImpl.java | 4 +++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java b/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java index d6b90e71..a89f63c6 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/config/FeatureFlags.java @@ -1,14 +1,19 @@ package com.greenfoxacademy.backend.config; import lombok.Getter; - import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Configuration; +/** + * Configuration class for feature flags. + */ @Getter @Configuration public class FeatureFlags { + /** + * Flag to enable email verification. + */ @Value("${features.emailVerificationEnabled}") private boolean emailVerificationEnabled; } \ No newline at end of file diff --git a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java index 883ed057..937de714 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/services/user/UserServiceImpl.java @@ -119,7 +119,9 @@ public void deleteProfile(String username) { * Verify the user by id sent as email. */ public void verifyUser(UUID id) { - if (!featureFlags.isEmailVerificationEnabled()) return; + if (!featureFlags.isEmailVerificationEnabled()) { + return; + } User userWithId = userRepository.findByVerificationId(id).orElseThrow(); userWithId.setVerificationId(null); userRepository.save(userWithId); From b7d780ed3e0c329983efc31ae4b25db46d8c1b29 Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 10:28:19 +0200 Subject: [PATCH 17/23] chore: add documentation for feature --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index c655d596..05663a1e 100644 --- a/README.md +++ b/README.md @@ -6,3 +6,9 @@ You can find the frontend of the project in the `frontend` folder [here](./frontend/README.md). + +### Feature toggles + +| Feature | Description | Environment Variable | Default | +| ------------------- | -------------------------------------- | ---------------------------------- | ------- | +| email verificiation | Email verification during registration | FEATURE_EMAIL_VERIFICATION_ENABLED | false | From b5f12fe6c0b16c1cdbc688f841d5d1dffcc8ae56 Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 11:02:31 +0200 Subject: [PATCH 18/23] refactor: protectedpage on frontend --- frontend/src/pages/utils/ProtectedPage.tsx | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/utils/ProtectedPage.tsx b/frontend/src/pages/utils/ProtectedPage.tsx index 1d3842d5..0e09090a 100644 --- a/frontend/src/pages/utils/ProtectedPage.tsx +++ b/frontend/src/pages/utils/ProtectedPage.tsx @@ -1,16 +1,15 @@ import type { PropsWithChildren } from "react"; +import { Navigate } from "react-router-dom"; import { usePetClinicState } from "../../state"; -import { Login } from "../Login"; - type ProtectedPageProps = PropsWithChildren; const ProtectedPage = ({ children }: ProtectedPageProps) => { const { auth: { user }, } = usePetClinicState(); - if (user) { - return <>{children}; + if (!user) { + return ; } - return ; + return <>{children}; }; export { ProtectedPage }; From 6ad9ba90bd942d0dcb435e1f963c1d348246725a Mon Sep 17 00:00:00 2001 From: AnnaUgrai <149159395+AnnaUgrai@users.noreply.github.com> Date: Sat, 7 Sep 2024 12:36:13 +0200 Subject: [PATCH 19/23] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Márk Kővári --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a7809a97..00802f87 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The project uses a `.env` file to store the secrets and environment variables. Y You can copy the sample file to a new file called `.env` and fill in the values. ```bash -cp .env.example .env +cp .env.sample .env ``` then fill in the values in the `.env` file. From 24b6344445806142bce3342598b1318afcbe81aa Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 12:21:29 +0200 Subject: [PATCH 20/23] fix: make buttons visible --- frontend/src/pages/Login.tsx | 6 ++++-- frontend/src/pages/ProfileDeletion.tsx | 10 +++++----- frontend/src/pages/ProfileDetail.tsx | 5 +++-- frontend/src/pages/ProfileUpdate.tsx | 9 ++++++--- frontend/src/pages/Register.tsx | 6 ++++-- 5 files changed, 22 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/Login.tsx b/frontend/src/pages/Login.tsx index 30c2971c..f4d77f34 100644 --- a/frontend/src/pages/Login.tsx +++ b/frontend/src/pages/Login.tsx @@ -1,4 +1,4 @@ -import { useToast } from "@chakra-ui/react"; +import { Button, useToast } from "@chakra-ui/react"; import type { ChangeEvent, FormEvent } from "react"; import { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; @@ -67,7 +67,9 @@ export function Login() { autoComplete="current-password" required={true} /> - + Main diff --git a/frontend/src/pages/ProfileDeletion.tsx b/frontend/src/pages/ProfileDeletion.tsx index b10aaff1..ef3f8583 100644 --- a/frontend/src/pages/ProfileDeletion.tsx +++ b/frontend/src/pages/ProfileDeletion.tsx @@ -1,4 +1,4 @@ -import { useToast } from "@chakra-ui/react"; +import { Button, useToast } from "@chakra-ui/react"; import { useNavigate } from "react-router-dom"; import { deleteProfile } from "../httpClient.ts"; import { usePetClinicState } from "../state.ts"; @@ -44,21 +44,21 @@ export function ProfileDeletion() { profile? We're sad to see you go! Please remember, this action is permanent and you'll lose all your data."

- - + ); } diff --git a/frontend/src/pages/ProfileDetail.tsx b/frontend/src/pages/ProfileDetail.tsx index bfda1e5f..40b2a8e6 100644 --- a/frontend/src/pages/ProfileDetail.tsx +++ b/frontend/src/pages/ProfileDetail.tsx @@ -1,3 +1,4 @@ +import { Button } from "@chakra-ui/react"; import { Link, useNavigate } from "react-router-dom"; import { usePetClinicState } from "../state.ts"; @@ -27,13 +28,13 @@ export function ProfileDetail() { Profile update - + ); } diff --git a/frontend/src/pages/ProfileUpdate.tsx b/frontend/src/pages/ProfileUpdate.tsx index d141a901..bd400fa5 100644 --- a/frontend/src/pages/ProfileUpdate.tsx +++ b/frontend/src/pages/ProfileUpdate.tsx @@ -1,3 +1,4 @@ +import { Button } from "@chakra-ui/react"; import type { ChangeEvent, FormEvent } from "react"; import { PasswordStrengthValidator } from "../components/PasswordStrengthValidator"; import { @@ -71,10 +72,12 @@ export function ProfileUpdate() { required={true} /> - - + + ); diff --git a/frontend/src/pages/Register.tsx b/frontend/src/pages/Register.tsx index bdd44cf0..17555d06 100644 --- a/frontend/src/pages/Register.tsx +++ b/frontend/src/pages/Register.tsx @@ -1,4 +1,4 @@ -import { useToast } from "@chakra-ui/react"; +import { Button, useToast } from "@chakra-ui/react"; import type { ChangeEvent, FormEvent } from "react"; import { useState } from "react"; import { Link } from "react-router-dom"; @@ -90,7 +90,9 @@ function Register() { onChange={handleUserChange} /> - + Login From 37d8351ee48e30bb126cd6563fc39a2b9937aa2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20K=C5=91v=C3=A1ri?= Date: Sat, 7 Sep 2024 04:16:52 -0700 Subject: [PATCH 21/23] Update frontend/src/pages/ProfileDeletion.tsx --- frontend/src/pages/ProfileDeletion.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/ProfileDeletion.tsx b/frontend/src/pages/ProfileDeletion.tsx index 72074984..6bc835b6 100644 --- a/frontend/src/pages/ProfileDeletion.tsx +++ b/frontend/src/pages/ProfileDeletion.tsx @@ -29,7 +29,7 @@ export function ProfileDeletion() { } catch (error) { if (error instanceof AxiosError) { toast({ - title: "Cannot login 🫣.", + title: "Cannot delete profile 🫣.", description: error.response?.data.error || "Unknown network error, please contact support.", From a307fd7cfeae38df7223cd9ec087b4aaa371a06d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20K=C5=91v=C3=A1ri?= Date: Sat, 7 Sep 2024 04:16:58 -0700 Subject: [PATCH 22/23] Update frontend/src/pages/Register.tsx --- frontend/src/pages/Register.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/pages/Register.tsx b/frontend/src/pages/Register.tsx index c1a1bcb1..cdd506d5 100644 --- a/frontend/src/pages/Register.tsx +++ b/frontend/src/pages/Register.tsx @@ -42,7 +42,7 @@ function Register() { } catch (error) { if (error instanceof AxiosError) { toast({ - title: "Cannot login 🫣.", + title: "Cannot register 🫣.", description: error.response?.data.error || "Unknown network error, please contact support.", From 69b8f08eabc438a38e3f831ac3541707cce204d3 Mon Sep 17 00:00:00 2001 From: markkovari Date: Sat, 7 Sep 2024 15:04:14 +0200 Subject: [PATCH 23/23] fix: imports --- .../src/main/java/com/greenfoxacademy/backend/models/Pet.java | 2 -- .../backend/services/user/OwnerServiceImplTest.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/backend/src/main/java/com/greenfoxacademy/backend/models/Pet.java b/backend/src/main/java/com/greenfoxacademy/backend/models/Pet.java index 791ff3d6..6fd1d341 100644 --- a/backend/src/main/java/com/greenfoxacademy/backend/models/Pet.java +++ b/backend/src/main/java/com/greenfoxacademy/backend/models/Pet.java @@ -8,9 +8,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; - import java.util.Date; - import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; diff --git a/backend/src/test/java/com/greenfoxacademy/backend/services/user/OwnerServiceImplTest.java b/backend/src/test/java/com/greenfoxacademy/backend/services/user/OwnerServiceImplTest.java index 4fba12ec..bcdde253 100644 --- a/backend/src/test/java/com/greenfoxacademy/backend/services/user/OwnerServiceImplTest.java +++ b/backend/src/test/java/com/greenfoxacademy/backend/services/user/OwnerServiceImplTest.java @@ -17,7 +17,6 @@ import com.greenfoxacademy.backend.services.user.owner.OwnerServiceImpl; import java.util.Optional; import java.util.UUID; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; @@ -26,7 +25,6 @@ import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;