73 Commits

Author SHA1 Message Date
86e902bbfe few small fixes 2025-06-13 17:51:35 +02:00
d9a8ffe4bd Merge branch 'environment-vars' 2025-06-11 23:34:32 +02:00
c59998c113 fix nested file 2025-06-11 23:31:19 +02:00
ff5dc5c090 Warnings fixed, logs added to tests 2025-06-11 23:00:12 +02:00
4d7a191e8a Added logs to ClientServiceTest 2025-06-11 22:30:50 +02:00
7c7e82b0e6 Image test and variablescontroller tests added 2025-06-11 22:18:56 +02:00
7d070075d6 Image test and variablescontroller tests added 2025-06-11 22:17:48 +02:00
b24d263f22 AuthController updated
AuthServiceTest added
2025-06-11 21:31:12 +02:00
f7023f9c4a ClientService Tests added 2025-06-11 21:02:42 +02:00
cad54d7b96 Order Tests added 2025-06-11 20:50:27 +02:00
b124a4b0e8 Wishlist and Notice Tests added 2025-06-11 20:33:37 +02:00
6e318a07c6 Text update 2025-06-11 19:42:04 +02:00
b476f2e8c9 ClientControllerTest addded 2025-06-11 19:32:48 +02:00
a7c8f22658 isMainImage pobierane z Frontend 2025-06-11 19:05:16 +02:00
5d7ab8d45d DisplayName in EmailController 2025-06-11 18:27:54 +02:00
5addf38127 EmailControllerTest added 2025-06-11 18:22:59 +02:00
f31885c795 implementacja zmiennych środowiskowych 2025-06-11 18:21:26 +02:00
a5bc401e89 Merge remote-tracking branch 'refs/remotes/origin/main' into tests 2025-06-10 22:23:37 +02:00
edeb36cb8c podwójne kodowanie hasło zlikwidowane 2025-06-10 20:21:21 +02:00
bacfd529aa obsługa przekierowania płatności 2025-06-10 19:54:25 +02:00
8656ececf1 another email supplier 2025-06-10 14:09:07 +02:00
1d104493b5 Merge branch 'refactor-auth' 2025-06-10 11:03:59 +02:00
3355914c70 Refactor of the whole AuthController 2025-06-10 10:26:29 +02:00
dfa747f548 Merge branch 'refs/heads/main' into tests 2025-06-09 21:51:45 +02:00
d51161221c Merge branch 'fix-payments' 2025-06-09 20:59:20 +02:00
Patryk
422daeb99e Merge remote-tracking branch 'origin/fix-payments' into fix-payments 2025-06-09 20:58:40 +02:00
Patryk
3204b921c4 fix tapy 2025-06-09 20:58:09 +02:00
f56ffacec3 filter 2025-06-09 20:39:57 +02:00
0f14c72fdd login endpoint refactored 2025-06-09 19:57:27 +02:00
2589c6010e Dodawanie atrybutów razem z notice 2025-06-08 20:15:26 +02:00
Patryk
1ec6e62c04 fix payments and add new functions 2025-06-08 19:54:15 +02:00
00b9f99af5 Refactor
added possibility to get attributes
2025-06-08 14:36:38 +02:00
81cbc1f4b2 ClientID for orders 2025-06-08 10:25:36 +02:00
190083c133 ClientId from token in Wishlist controller 2025-06-07 15:18:51 +02:00
f9f2bff77e user role fix 2025-06-07 14:48:54 +02:00
3d064e0496 Merge branch 'main' into tests 2025-06-07 14:42:51 +02:00
501121f235 Merge branch 'autoryzacja' 2025-06-07 14:38:50 +02:00
62a5ad1bc6 MailSender is working 2025-06-07 13:20:37 +02:00
5262749e2d autoryzacja google 2025-06-06 16:05:18 +02:00
5f548de73a dto change to show good role 2025-06-04 12:07:56 +02:00
ffbd8d220c dużo lepsza autoryzacja teraz, dużo lepsza. Tokeny wygasają, można mieć tylko jeden aktywny token per user 2025-06-02 13:46:09 +02:00
0d32b4a495 Merge branch 'paymentIntegration' into autoryzacja
# Conflicts:
#	src/main/resources/application.properties
2025-06-01 09:51:53 +02:00
8ea5d84779 change trasacitonID 2025-05-31 12:47:03 +02:00
a09603f8cb add toString to TransactionPaymentResponseDTO 2025-05-31 12:45:01 +02:00
45c607060a test payment request v2 2025-05-31 12:38:54 +02:00
0b85fed4b8 test payment request 2025-05-31 12:33:38 +02:00
d2163e1601 Merge remote-tracking branch 'origin/paymentIntegration' 2025-05-31 12:12:03 +02:00
293be1d46e Autoryzacja początkowo zaimplementowana 2025-05-31 12:02:15 +02:00
3b9b0769d1 Testy 2025-05-30 22:46:42 +02:00
f4c8177270 change wishlist toogle 2025-05-29 23:17:54 +02:00
Patryk
9b64dc8da8 fix return url 2025-05-26 21:59:26 +02:00
Patryk
12cb37127b ad: handling of payment notifications 2025-05-26 21:51:24 +02:00
Patryk
281cc627de add payment notification endpoint 2025-05-26 20:36:39 +02:00
3e5baa34d1 Testy 2025-05-23 22:15:36 +02:00
Patryk
6363f966f6 Integrate simple payment handling with WebClient and persist results 2025-05-23 19:06:19 +02:00
Patryk
c642f6f87b create order and change order status 2025-05-20 22:25:00 +02:00
Patryk
65524d0f25 Merge branch 'main' into initOrderAndPayments 2025-05-20 21:25:10 +02:00
Patryk
71fdf1640a change order entities and ad tpay api keys 2025-05-20 21:17:31 +02:00
8fae9f1e55 fix of Kiedy usuwasz ogłoszenie, nie usuwają zdjęcia z bazy i z dysku 2025-05-20 10:37:04 +02:00
d869a18901 boost controller endpoint little fix
+ get rid of not used dependencies
2025-05-16 13:42:24 +02:00
Patryk
1d55f40753 add boostNotice function 2025-05-15 20:29:37 +02:00
3d205df038 few cosmetic fixes 2025-05-14 08:35:33 +02:00
Patryk
5ccfc6ba2c change repository to service in wishlist, add @Lazy 2025-05-13 20:54:44 +02:00
Patryk
f0e3a129d0 change repository to service in wishlist, add @Lazy 2025-05-13 20:54:39 +02:00
Patryk
cdd31fd6b7 init wishlist files 2025-05-12 19:57:00 +02:00
09c15e70d9 New way of categories transfer 2025-05-05 10:10:03 +02:00
3b85b12741 Few improvements such as
application.properties.prod file
new DTO for response when adding notice
2025-05-02 14:49:22 +02:00
039678b90a Categories as map 2025-04-28 18:37:41 +02:00
025f733362 added endpoint for variables 2025-04-28 15:58:59 +02:00
c2f74ab799 little fixes one more time 2025-04-28 15:44:35 +02:00
bf565178f6 fix of images deletion 2025-04-28 15:06:32 +02:00
7f8f13b115 Images are working but still there is need to add isImageMain flag to images. 2025-04-28 14:17:38 +02:00
6b5dded7f8 WIP for images 2025-04-24 07:34:53 +02:00
93 changed files with 4571 additions and 392 deletions

View File

@@ -1,5 +1,7 @@
FROM openjdk:21
COPY target/ArtisanConnectBackend-0.0.1-SNAPSHOT.jar app.jar
WORKDIR /app
ENTRYPOINT ["java","-jar","/app.jar"]
COPY target/ArtisanConnectBackend-0.0.1-SNAPSHOT.jar app/artisan.jar
ENTRYPOINT ["java","-jar","app/artisan.jar"]

View File

@@ -2,10 +2,13 @@ services:
app:
container_name: artisan
build: .
networks:
- artisan_network
depends_on:
- db
networks:
- artisan_network
ports:
- '8085:8080'
db:
container_name: db

65
pom.xml
View File

@@ -10,7 +10,7 @@
</parent>
<groupId>_11.asktpk</groupId>
<artifactId>ArtisanConnectBackend</artifactId>
<version>0.0.1-SNAPSHOT</version>
<version>1.0.0</version>
<name>ArtisanConnectBackend</name>
<description>ArtisanConnectBackend</description>
<url/>
@@ -34,31 +34,21 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-starter-oauth2-client</artifactId>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.boot</groupId>-->
<!-- <artifactId>spring-boot-docker-compose</artifactId>-->
<!-- <scope>runtime</scope>-->
<!-- <optional>true</optional>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
<version>2.4.12</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
@@ -73,15 +63,10 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.security</groupId>-->
<!-- <artifactId>spring-security-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
<version>4.12.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
@@ -93,6 +78,42 @@
<artifactId>jakarta.validation-api</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
<version>3.3.4</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.5</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.5</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>

View File

@@ -1,13 +1,27 @@
package _11.asktpk.artisanconnectbackend;
import jakarta.annotation.PostConstruct;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.core.env.Environment;
@SpringBootApplication
public class ArtisanConnectBackendApplication {
private final Environment environment;
public ArtisanConnectBackendApplication(Environment environment) {
this.environment = environment;
}
public static void main(String[] args) {
SpringApplication.run(ArtisanConnectBackendApplication.class, args);
}
@PostConstruct
public void logDataSourceUrl() {
System.out.println("Datasource URL: " + environment.getProperty("spring.datasource.url"));
}
}

View File

@@ -0,0 +1,15 @@
package _11.asktpk.artisanconnectbackend.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class AppConfig {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

View File

@@ -0,0 +1,35 @@
package _11.asktpk.artisanconnectbackend.config;
import _11.asktpk.artisanconnectbackend.dto.RequestResponseDTO;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;
@Controller
public class CustomErrorController implements ErrorController {
@RequestMapping("/error")
public ResponseEntity<RequestResponseDTO> handleError(HttpServletRequest request) {
Object status = request.getAttribute(RequestDispatcher.ERROR_STATUS_CODE);
if (status != null) {
int statusCode = Integer.parseInt(status.toString());
if (statusCode == HttpStatus.NOT_FOUND.value()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new RequestResponseDTO("Nie znaleziono zasobu. Sprawdź URL i spróbuj ponownie."));
} else if (statusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new RequestResponseDTO("Wystąpił wewnętrzny błąd serwera. Spróbuj ponownie później."));
}
}
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(new RequestResponseDTO("Wystąpił nieoczekiwany błąd."));
}
}

View File

@@ -0,0 +1,38 @@
package _11.asktpk.artisanconnectbackend.config;
import _11.asktpk.artisanconnectbackend.security.JwtRequestFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtRequestFilter jwtRequestFilter;
public SecurityConfig(JwtRequestFilter jwtRequestFilter) {
this.jwtRequestFilter = jwtRequestFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.cors(cors -> cors.configure(http))
.csrf(AbstractHttpConfigurer::disable)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/v1/auth/**", "/api/v1/payments/notification").permitAll()
.anyRequest().authenticated())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}

View File

@@ -0,0 +1,109 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.customExceptions.ClientAlreadyExistsException;
import _11.asktpk.artisanconnectbackend.customExceptions.WrongLoginPasswordException;
import _11.asktpk.artisanconnectbackend.dto.*;
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
import _11.asktpk.artisanconnectbackend.service.AuthService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.HttpClientErrorException;
@Slf4j
@RestController
@RequestMapping("/api/v1/auth")
public class AuthController {
private final AuthService authService;
private final JwtUtil jwtUtil;
public AuthController(AuthService authService, JwtUtil jwtUtil) {
this.authService = authService;
this.jwtUtil = jwtUtil;
}
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody AuthRequestDTO authRequestDTO) {
if (authRequestDTO.getEmail() == null || authRequestDTO.getPassword() == null
|| authRequestDTO.getEmail().isEmpty() || authRequestDTO.getPassword().isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Przekazano puste login lub hasło"));
}
authRequestDTO.setEmail(authRequestDTO.getEmail().toLowerCase());
try {
AuthResponseDTO responseDTO = authService.login(authRequestDTO.getEmail(), authRequestDTO.getPassword());
return ResponseEntity.status(HttpStatus.OK)
.body(responseDTO);
} catch (WrongLoginPasswordException e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new RequestResponseDTO(e.getMessage()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO(e.getMessage()));
}
}
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody ClientRegistrationDTO clientRegistrationDTO) {
if (clientRegistrationDTO.getEmail() == null || clientRegistrationDTO.getPassword() == null
|| clientRegistrationDTO.getEmail().isEmpty() || clientRegistrationDTO.getPassword().isEmpty()) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Przekazano puste login lub hasło"));
}
clientRegistrationDTO.setEmail(clientRegistrationDTO.getEmail().toLowerCase());
try {
AuthResponseDTO registrationData = authService.register(clientRegistrationDTO.getEmail(), clientRegistrationDTO.getPassword(), clientRegistrationDTO.getFirstName(), clientRegistrationDTO.getLastName());
return ResponseEntity.status(HttpStatus.CREATED)
.body(registrationData);
} catch (ClientAlreadyExistsException clientAlreadyExistsException) {
return ResponseEntity.status(HttpStatus.CONFLICT)
.body(new RequestResponseDTO(clientAlreadyExistsException.getMessage()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO(e.getMessage()));
}
}
@PostMapping("/logout")
public ResponseEntity<RequestResponseDTO> logout(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
authService.logout(token);
return ResponseEntity.ok(new RequestResponseDTO("Successfully logged out"));
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Invalid token"));
}
@PostMapping("/google")
public ResponseEntity<?> authenticateWithGoogle(@RequestBody GoogleAuthRequestDTO dto) {
if(dto.getGoogleToken() == null){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Invalid or empty token"));
}
try {
AuthResponseDTO response = authService.googleLogin(dto.getGoogleToken());
return ResponseEntity.status(HttpStatus.OK).body(response);
} catch (HttpClientErrorException httpClientErrorException) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Google access token is invalid or expired"));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
.body(new RequestResponseDTO("Authentication Error (Google): " + e.getMessage()));
}
}
@GetMapping("/me")
public ResponseEntity<?> getMe(HttpServletRequest request) {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7);
return ResponseEntity.status(HttpStatus.OK).body(new AuthResponseDTO(jwtUtil.extractUserId(token), jwtUtil.extractRole(token), token));
}
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Invalid or empty token"));
}
}

View File

@@ -24,16 +24,16 @@ public class ClientController {
}
@GetMapping("/get/{id}")
public ResponseEntity getClientById(@PathVariable long id) {
public ResponseEntity<?> getClientById(@PathVariable long id) {
if(clientService.getClientById(id) != null) {
return new ResponseEntity(clientService.getClientById(id), HttpStatus.OK);
return new ResponseEntity<>(clientService.getClientByIdDTO(id), HttpStatus.OK);
} else {
return new ResponseEntity(HttpStatus.NOT_FOUND);
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
@PostMapping("/add")
public ResponseEntity addClient(@RequestBody ClientDTO clientDTO) {
public ResponseEntity<?> addClient(@RequestBody ClientDTO clientDTO) {
if(clientService.clientExists(clientDTO.getId())) {
return new ResponseEntity<>(HttpStatus.CONFLICT);
} else {
@@ -43,7 +43,7 @@ public class ClientController {
// TODO: do zrobienia walidacja danych
@PutMapping("/edit/{id}")
public ResponseEntity updateClient(@PathVariable("id") long id, @RequestBody ClientDTO clientDTO) {
public ResponseEntity<?> updateClient(@PathVariable("id") long id, @RequestBody ClientDTO clientDTO) {
if(clientService.clientExists(id)) {
return new ResponseEntity<>(clientService.updateClient(id, clientDTO),HttpStatus.OK);
} else {
@@ -52,7 +52,7 @@ public class ClientController {
}
@DeleteMapping("/delete/{id}")
public ResponseEntity deleteClient(@PathVariable("id") long id) {
public ResponseEntity<?> deleteClient(@PathVariable("id") long id) {
if(clientService.clientExists(id)) {
clientService.deleteClient(id);
return new ResponseEntity<>(HttpStatus.OK);

View File

@@ -0,0 +1,25 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.dto.EmailDTO;
import _11.asktpk.artisanconnectbackend.service.EmailService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/v1/email")
public class EmailController {
private final EmailService emailService;
public EmailController(EmailService emailService) {
this.emailService = emailService;
}
@PostMapping("/send")
public ResponseEntity<String> sendEmail(@RequestBody EmailDTO email) {
try {
emailService.sendEmail(email);
return ResponseEntity.ok("Email wysłany pomyślnie");
} catch (Exception e) {
return ResponseEntity.status(500).body("Błąd podczas wysyłania emaila");
}
}
}

View File

@@ -0,0 +1,95 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.dto.RequestResponseDTO;
import _11.asktpk.artisanconnectbackend.service.ImageService;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.data.repository.query.Param;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.*;
@RestController
@RequestMapping("/api/v1/images")
public class ImageController {
private final ImageService imageService;
private final NoticeService noticeService;
ImageController(ImageService imageService, NoticeService noticeService) {
this.imageService = imageService;
this.noticeService = noticeService;
}
@Value("${file.upload-dir}")
private String uploadDir;
@PostMapping("/upload/{id}")
public ResponseEntity<RequestResponseDTO> uploadImage(@RequestParam("file") MultipartFile file, @PathVariable("id") Long noticeId, @Param("isMainImage") Boolean isMainImage) {
try {
if(file.isEmpty()) {
return ResponseEntity.badRequest().body(new RequestResponseDTO("File is empty"));
}
if(!Objects.equals(file.getContentType(), "image/jpeg") && !Objects.equals(file.getContentType(), "image/png")) {
return ResponseEntity.badRequest().body(new RequestResponseDTO("File must be a JPEG or PNG image."));
}
if(noticeId == null || !noticeService.noticeExists(noticeId)) {
return ResponseEntity.badRequest().body(new RequestResponseDTO("Notice ID is invalid or does not exist."));
}
String newImageName = imageService.saveImageToStorage(uploadDir, file);
imageService.addImageNameToDB(newImageName, noticeId, isMainImage);
return ResponseEntity.ok(new RequestResponseDTO("Image uploaded successfully with new name: " + newImageName));
} catch (Exception e) {
System.out.println(e.getMessage());
return ResponseEntity.status(HttpStatus.UNSUPPORTED_MEDIA_TYPE).body(new RequestResponseDTO(e.getMessage()));
}
}
@GetMapping("/get/{filename}")
public ResponseEntity<Resource> getImage(@PathVariable String filename) {
try {
return ResponseEntity.ok()
.contentType(MediaType.IMAGE_JPEG)
.body(imageService.getImage(uploadDir, filename));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).build();
}
}
@GetMapping("/list/{id}")
public ResponseEntity<?> getImagesNamesList(@PathVariable("id") Long noticeId) {
List<String> result;
try {
noticeService.getNoticeById(noticeId);
result = imageService.getImagesList(noticeId);
return ResponseEntity.ok(result);
} catch (EntityNotFoundException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO(e.getMessage()));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new RequestResponseDTO(e.getMessage()));
}
}
@DeleteMapping("/delete/{filename}")
public ResponseEntity<RequestResponseDTO> deleteImage(@PathVariable("filename") String filename) {
if(filename == null) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new RequestResponseDTO("Filename is empty."));
}
try {
imageService.deleteImage(uploadDir, filename);
return ResponseEntity.status(HttpStatus.OK).body(new RequestResponseDTO("Image deleted successfully."));
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new RequestResponseDTO(e.getMessage()));
}
}
}

View File

@@ -1,18 +1,17 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.dto.*;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import _11.asktpk.artisanconnectbackend.dto.NoticeDTO;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import jakarta.persistence.EntityNotFoundException;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@RequestMapping("/api/v1/notices")
@@ -20,19 +19,21 @@ import java.util.List;
public class NoticeController {
private final NoticeService noticeService;
private final ClientService clientService;
private final Tools tools;
public NoticeController(NoticeService noticeService, ClientService clientService) {
public NoticeController(NoticeService noticeService, ClientService clientService, Tools tools) {
this.noticeService = noticeService;
this.clientService = clientService;
this.tools = tools;
}
@GetMapping("/get/all")
public List<NoticeDTO> getAllNotices() {
public List<NoticeResponseDTO> getAllNotices() {
return noticeService.getAllNotices();
}
@GetMapping("/get/{id}")
public ResponseEntity getNoticeById(@PathVariable long id) {
public ResponseEntity<?> getNoticeById(@PathVariable long id) {
if (noticeService.noticeExists(id)) {
return ResponseEntity.ok(noticeService.getNoticeById(id));
} else {
@@ -41,55 +42,34 @@ public class NoticeController {
}
@PostMapping("/add")
public ResponseEntity<String> addNotice(@RequestBody NoticeDTO dto) {
if (!clientService.clientExists(dto.getClientId())) {
public ResponseEntity<NoticeAdditionDTO> addNotice(@RequestBody NoticeRequestDTO dto, HttpServletRequest request) {
Long clientId = tools.getClientIdFromRequest(request);
if (!clientService.clientExists(clientId)) {
return ResponseEntity
.status(HttpStatus.BAD_REQUEST)
.body("Nie znaleziono klienta o ID: " + dto.getClientId());
.body(new NoticeAdditionDTO("Nie znaleziono klienta o ID: " + clientId));
}
dto.setPublishDate(java.time.LocalDateTime.now());
dto.setClientId(clientId);
noticeService.addNotice(dto);
return ResponseEntity.status(HttpStatus.CREATED).body("Dodano ogłoszenie.");
}
// TODO: zamiast dodawać tutaj pętlą, musi to robić NoticeService, trzeba zaimplementować odpowienią metodę
@PostMapping("/bulk_add")
public ResponseEntity<String> addNotices(@RequestBody List<NoticeDTO> notices_list) {
ResponseEntity<String> response = new ResponseEntity<>(HttpStatus.CREATED);
List<String> errors = new ArrayList<>();
boolean isError = false;
if (notices_list.isEmpty()) {
return response.status(HttpStatus.BAD_REQUEST).body("Lista ogłoszeń jest pusta.");
if (dto.getCategory() == null || !Arrays.asList(Enums.Category.values()).contains(dto.getCategory())) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new NoticeAdditionDTO("Nie ma takiej kategorii"));
}
for (NoticeDTO dto : notices_list) {
if (!clientService.clientExists(dto.getClientId())) {
isError = true;
errors.add(dto.getClientId().toString());
} else {
if (!isError) {
noticeService.addNotice(dto);
}
}
}
Long newNoticeId = noticeService.addNotice(dto);
if (isError) {
return response.status(HttpStatus.BAD_REQUEST).body("Nie znaleziono klientów: " + errors);
}
return response;
return ResponseEntity.status(HttpStatus.CREATED).body(new NoticeAdditionDTO(newNoticeId ,"Dodano ogłoszenie."));
}
@PutMapping("/edit/{id}")
public ResponseEntity<Object> editNotice(@PathVariable("id") long id, @RequestBody NoticeDTO dto) {
public ResponseEntity<Object> editNotice(@PathVariable("id") long id, @RequestBody NoticeRequestDTO dto, HttpServletRequest request) {
Long clientIdFromToken = tools.getClientIdFromRequest(request);
if (noticeService.noticeExists(id)) {
if (!noticeService.isNoticeOwnedByClient(id, clientIdFromToken)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new RequestResponseDTO("Nie masz uprawnień do edycji tego ogłoszenia."));
}
try {
return new ResponseEntity<>(noticeService.updateNotice(id, dto), HttpStatus.OK);
return ResponseEntity.status(HttpStatus.OK).body(noticeService.updateNotice(id, dto));
} catch (EntityNotFoundException e) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage());
}
@@ -99,61 +79,28 @@ public class NoticeController {
}
@DeleteMapping("/delete/{id}")
public ResponseEntity deleteNotice(@PathVariable("id") long id) {
public ResponseEntity<RequestResponseDTO> deleteNotice(@PathVariable("id") long id, HttpServletRequest request) {
Long clientIdFromToken = tools.getClientIdFromRequest(request);
if (noticeService.noticeExists(id)) {
if (!noticeService.isNoticeOwnedByClient(id, clientIdFromToken)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(new RequestResponseDTO("Nie masz uprawnień do usunięcia tego ogłoszenia."));
}
noticeService.deleteNotice(id);
return new ResponseEntity<>(HttpStatus.OK);
return ResponseEntity.status(HttpStatus.OK).body(new RequestResponseDTO("Pomyślnie usunięto ogłoszenie o ID: " + id));
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new RequestResponseDTO("Nie znaleziono ogłoszenia o ID: " + id));
}
}
@PostMapping("/upload/{id}")
public ResponseEntity<String> uploadImage(@PathVariable("id") Long id, @RequestParam("file") MultipartFile file) {
if (!noticeService.noticeExists(id)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nie znaleziono ogłoszenia o ID: " + id);
@PostMapping("/boost")
public ResponseEntity<RequestResponseDTO> boostNotice(@RequestBody NoticeBoostDTO dto, HttpServletRequest request) {
Long clientId = tools.getClientIdFromRequest(request);
if (noticeService.isNoticeOwnedByClient(dto.getNoticeId(), clientId)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new RequestResponseDTO("Ogłoszenie nie istnieje lub nie należy do zalogowanego klienta."));
}
noticeService.boostNotice(dto.getNoticeId());
try {
String filePath = noticeService.saveImage(id, file);
return ResponseEntity.ok("Zdjęcie zapisane pod ścieżką: " + filePath);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Błąd podczas zapisywania zdjęcia: " + e.getMessage());
}
return ResponseEntity.status(HttpStatus.OK).body(new RequestResponseDTO("Ogłoszenie zostało pomyślnie wypromowane."));
}
@GetMapping("/images/{id}")
public ResponseEntity<List<String>> getAllImages(@PathVariable("id") Long id) {
try {
Path directoryPath = Paths.get("src/main/resources/static/images/notices/" + id);
if (!Files.exists(directoryPath) || !Files.isDirectory(directoryPath)) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
List<String> imagePaths = new ArrayList<>();
Files.list(directoryPath).forEach(file -> {
if (Files.isRegularFile(file) && Files.isReadable(file)) {
imagePaths.add(file.toString());
}
});
if (imagePaths.isEmpty()) {
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
}
return ResponseEntity.ok(imagePaths);
} catch (Exception e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
}
}
// @GetMapping("/check/{id}")
// public ResponseEntity<String> checkNotice(@PathVariable("id") long id) {
// if (noticeService.noticeExists(id)) {
// return ResponseEntity.ok("Ogłoszenie o ID " + id + " istnieje.");
// } else {
// return ResponseEntity.status(HttpStatus.NOT_FOUND).body("Nie znaleziono ogłoszenia o ID: " + id);
// }
// }
}

View File

@@ -0,0 +1,136 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.dto.*;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Order;
import _11.asktpk.artisanconnectbackend.entities.Payment;
import _11.asktpk.artisanconnectbackend.service.OrderService;
import _11.asktpk.artisanconnectbackend.service.PaymentService;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
private final OrderService orderService;
private final PaymentService paymentService;
private final Tools tools;
public OrderController(OrderService orderService, PaymentService paymentService, Tools tools) {
this.orderService = orderService;
this.paymentService = paymentService;
this.tools = tools;
}
@PostMapping("/add")
public ResponseEntity<?> addClient(@RequestBody OrderDTO orderDTO, HttpServletRequest request) {
orderDTO.setClientId(tools.getClientIdFromRequest(request));
return ResponseEntity.status(HttpStatus.CREATED).body(orderService.addOrder(orderDTO));
}
@PutMapping("/changeStatus")
public ResponseEntity<?> changeStatus(@RequestBody OrderStatusDTO orderStatusDTO) {
return ResponseEntity.status(HttpStatus.OK).body(orderService.changeOrderStatus(orderStatusDTO.getId(), orderStatusDTO.getStatus()));
}
@PostMapping("/token")
public ResponseEntity<?> fetchToken(@RequestParam Long orderId) {
Order order = orderService.getOrderById(orderId);
Client client = order.getClient();
OAuthPaymentResponseDTO authPaymentDTO = paymentService.getOAuthToken();
TransactionPaymentRequestDTO.Payer payer = new TransactionPaymentRequestDTO.Payer(
client.getEmail(), client.getFirstName()+' '+client.getLastName());
String paymentDescription = order.getOrderType() == Enums.OrderType.ACTIVATION ? "Aktywacja ogłoszenia" : "Podbicie ogłoszenia";
paymentDescription += order.getNotice().getTitle();
TransactionPaymentRequestDTO.Callbacks callbacks = new TransactionPaymentRequestDTO.Callbacks();
TransactionPaymentRequestDTO.PayerUrls payerUrls = new TransactionPaymentRequestDTO.PayerUrls();
payerUrls.setSuccess("com.hamx.artisanconnect://dashboard/userNotices");
payerUrls.setError("com.hamx.artisanconnect://dashboard/userNotices");
callbacks.setPayerUrls(payerUrls);
TransactionPaymentRequestDTO paymentRequest = new TransactionPaymentRequestDTO(
order.getAmount(), paymentDescription, payer, callbacks);
String response = paymentService.createTransaction(order, authPaymentDTO.getAccess_token(), paymentRequest);
return ResponseEntity.status(HttpStatus.OK).body(response);
}
@GetMapping("/get/all")
public ResponseEntity<List<OrderWithPaymentsDTO>> getOrders(HttpServletRequest request) {
Long clientId = tools.getClientIdFromRequest(request);
List<Order> orders = orderService.getOrdersByClientId(clientId);
List<OrderWithPaymentsDTO> dtoList = orders.stream().map(order -> {
OrderWithPaymentsDTO dto = new OrderWithPaymentsDTO();
dto.setOrderId(order.getId());
dto.setOrderType(order.getOrderType().name());
dto.setStatus(order.getStatus().name());
dto.setAmount(order.getAmount());
dto.setCreatedAt(order.getCreatedAt());
List<Payment> payments = paymentService.getPaymentsByOrderId(order.getId());
List<PaymentDTO> paymentDTOs = payments.stream().map(payment -> {
PaymentDTO pDto = new PaymentDTO();
pDto.setPaymentId(payment.getIdPayment());
pDto.setAmount(payment.getAmount());
pDto.setStatus(payment.getStatus().name());
pDto.setTransactionPaymentUrl(payment.getTransactionPaymentUrl());
pDto.setTransactionId(payment.getTransactionId());
return pDto;
}).toList();
dto.setPayments(paymentDTOs);
return dto;
}).toList();
return ResponseEntity.ok(dtoList);
}
@GetMapping("/get/{orderId}")
public ResponseEntity<OrderWithPaymentsDTO> getOrderById(HttpServletRequest request,
@PathVariable Long orderId) {
Long clientId = tools.getClientIdFromRequest(request);
Order order = orderService.getOrderById(orderId);
if (!order.getClient().getId().equals(clientId)) {
return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
}
OrderWithPaymentsDTO dto = new OrderWithPaymentsDTO();
dto.setOrderId(order.getId());
dto.setOrderType(order.getOrderType().name());
dto.setStatus(order.getStatus().name());
dto.setAmount(order.getAmount());
dto.setCreatedAt(order.getCreatedAt());
List<Payment> payments = paymentService.getPaymentsByOrderId(order.getId());
List<PaymentDTO> paymentDTOs = payments.stream().map(payment -> {
PaymentDTO pDto = new PaymentDTO();
pDto.setPaymentId(payment.getIdPayment());
pDto.setAmount(payment.getAmount());
pDto.setStatus(payment.getStatus().name());
pDto.setTransactionPaymentUrl(payment.getTransactionPaymentUrl());
pDto.setTransactionId(payment.getTransactionId());
return pDto;
}).toList();
dto.setPayments(paymentDTOs);
return ResponseEntity.ok(dto);
}
}

View File

@@ -0,0 +1,93 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.entities.Order;
import _11.asktpk.artisanconnectbackend.entities.Payment;
import _11.asktpk.artisanconnectbackend.repository.PaymentRepository;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import org.springframework.beans.factory.annotation.Value;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/v1/payments")
public class PaymentController {
@Value("${tpay.securityCode}")
private String sellerSecurityCode;
private static final Logger log = LoggerFactory.getLogger(PaymentController.class);
private final PaymentRepository paymentRepository;
public PaymentController(PaymentRepository paymentRepository) {
this.paymentRepository = paymentRepository;
}
@PostMapping(value = "/notification", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
public ResponseEntity<String> handleTpayNotification(@RequestParam Map<String, String> params) {
String id = params.get("id");
String trId = params.get("tr_id");
String trAmount = params.get("tr_amount");
String trCrc = params.get("tr_crc");
String md5sum = params.get("md5sum");
String trStatus = params.get("tr_status");
String expectedMd5 = DigestUtils.md5DigestAsHex(
(id + trId + trAmount + trCrc + sellerSecurityCode).getBytes()
);
if (!expectedMd5.equals(md5sum)) {
return ResponseEntity.status(400).body("INVALID CHECKSUM");
}
Optional<Payment> optionalPayment = paymentRepository.findByTransactionId(trId);
if (optionalPayment.isPresent()) {
Payment payment = optionalPayment.get();
if ("true".equalsIgnoreCase(trStatus) || "PAID".equalsIgnoreCase(trStatus)) {
payment.setStatus(Enums.PaymentStatus.CORRECT);
if (payment.getOrder() != null) {
Order order = payment.getOrder();
order.setStatus(Enums.OrderStatus.COMPLETED);
Notice notice = order.getNotice();
if (order.getOrderType() == Enums.OrderType.ACTIVATION) {
notice.setStatus(Enums.Status.ACTIVE);
} else if (order.getOrderType() == Enums.OrderType.BOOST) {
notice.setPublishDate(LocalDateTime.now());
}
}
} else if ("false".equalsIgnoreCase(trStatus)) {
payment.setStatus(Enums.PaymentStatus.INCORRECT);
if (payment.getOrder() != null) {
payment.getOrder().setStatus(Enums.OrderStatus.CANCELLED);
}
}
paymentRepository.save(payment);
}
return ResponseEntity.ok("TRUE");
}
private String paramsToLogString(Map<String, String> params) {
return params.entrySet().stream()
.map(e -> e.getKey() + " = " + e.getValue())
.collect(Collectors.joining("\n"));
}
}

View File

@@ -0,0 +1,33 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.dto.CategoriesDTO;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/v1/vars")
public class VariablesController {
@GetMapping("/categories")
public List<CategoriesDTO> getAllVariables() {
List<CategoriesDTO> categoriesDTOList = new ArrayList<>();
for (Map.Entry<Enums.Category, String> entry : Enums.categoryPL.entrySet()) {
CategoriesDTO categoriesDTO = new CategoriesDTO();
categoriesDTO.setLabel(entry.getValue());
categoriesDTO.setValue(entry.getKey().toString());
categoriesDTOList.add(categoriesDTO);
}
return categoriesDTOList;
}
@GetMapping("/statuses")
public List<Enums.Status> getAllStatuses() {
return List.of(Enums.Status.values());
}
}

View File

@@ -0,0 +1,62 @@
package _11.asktpk.artisanconnectbackend.controller;
import _11.asktpk.artisanconnectbackend.dto.NoticeResponseDTO;
import _11.asktpk.artisanconnectbackend.dto.RequestResponseDTO;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import _11.asktpk.artisanconnectbackend.service.WishlistService;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
@Slf4j
@RestController
@RequestMapping("/api/v1/wishlist")
public class WishlistController {
private final WishlistService wishlistService;
private final ClientService clientService;
private final NoticeService noticeService;
private final Tools tools;
public WishlistController(WishlistService wishlistService, ClientService clientService, NoticeService noticeService, Tools tools) {
this.wishlistService = wishlistService;
this.clientService = clientService;
this.noticeService = noticeService;
this.tools = tools;
}
@PostMapping("/toggle/{noticeId}")
public ResponseEntity<RequestResponseDTO> toggleWishlist(@PathVariable Long noticeId, HttpServletRequest request) {
Long clientId = tools.getClientIdFromRequest(request);
NoticeResponseDTO noticeResponseDTO = noticeService.getNoticeById(noticeId);
if (noticeResponseDTO == null) {
return ResponseEntity.badRequest().body(new RequestResponseDTO("Notice not found"));
}
boolean added = wishlistService.toggleWishlist(
clientService.getClientById(clientId),
noticeService.getNoticeByIdEntity(noticeId)
);
if (added) {
return ResponseEntity.ok(new RequestResponseDTO("Wishlist entry added"));
} else {
return ResponseEntity.ok(new RequestResponseDTO("Wishlist entry removed"));
}
}
// @GetMapping("/{clientId}")
// public ResponseEntity<List<WishlistDTO>> getWishlist(@PathVariable Long clientId) {
// List<WishlistDTO> wishlist = wishlistService.getWishlistForClientId(clientId);
// return ResponseEntity.ok(wishlist);
// }
@GetMapping("/")
public List<NoticeResponseDTO> getWishlistForClient(HttpServletRequest request) {
Long clientId = tools.getClientIdFromRequest(request);
return wishlistService.getNoticesInWishlist(clientId);
}
}

View File

@@ -0,0 +1,7 @@
package _11.asktpk.artisanconnectbackend.customExceptions;
public class ClientAlreadyExistsException extends Exception {
public ClientAlreadyExistsException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,7 @@
package _11.asktpk.artisanconnectbackend.customExceptions;
public class WrongLoginPasswordException extends Exception {
public WrongLoginPasswordException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,11 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class AttributeDto {
private String name;
private String value;
}

View File

@@ -0,0 +1,10 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class AuthRequestDTO {
private String email;
private String password;
}

View File

@@ -0,0 +1,12 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter @AllArgsConstructor
public class AuthResponseDTO {
private Long user_id;
private String user_role;
private String token;
}

View File

@@ -0,0 +1,16 @@
package _11.asktpk.artisanconnectbackend.dto;
//[
// { "label": "Meble", "value": "Furniture" },
// { "label": "Biżuteria", "value": "Jewelry" },
// { "label": "Ceramika", "value": "Ceramics" }
//]
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class CategoriesDTO {
String label;
String value;
}

View File

@@ -1,14 +1,16 @@
package _11.asktpk.artisanconnectbackend.dto;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import jakarta.validation.constraints.Email;
import _11.asktpk.artisanconnectbackend.utils.Enums.Role;
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
public class ClientDTO {
private Long id;
@@ -18,5 +20,5 @@ public class ClientDTO {
private String firstName;
private String lastName;
private String image;
private Role role;
private String role;
}

View File

@@ -0,0 +1,16 @@
package _11.asktpk.artisanconnectbackend.dto;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class ClientRegistrationDTO {
@Email
@NotBlank
private String email;
private String firstName;
private String lastName;
private String password;
}

View File

@@ -0,0 +1,20 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
@Getter
@Setter
public class EmailDTO {
@Email(message = "Podaj poprawny adres email")
@NotBlank(message = "Adres email nie może być pusty")
private String to;
@NotBlank(message = "Temat nie może być pusty")
private String subject;
@NotBlank(message = "Treść nie może być pusta")
private String body;
}

View File

@@ -0,0 +1,9 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class GoogleAuthRequestDTO {
private String googleToken;
}

View File

@@ -0,0 +1,19 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class NoticeAdditionDTO {
public Long noticeId;
public String message;
public NoticeAdditionDTO(String message) {
this.message = message;
}
public NoticeAdditionDTO(Long noticeId, String message) {
this.noticeId = noticeId;
this.message = message;
}
}

View File

@@ -0,0 +1,9 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class NoticeBoostDTO {
private Long noticeId;
}

View File

@@ -1,51 +0,0 @@
package _11.asktpk.artisanconnectbackend.dto;
import _11.asktpk.artisanconnectbackend.entities.AttributesNotice;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.List;
@Getter @Setter
public class NoticeDTO {
private long noticeId;
private String title;
private Long clientId;
private String description;
private Double price;
private Enums.Category category;
private List<String> images;
private Enums.Status status;
private LocalDateTime publishDate;
private List<AttributesNotice> attributesNotices;
public NoticeDTO() {
}
public NoticeDTO(Long noticeId, String title, Long clientId, String description, Double price,
Enums.Category category, List<String> images, Enums.Status status,
LocalDateTime publishDate, List<AttributesNotice> attributesNotices) {
this.noticeId = noticeId;
this.title = title;
this.clientId = clientId;
this.description = description;
this.price = price;
this.category = category;
this.images = images;
this.status = status;
this.publishDate = publishDate;
this.attributesNotices = attributesNotices;
}
}

View File

@@ -0,0 +1,27 @@
package _11.asktpk.artisanconnectbackend.dto;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Getter @Setter
public class NoticeRequestDTO {
private String title;
private Long clientId;
private String description;
private Double price;
private Enums.Category category;
private Enums.Status status;
private List<AttributeDto> attributes;
public NoticeRequestDTO() {
}
}

View File

@@ -0,0 +1,33 @@
package _11.asktpk.artisanconnectbackend.dto;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.List;
@Getter @Setter
public class NoticeResponseDTO {
private long noticeId;
private String title;
private Long clientId;
private String description;
private Double price;
private Enums.Category category;
private Enums.Status status;
private LocalDateTime publishDate;
private List<AttributeDto> attributes;
public NoticeResponseDTO() {
}
}

View File

@@ -0,0 +1,15 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class OAuthPaymentResponseDTO {
private long issued_at;
private String scope;
private String token_type;
private int expires_in;
private String client_id;
private String access_token;
}

View File

@@ -0,0 +1,13 @@
package _11.asktpk.artisanconnectbackend.dto;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class OrderDTO {
private Long clientId;
private Long noticeId;
private Enums.OrderType orderType;
}

View File

@@ -0,0 +1,12 @@
package _11.asktpk.artisanconnectbackend.dto;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class OrderStatusDTO {
public long id;
public Enums.OrderStatus status;
}

View File

@@ -0,0 +1,17 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.List;
@Getter @Setter
public class OrderWithPaymentsDTO {
private Long orderId;
private String orderType;
private String status;
private Double amount;
private LocalDateTime createdAt;
private List<PaymentDTO> payments;
}

View File

@@ -0,0 +1,34 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class PaymentDTO {
private Long paymentId;
private Double amount;
private String status;
private String transactionPaymentUrl;
private String transactionId;
public void setPaymentId(Long paymentId) {
this.paymentId = paymentId;
}
public void setAmount(Double amount) {
this.amount = amount;
}
public void setStatus(String status) {
this.status = status;
}
public void setTransactionPaymentUrl(String transactionPaymentUrl) {
this.transactionPaymentUrl = transactionPaymentUrl;
}
public void setTransactionId(String transactionId) {
this.transactionId = transactionId;
}
}

View File

@@ -0,0 +1,17 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter @Setter
public class RequestResponseDTO {
public String message;
public RequestResponseDTO(String message) {
this.message = message;
}
public String toJSON() {
return "{\"message\":\"" + message + "\"}";
}
}

View File

@@ -0,0 +1,41 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.*;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class TransactionPaymentRequestDTO {
private double amount;
private String description;
private Payer payer;
private Callbacks callbacks;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class Payer {
private String email;
private String name;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class Callbacks {
private PayerUrls payerUrls;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class PayerUrls {
private String success;
private String error;
}
}

View File

@@ -0,0 +1,80 @@
package _11.asktpk.artisanconnectbackend.dto;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public class TransactionPaymentResponseDTO {
private String result;
private String requestId;
private String transactionId;
private String title;
private String posId;
private String status;
private DateInfo date;
private double amount;
private String currency;
private String description;
private String hiddenDescription;
private Payer payer;
private Payments payments;
private String transactionPaymentUrl;
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public static class DateInfo {
private String creation;
private String realization;
}
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Payer {
private String payerId;
private String email;
private String name;
private String phone;
private String address;
private String city;
private String country;
private String postalCode;
}
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true)
public static class Payments {
private String status;
private String method;
private double amountPaid;
private DateInfo date;
}
@Override
public String toString() {
return "YourClassName{" +
"result='" + result + '\'' +
", requestId='" + requestId + '\'' +
", transactionId='" + transactionId + '\'' +
", title='" + title + '\'' +
", posId='" + posId + '\'' +
", status='" + status + '\'' +
", date=" + date +
", amount=" + amount +
", currency='" + currency + '\'' +
", description='" + description + '\'' +
", hiddenDescription='" + hiddenDescription + '\'' +
", payer=" + payer +
", payments=" + payments +
", transactionPaymentUrl='" + transactionPaymentUrl + '\'' +
'}';
}
}

View File

@@ -0,0 +1,12 @@
package _11.asktpk.artisanconnectbackend.dto;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class WishlistDTO {
private Long id;
private Long clientId;
private Long noticeId;
}

View File

@@ -1,9 +1,12 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "attribute_values")
@Getter @Setter
public class AttributeValues {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -14,6 +17,4 @@ public class AttributeValues {
private Attributes attribute;
private String value;
// Getters, setters, and constructors
}

View File

@@ -1,10 +1,14 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.*;
import lombok.Setter;
import lombok.Getter;
import java.util.List;
@Entity
@Table(name = "attributes")
@Getter @Setter
public class Attributes {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -12,8 +16,6 @@ public class Attributes {
private String name;
@OneToMany(mappedBy = "attribute", cascade = CascadeType.ALL)
@OneToMany(mappedBy = "attribute")
private List<AttributeValues> attributeValues;
// Getters, setters, and constructors
}

View File

@@ -1,21 +1,20 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.*;
import lombok.Setter;
import lombok.Getter;
@Entity
@Table(name = "attributes_notice")
@Getter @Setter
public class AttributesNotice {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "id_notice")
private Notice notice;
private Long notice_id;
@ManyToOne
@JoinColumn(name = "id_value")
private AttributeValues attributeValue;
// Getters, setters, and constructors
}

View File

@@ -1,17 +1,26 @@
package _11.asktpk.artisanconnectbackend.entities;
import _11.asktpk.artisanconnectbackend.utils.Enums.Role;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.CreationTimestamp;
import java.util.Date;
import java.util.List;
@Entity
@Table(name = "clients")
@Getter @Setter
@NoArgsConstructor
public class Client {
public Client(String email, String password, String firstName, String lastName) {
this.email = email;
this.password = password;
this.firstName = firstName;
this.lastName = lastName;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@@ -24,14 +33,15 @@ public class Client {
private String lastName;
private String image; // Optional field
private String image;
@Enumerated(EnumType.STRING)
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "role_id", referencedColumnName = "id")
private Role role;
// @OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
// private List<Notice> notices;
@OneToMany(mappedBy = "client", cascade = CascadeType.ALL)
private List<Orders> orders;
private List<Order> orders;
@CreationTimestamp
private Date createdAt;
}

View File

@@ -1,16 +0,0 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.*;
@Entity
@Table(name = "global_variables")
public class GlobalVariables {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String value;
// Getters, setters, and constructors
}

View File

@@ -0,0 +1,23 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.*;
import jdk.jfr.BooleanFlag;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "images")
@Getter @Setter
public class Image {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long noticeId;
private String imageName;
@BooleanFlag
private boolean isMainImage;
}

View File

@@ -30,20 +30,17 @@ public class Notice {
@Enumerated(EnumType.STRING)
private Category category;
@ElementCollection
private List<String> images;
@Enumerated(EnumType.STRING)
private Status status;
private LocalDateTime publishDate;
@OneToMany(mappedBy = "notice", cascade = CascadeType.ALL)
@OneToMany(mappedBy = "notice_id")
private List<AttributesNotice> attributesNotices;
@OneToMany(mappedBy = "notice", cascade = CascadeType.ALL)
private List<Orders> orders;
@OneToMany(mappedBy = "notice")
private List<Order> orders;
@OneToMany(mappedBy = "notice", cascade = CascadeType.ALL)
private List<Payments> payments;
// @OneToMany(mappedBy = "notice", cascade = CascadeType.ALL)
// private List<Payment> payment;
}

View File

@@ -0,0 +1,43 @@
package _11.asktpk.artisanconnectbackend.entities;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
@Entity
@Table(name = "orders")
@Getter
@Setter
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "id_client")
private Client client;
@ManyToOne
@JoinColumn(name = "id_notice")
private Notice notice;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Enums.OrderType orderType;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Enums.OrderStatus status;
@Column(nullable = false)
private Double amount;
@Column(nullable = false)
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}

View File

@@ -1,26 +0,0 @@
package _11.asktpk.artisanconnectbackend.entities;
import _11.asktpk.artisanconnectbackend.utils.Enums.Status;
import jakarta.persistence.*;
@Entity
@Table(name = "orders")
public class Orders {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idOrder;
@ManyToOne
@JoinColumn(name = "id_user")
private Client client;
@ManyToOne
@JoinColumn(name = "id_notice")
private Notice notice;
@Enumerated(EnumType.STRING)
private Status status;
// Getters, setters, and constructors
}

View File

@@ -0,0 +1,30 @@
package _11.asktpk.artisanconnectbackend.entities;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "payment")
@Getter @Setter
public class Payment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idPayment;
@ManyToOne
@JoinColumn(name = "id_order")
private Order order;
private Double amount;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private Enums.PaymentStatus status;
private String transactionPaymentUrl;
private String transactionId;
}

View File

@@ -1,30 +0,0 @@
package _11.asktpk.artisanconnectbackend.entities;
import _11.asktpk.artisanconnectbackend.utils.Enums.Status;
import jakarta.persistence.*;
@Entity
@Table(name = "payments")
public class Payments {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long idPayment;
@ManyToOne
@JoinColumn(name = "id_order")
private Orders order;
@ManyToOne
@JoinColumn(name = "id_notice")
private Notice notice;
private Double noticePublishPrice;
@Enumerated(EnumType.STRING)
private Status status;
private String sessionId;
// Getters, setters, and constructors
}

View File

@@ -0,0 +1,19 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "roles")
@Getter
@Setter
public class Role {
@Id
private Long id;
@Column(name="rolename")
private String role;
}

View File

@@ -0,0 +1,24 @@
package _11.asktpk.artisanconnectbackend.entities;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Table(name = "wishlist")
@Getter
@Setter
public class Wishlist {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "client_id", nullable = false)
private Client client;
@ManyToOne
@JoinColumn(name = "notice_id", nullable = false)
private Notice notice;
}

View File

@@ -0,0 +1,14 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.AttributeValues;
import _11.asktpk.artisanconnectbackend.entities.Attributes;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface AttributeValuesRepository extends JpaRepository<AttributeValues, Long> {
Optional<AttributeValues> findByAttributeAndValue(Attributes attribute, String value);
}

View File

@@ -0,0 +1,9 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.AttributesNotice;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface AttributesNoticeRepository extends JpaRepository<AttributesNotice, Long> {
}

View File

@@ -0,0 +1,12 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Attributes;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface AttributesRepository extends JpaRepository<Attributes, Long> {
Optional<Attributes> findByName(String name);
}

View File

@@ -1,8 +1,8 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Client;
import org.springframework.data.jpa.repository.JpaRepository;
public interface ClientRepository extends JpaRepository<Client, Long> {
Client findByEmail(String email);
}

View File

@@ -0,0 +1,14 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Image;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
public interface ImageRepository extends JpaRepository<Image, Long> {
List<Image> findByNoticeId(Long noticeId);
boolean existsImageByImageNameEqualsIgnoreCase(String imageName);
void deleteByImageNameEquals(String imageName);
}

View File

@@ -1,8 +1,9 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import org.springframework.data.jpa.repository.JpaRepository;
public interface NoticeRepository extends JpaRepository<Notice, Long> {
}
boolean existsByIdNoticeAndClientId(long noticeId, long clientId);
}

View File

@@ -0,0 +1,13 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
List<Order> findByClientId(Long clientId);
}

View File

@@ -0,0 +1,15 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Payment;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface PaymentRepository extends JpaRepository<Payment, Long> {
Optional<Payment> findByTransactionId(String transactionId);
List<Payment> findAllByOrderId(Long id);
}

View File

@@ -0,0 +1,12 @@
package _11.asktpk.artisanconnectbackend.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import _11.asktpk.artisanconnectbackend.entities.Role;
@Repository
public interface RolesRepository extends JpaRepository<Role, String> {
Role findRoleById(Long id);
Role findRoleByRole(String role);
}

View File

@@ -0,0 +1,16 @@
package _11.asktpk.artisanconnectbackend.repository;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.entities.Wishlist;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.List;
import java.util.Optional;
public interface WishlistRepository extends JpaRepository<Wishlist, Long> {
List<Wishlist> findAllByClientId(Long clientId);
Optional<Wishlist> findByClientAndNotice(Client client, Notice notice);
}

View File

@@ -0,0 +1,80 @@
package _11.asktpk.artisanconnectbackend.security;
import _11.asktpk.artisanconnectbackend.dto.RequestResponseDTO;
import io.jsonwebtoken.ExpiredJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jetbrains.annotations.NotNull;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Collections;
@Component
public class JwtRequestFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
public JwtRequestFilter(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
@Override
protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String email = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
try {
if (jwtUtil.isBlacklisted(jwt) || !jwtUtil.isLatestToken(jwt)) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
String jsonResponse = "{\"error\": \"Token is invalid. Please login again.\"}";
response.getWriter().write(jsonResponse);
return;
}
email = jwtUtil.extractEmail(jwt);
} catch (ExpiredJwtException expiredJwtException) {
logger.error(expiredJwtException.getMessage());
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write(new RequestResponseDTO("Authentication token is expired. Please login again.").toJSON());
return;
} catch (Exception e) {
logger.error(e.getMessage());
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
response.getWriter().write(new RequestResponseDTO(e.getMessage()).toJSON());
return;
}
}
if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) {
String role = jwtUtil.extractRole(jwt);
UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
email, null, Collections.singletonList(new SimpleGrantedAuthority("ROLE_" + role)));
authToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authToken);
}
// logger.info("Token of user " + jwtUtil.extractEmail(jwt) + (jwtUtil.isTokenExpired(jwt) ? " is expired" : " is not expired"));
chain.doFilter(request, response);
}
}

View File

@@ -0,0 +1,101 @@
package _11.asktpk.artisanconnectbackend.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.crypto.SecretKey;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
@Component
public class JwtUtil {
@Value("${jwt.secret:defaultSecretKeyNeedsToBeAtLeast32BytesLong}")
private String secret;
@Value("${jwt.expiration}")
private long expiration;
// sterowanie tokenami wygasnietymi
private final Set<String> blacklistedTokens = ConcurrentHashMap.newKeySet();
public void blacklistToken(String token) {
blacklistedTokens.add(token);
}
public boolean isBlacklisted(String token) {
return blacklistedTokens.contains(token);
}
private SecretKey getSigningKey() {
return Keys.hmacShaKeyFor(secret.getBytes());
}
private final Map<String, String> userActiveTokens = new ConcurrentHashMap<>();
public boolean isLatestToken(String token) {
String email = extractEmail(token);
String tokenId = extractTokenId(token);
String latestTokenId = userActiveTokens.get(email);
return latestTokenId != null && latestTokenId.equals(tokenId);
}
public String generateToken(String email, String role, Long userId) {
Map<String, Object> claims = new HashMap<>();
claims.put("role", role);
claims.put("userId", userId);
claims.put("tokenId", UUID.randomUUID().toString());
String token = createToken(claims, email);
userActiveTokens.put(email, extractTokenId(token));
return token;
}
private String createToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date())
.setExpiration(new Date(System.currentTimeMillis() + expiration))
.signWith(getSigningKey(), SignatureAlgorithm.HS256)
.compact();
}
public String extractTokenId(String token) {
return extractAllClaims(token).get("tokenId", String.class);
}
public String extractEmail(String token) {
return extractClaim(token, Claims::getSubject);
}
public String extractRole(String token) {
return extractAllClaims(token).get("role", String.class);
}
public Long extractUserId(String token) {
return extractAllClaims(token).get("userId", Long.class);
}
public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
private Claims extractAllClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(getSigningKey())
.build()
.parseClaimsJws(token)
.getBody();
}
}

View File

@@ -0,0 +1,116 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.customExceptions.ClientAlreadyExistsException;
import _11.asktpk.artisanconnectbackend.customExceptions.WrongLoginPasswordException;
import _11.asktpk.artisanconnectbackend.dto.AuthResponseDTO;
import _11.asktpk.artisanconnectbackend.dto.ClientDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
import org.springframework.http.*;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
@Slf4j
@Service
public class AuthService {
private final ClientService clientService;
private final PasswordEncoder passwordEncoder;
private final JwtUtil jwtUtil;
public AuthService(ClientService clientService, JwtUtil jwtUtil, PasswordEncoder passwordEncoder) {
this.clientService = clientService;
this.jwtUtil = jwtUtil;
this.passwordEncoder = passwordEncoder;
}
public AuthResponseDTO login(String email, String password) throws Exception {
Client client = clientService.getClientByEmail(email);
if (client == null) {
throw new Exception("Klient o podanym adresie nie istnieje!");
}
if (passwordEncoder.matches(password, client.getPassword())) {
String token = jwtUtil.generateToken(client.getEmail(), client.getRole().getRole(), client.getId());
log.info("User logged in with {}", client.getEmail());
return new AuthResponseDTO(client.getId(), client.getRole().getRole(), token);
}
throw new WrongLoginPasswordException("Login lub hasło jest niepoprawny!");
}
public AuthResponseDTO register(String email, String password, String firstName, String lastName) throws Exception {
if (clientService.getClientByEmail(email) != null) {
throw new ClientAlreadyExistsException("Klient o podanym adresie email już istnieje!");
}
Client newClient = new Client();
newClient.setEmail(email);
newClient.setPassword(passwordEncoder.encode(password));
newClient.setFirstName(firstName);
newClient.setLastName(lastName);
ClientDTO savedClient = clientService.registerClient(newClient);
if (savedClient != null) {
log.info("New user registered with {}", savedClient.getEmail());
String token = jwtUtil.generateToken(
savedClient.getEmail(),
savedClient.getRole(),
savedClient.getId()
);
return new AuthResponseDTO(savedClient.getId(), savedClient.getRole(), token);
} else {
throw new Exception("Rejestracja nie powiodła się!");
}
}
public void logout(String token) {
jwtUtil.blacklistToken(token);
}
public AuthResponseDTO googleLogin(String googleAccessToken) throws Exception {
String googleUserInfoUrl = "https://www.googleapis.com/oauth2/v3/userinfo";
ResponseEntity<Map> response;
HttpHeaders headers = new HttpHeaders();
headers.setBearerAuth(googleAccessToken);
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(
googleUserInfoUrl, HttpMethod.GET, new HttpEntity<>(headers), Map.class);
Map<String, Object> userInfo = response.getBody();
// String googleId = (String) userInfo.get("sub"); Potencjalnie możemy używać googlowskiego ID, ale to ma konflikt z naszym generowanym
if (userInfo == null) {
throw new Exception("Pobrany użytkownik jest pusty! Może to być spowodowane niepoprawnym tokenem lub brakiem dostępu do Google API.");
}
String email = (String) userInfo.get("email");
String name = (String) userInfo.get("name");
Client client = clientService.getClientByEmail(email);
if (client == null) {
client = new Client();
client.setEmail(email);
client.setFirstName(name);
client.setRole(clientService.getUserRole()); // to pobiera po prostu role "USER" z tabeli w bazie
clientService.saveClientToDB(client);
}
String jwt = jwtUtil.generateToken(client.getEmail(), client.getRole().getRole(), client.getId());
log.info("User authenticated with google: {}", client.getEmail());
return new AuthResponseDTO(
client.getId(),
client.getRole().getRole(),
jwt
);
}
}

View File

@@ -1,8 +1,11 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.dto.ClientDTO;
import _11.asktpk.artisanconnectbackend.dto.ClientRegistrationDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Role;
import _11.asktpk.artisanconnectbackend.repository.ClientRepository;
import _11.asktpk.artisanconnectbackend.repository.RolesRepository;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.stereotype.Service;
@@ -11,37 +14,61 @@ import java.util.List;
@Service
public class ClientService {
private final ClientRepository clientRepository;
private final RolesRepository rolesRepository;
public ClientService(ClientRepository clientRepository) {
public ClientService(ClientRepository clientRepository, RolesRepository rolesRepository) {
this.clientRepository = clientRepository;
this.rolesRepository = rolesRepository;
}
private ClientDTO toDto(Client client) {
public ClientDTO toDto(Client client) {
if(client == null) {
return null;
}
ClientDTO dto = new ClientDTO();
dto.setId(client.getId());
dto.setFirstName(client.getFirstName());
dto.setLastName(client.getLastName());
dto.setEmail(client.getEmail());
dto.setRole(client.getRole());
dto.setRole(client.getRole().getRole());
dto.setImage(client.getImage());
return dto;
}
private Client fromDto(ClientDTO dto) {
public Client fromDto(ClientDTO dto) {
Client client = new Client();
Role rola;
if (clientRepository.findById(dto.getId()).isPresent()) {
rola = clientRepository.findById(dto.getId()).get().getRole();
} else {
rola = new Role();
rola.setRole("USER");
}
client.setId(dto.getId());
client.setFirstName(dto.getFirstName());
client.setLastName(dto.getLastName());
client.setEmail(dto.getEmail());
client.setRole(dto.getRole());
client.setRole(rola);
client.setImage(dto.getImage());
return client;
}
private Client fromDto(ClientRegistrationDTO dto) {
Client client = new Client();
client.setFirstName(dto.getFirstName());
client.setLastName(dto.getLastName());
client.setEmail(dto.getEmail());
client.setPassword(dto.getPassword());
return client;
}
public List<ClientDTO> getAllClients() {
List<Client> clients = clientRepository.findAll();
return clients.stream().map(this::toDto).toList();
@@ -51,6 +78,18 @@ public class ClientService {
return clientRepository.findById(id).orElse(null);
}
public ClientDTO getClientByIdDTO(Long id) {
return toDto(clientRepository.findById(id).orElse(null));
}
public Client getClientByEmail(String email) {
return clientRepository.findByEmail(email);
}
public Role getUserRole() {
return rolesRepository.findRoleByRole("USER");
}
public boolean clientExists(Long id) {
return clientRepository.existsById(id);
}
@@ -59,15 +98,21 @@ public class ClientService {
return toDto(clientRepository.save(fromDto(clientDTO)));
}
public Client saveClientToDB(Client client) {
return clientRepository.save(client);
}
public ClientDTO updateClient(long id, ClientDTO clientDTO) {
Client existingClient = clientRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id));
Role newRole = rolesRepository.findRoleByRole(clientDTO.getRole());
existingClient.setEmail(clientDTO.getEmail());
existingClient.setFirstName(clientDTO.getFirstName());
existingClient.setLastName(clientDTO.getLastName());
existingClient.setImage(clientDTO.getImage());
existingClient.setRole(clientDTO.getRole());
existingClient.setRole(newRole);
return toDto(clientRepository.save(existingClient));
}
@@ -75,4 +120,9 @@ public class ClientService {
public void deleteClient(Long id) {
clientRepository.deleteById(id);
}
public ClientDTO registerClient(Client client) {
client.setRole(getUserRole()); // ID 1 - USER role
return toDto(clientRepository.save(client));
}
}

View File

@@ -0,0 +1,24 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.dto.EmailDTO;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
@Service
public class EmailService {
private final JavaMailSender mailSender;
public EmailService(JavaMailSender mailSender) {
this.mailSender = mailSender;
}
public void sendEmail(EmailDTO email) {
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom("noreply@zikor.pl");
message.setTo(email.getTo());
message.setSubject(email.getSubject());
message.setText(email.getBody());
mailSender.send(message);
}
}

View File

@@ -0,0 +1,94 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.entities.Image;
import _11.asktpk.artisanconnectbackend.repository.ImageRepository;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@Service
@Transactional
public class ImageService {
private final ImageRepository imageRepository;
ImageService(ImageRepository imageRepository) {
this.imageRepository = imageRepository;
}
public String saveImageToStorage(String uploadDirectory, MultipartFile imageFile) throws IOException {
String uniqueFileName = UUID.randomUUID() + imageFile.getOriginalFilename();
Path uploadPath = Path.of(uploadDirectory);
Path filePath = uploadPath.resolve(uniqueFileName);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
Files.copy(imageFile.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
return uniqueFileName;
}
public void addImageNameToDB(String filename, Long noticeId, boolean isMainImage) {
Image image = new Image();
image.setImageName(filename);
image.setNoticeId(noticeId);
image.setMainImage(isMainImage);
imageRepository.save(image);
}
public Resource getImage(String imageDirectory, String imageName) throws IOException {
Path filePath = Paths.get(imageDirectory).resolve(imageName);
Resource resource = new UrlResource(filePath.toUri());
if(imageName.isEmpty() || imageDirectory.isEmpty()) {
throw new IOException("Filename or folder is empty. Please check your request and try again.");
}
if (!resource.exists()) {
throw new IOException("File not found");
}
return resource;
}
public void deleteImage(String imageDirectory, String imageName) throws IOException {
Path imagePath = Path.of(imageDirectory, imageName);
deleteImageRecordFromDB(imageName);
if (Files.exists(imagePath)) {
Files.delete(imagePath);
} else {
throw new IOException("File not found");
}
}
public List<String> getImagesList(Long noticeID) throws Exception {
List<Image> images = imageRepository.findByNoticeId(noticeID);
if (images.isEmpty()) {
throw new Exception("There is no images for this notice");
}
return images.stream()
.map(Image::getImageName)
.collect(Collectors.toList());
}
public void deleteImageRecordFromDB(String imageName) {
if(imageRepository.existsImageByImageNameEqualsIgnoreCase(imageName)) {
imageRepository.deleteByImageNameEquals(imageName);
}
}
}

View File

@@ -1,43 +1,55 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.repository.ClientRepository;
import _11.asktpk.artisanconnectbackend.repository.NoticeRepository;
import _11.asktpk.artisanconnectbackend.dto.NoticeDTO;
import _11.asktpk.artisanconnectbackend.dto.AttributeDto;
import _11.asktpk.artisanconnectbackend.dto.NoticeRequestDTO;
import _11.asktpk.artisanconnectbackend.entities.*;
import _11.asktpk.artisanconnectbackend.repository.*;
import _11.asktpk.artisanconnectbackend.dto.NoticeResponseDTO;
import jakarta.persistence.EntityNotFoundException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Service
public class NoticeService {
private static final Logger logger = LogManager.getLogger(NoticeService.class);
@Value("${file.upload-dir}")
private String uploadDir;
private final NoticeRepository noticeRepository;
private final ClientRepository clientRepository;
private final ImageService imageService;
private final AttributesRepository attributesRepository;
private final AttributeValuesRepository attributeValuesRepository;
private final AttributesNoticeRepository attributesNoticeRepository;
public NoticeService(NoticeRepository noticeRepository, ClientRepository clientRepository) {
public NoticeService(NoticeRepository noticeRepository,
ClientRepository clientRepository,
ImageService imageService,
AttributesRepository attributesRepository,
AttributeValuesRepository attributeValuesRepository,
AttributesNoticeRepository attributesNoticeRepository) {
this.noticeRepository = noticeRepository;
this.clientRepository = clientRepository;
this.imageService = imageService;
this.attributesRepository = attributesRepository;
this.attributeValuesRepository = attributeValuesRepository;
this.attributesNoticeRepository = attributesNoticeRepository;
}
private Notice fromDTO(NoticeDTO dto) {
public Notice fromDTO(NoticeRequestDTO dto) {
Notice notice = new Notice();
notice.setTitle(dto.getTitle());
notice.setDescription(dto.getDescription());
notice.setPrice(dto.getPrice());
notice.setCategory(dto.getCategory());
notice.setImages(dto.getImages());
notice.setStatus(dto.getStatus());
notice.setPublishDate(dto.getPublishDate());
notice.setAttributesNotices(dto.getAttributesNotices());
Client client = clientRepository.findById(dto.getClientId())
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono klienta o ID: " + dto.getClientId()));
@@ -46,45 +58,92 @@ public class NoticeService {
return notice;
}
private NoticeDTO toDTO(Notice notice) {
NoticeDTO dto = new NoticeDTO();
private NoticeResponseDTO toDTO(Notice notice) {
NoticeResponseDTO dto = new NoticeResponseDTO();
dto.setNoticeId(notice.getIdNotice());
dto.setTitle(notice.getTitle());
dto.setClientId(notice.getClient().getId());
dto.setDescription(notice.getDescription());
dto.setPrice(notice.getPrice());
dto.setCategory(notice.getCategory());
dto.setImages(notice.getImages());
dto.setStatus(notice.getStatus());
dto.setPublishDate(notice.getPublishDate());
dto.setAttributesNotices(notice.getAttributesNotices());
List<AttributeDto> attributes = new ArrayList<>();
if (notice.getAttributesNotices() != null) {
for (AttributesNotice an : notice.getAttributesNotices()) {
AttributeDto attr = new AttributeDto();
attr.setName(an.getAttributeValue().getAttribute().getName());
attr.setValue(an.getAttributeValue().getValue());
attributes.add(attr);
}
}
dto.setAttributes(attributes);
return dto;
}
public List<NoticeDTO> getAllNotices() {
List<NoticeDTO> result = new ArrayList<>();
public List<NoticeResponseDTO> getAllNotices() {
List<NoticeResponseDTO> result = new ArrayList<>();
for (Notice notice : noticeRepository.findAll()) {
result.add(toDTO(notice));
}
return result;
}
public NoticeDTO getNoticeById(Long id) {
public NoticeResponseDTO getNoticeById(Long id) {
Notice notice = noticeRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id));
return toDTO(notice);
}
public void addNotice(NoticeDTO dto) {
noticeRepository.save(fromDTO(dto));
public Notice getNoticeByIdEntity(Long id) {
return noticeRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id));
}
public Long addNotice(NoticeRequestDTO dto) {
Notice notice = fromDTO(dto);
notice.setPublishDate(LocalDateTime.now());
Notice savedNotice = noticeRepository.save(notice);
if (dto.getAttributes() != null && !dto.getAttributes().isEmpty()) {
saveAttributes(savedNotice.getIdNotice(), dto.getAttributes());
}
return savedNotice.getIdNotice();
}
private void saveAttributes(Long noticeId, List<AttributeDto> attributeDtos) {
for (AttributeDto attributeDto : attributeDtos) {
Attributes attribute = attributesRepository.findByName(attributeDto.getName())
.orElseGet(() -> {
Attributes newAttribute = new Attributes();
newAttribute.setName(attributeDto.getName());
return attributesRepository.save(newAttribute);
});
AttributeValues attributeValue = attributeValuesRepository
.findByAttributeAndValue(attribute, attributeDto.getValue())
.orElseGet(() -> {
AttributeValues newValue = new AttributeValues();
newValue.setAttribute(attribute);
newValue.setValue(attributeDto.getValue());
return attributeValuesRepository.save(newValue);
});
AttributesNotice attributesNotice = new AttributesNotice();
attributesNotice.setNotice_id(noticeId);
attributesNotice.setAttributeValue(attributeValue);
attributesNoticeRepository.save(attributesNotice);
}
}
public boolean noticeExists(Long id) {
return noticeRepository.existsById(id);
}
public NoticeDTO updateNotice(Long id, NoticeDTO dto) {
public NoticeResponseDTO updateNotice(Long id, NoticeRequestDTO dto) {
Notice existingNotice = noticeRepository.findById(id)
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id));
@@ -92,9 +151,7 @@ public class NoticeService {
existingNotice.setDescription(dto.getDescription());
existingNotice.setPrice(dto.getPrice());
existingNotice.setCategory(dto.getCategory());
existingNotice.setImages(dto.getImages());
existingNotice.setStatus(dto.getStatus());
existingNotice.setAttributesNotices(dto.getAttributesNotices());
if (dto.getClientId() != null && !dto.getClientId().equals(existingNotice.getClient().getId())) {
Client client = clientRepository.findById(dto.getClientId())
@@ -108,55 +165,40 @@ public class NoticeService {
public void deleteNotice(Long id) {
if (noticeExists(id)) {
noticeRepository.deleteById(id);
List<String> imagesList = new ArrayList<>();
try {
imagesList = imageService.getImagesList(id);
} catch (Exception e) {
logger.info("There weren't any images for notice with ID: " + id + ". Skipping deletion of images. Message: " + e.getMessage());
}
try {
for (String imageName : imagesList) {
imageService.deleteImage(uploadDir, imageName);
}
} catch (Exception e) {
logger.info("There were some issues while deleting images for notice with ID: " + id + ". Message: " + e.getMessage());
}
} else {
throw new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + id);
}
}
public String saveImage(Long noticeId, MultipartFile file) throws IOException {
String uploadDir = "src/main/resources/static/images/notices/" + noticeId;
Path uploadPath = Paths.get(uploadDir);
if (!Files.exists(uploadPath)) {
Files.createDirectories(uploadPath);
}
// szukanie nazwy pliku
String fileName = file.getOriginalFilename();
if (fileName != null) {
String extension = fileName.substring(fileName.lastIndexOf('.'));
String baseName = fileName.substring(0, fileName.lastIndexOf('.'));
List<Path> filesInDirectory = Files.list(uploadPath)
.filter(Files::isRegularFile)
.toList();
int maxNumber = filesInDirectory.stream()
.map(path -> path.getFileName().toString())
.filter(name -> name.startsWith(baseName) && name.endsWith(extension))
.map(name -> name.substring(baseName.length(), name.length() - extension.length()))
.filter(number -> number.matches("\\d+"))
.mapToInt(Integer::parseInt)
.max()
.orElse(0);
fileName = baseName + (maxNumber + 1) + extension;
}
//koniec szukania nazwy pliku
if(fileName == null) {
throw new IOException("Nie można znaleźć nazwy pliku");
}
Path filePath = uploadPath.resolve(fileName);
Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
public boolean isNoticeOwnedByClient(long noticeId, long clientId) {
return noticeRepository.existsByIdNoticeAndClientId(noticeId, clientId);
}
public void boostNotice(long noticeId) {
Notice notice = noticeRepository.findById(noticeId)
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + noticeId));
List<String> images = notice.getImages();
images.add(filePath.toString());
notice.setImages(images);
.orElseThrow(() -> new EntityNotFoundException("Ogłoszenie o ID " + noticeId + " nie istnieje."));
notice.setPublishDate(LocalDateTime.now());
noticeRepository.save(notice);
return filePath.toString();
}
}

View File

@@ -0,0 +1,83 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.dto.OrderDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.repository.ClientRepository;
import _11.asktpk.artisanconnectbackend.repository.NoticeRepository;
import _11.asktpk.artisanconnectbackend.repository.OrderRepository;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import jakarta.persistence.EntityNotFoundException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import _11.asktpk.artisanconnectbackend.entities.Order;
import java.time.LocalDateTime;
import java.util.List;
@Service
public class OrderService {
private final OrderRepository orderRepository;
private final ClientRepository clientRepository;
private final NoticeRepository noticeRepository;
@Autowired
public OrderService(OrderRepository orderRepository, ClientRepository clientRepository, NoticeRepository noticeRepository) {
this.orderRepository = orderRepository;
this.clientRepository = clientRepository;
this.noticeRepository = noticeRepository;
}
public Order fromDTO(OrderDTO orderDTO) {
Order order = new Order();
order.setOrderType(orderDTO.getOrderType());
order.setStatus(Enums.OrderStatus.PENDING);
if(orderDTO.getOrderType() == Enums.OrderType.ACTIVATION){
order.setAmount(10.00);
}else{
order.setAmount(8.00);
}
order.setCreatedAt(LocalDateTime.now()
);
order.setUpdatedAt(LocalDateTime.now()
);
Client client = clientRepository.findById(orderDTO.getClientId())
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono klienta o ID: " + orderDTO.getClientId()));
order.setClient(client);
Notice notice = noticeRepository.findById(orderDTO.getNoticeId())
.orElseThrow(() -> new EntityNotFoundException("Nie znaleziono ogłoszenia o ID: " + orderDTO.getNoticeId()));
order.setNotice(notice);
return order;
}
public Long addOrder(OrderDTO orderDTO) {
return orderRepository.save(fromDTO(orderDTO)).getId();
}
public Long changeOrderStatus(Long id, Enums.OrderStatus status) {
Order order = orderRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("Nie znaleziono zamówienia o ID: " + id));
order.setStatus(status);
order = orderRepository.save(order);
return order.getId();
}
public Order getOrderById(Long id) {
return orderRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Nie znaleziono zamówienia o ID: " + id));
}
public List<Order> getOrdersByClientId(Long clientId) {
return orderRepository.findByClientId(clientId);
}
}

View File

@@ -0,0 +1,91 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.dto.OAuthPaymentResponseDTO;
import _11.asktpk.artisanconnectbackend.dto.TransactionPaymentRequestDTO;
import _11.asktpk.artisanconnectbackend.dto.TransactionPaymentResponseDTO;
import _11.asktpk.artisanconnectbackend.entities.Order;
import _11.asktpk.artisanconnectbackend.entities.Payment;
import _11.asktpk.artisanconnectbackend.repository.PaymentRepository;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.util.List;
@Service
public class PaymentService {
private final WebClient webClient;
private final String clientId;
private final String clientSecret;
private final String authUrl;
private final String transactionUrl;
private final PaymentRepository paymentRepository;
public PaymentService(
WebClient.Builder webClientBuilder,
@Value("${tpay.clientId}") String clientId,
@Value("${tpay.clientSecret}") String clientSecret,
@Value("${tpay.authUrl}") String authUrl,
@Value("${tpay.transactionUrl}") String transactionUrl,
PaymentRepository paymentRepository
) {
this.webClient = webClientBuilder.baseUrl(authUrl).build();
this.clientId = clientId;
this.clientSecret = clientSecret;
this.authUrl = authUrl;
this.transactionUrl = transactionUrl;
this.paymentRepository = paymentRepository;
}
public OAuthPaymentResponseDTO getOAuthToken() {
return webClient.post()
.uri("")
.contentType(MediaType.MULTIPART_FORM_DATA)
.header("accept", "application/json")
.body(BodyInserters.fromMultipartData("client_id", clientId)
.with("client_secret", clientSecret))
.retrieve()
.bodyToMono(OAuthPaymentResponseDTO.class)
.block();
}
public String createTransaction(Order order, String accessToken, TransactionPaymentRequestDTO transactionPaymentRequestDTO) {
TransactionPaymentResponseDTO response = webClient.post()
.uri(transactionUrl)
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.contentType(MediaType.APPLICATION_JSON)
.bodyValue(transactionPaymentRequestDTO)
.retrieve()
.bodyToMono(TransactionPaymentResponseDTO.class)
.block();
if (response != null && "success".equalsIgnoreCase(response.getResult())) {
Payment payment = new Payment();
payment.setOrder(order);
payment.setAmount(response.getAmount());
payment.setStatus(Enums.PaymentStatus.PENDING);
payment.setTransactionId(response.getTitle());
payment.setTransactionPaymentUrl(response.getTransactionPaymentUrl());
paymentRepository.save(payment);
System.out.println(response);
return response.getTransactionPaymentUrl();
}
return null;
}
public List<Payment> getPaymentsByOrderId(Long id) {
return paymentRepository.findAllByOrderId(id);
}
}

View File

@@ -0,0 +1,66 @@
package _11.asktpk.artisanconnectbackend.service;
import _11.asktpk.artisanconnectbackend.dto.WishlistDTO;
import _11.asktpk.artisanconnectbackend.dto.NoticeResponseDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.entities.Wishlist;
import _11.asktpk.artisanconnectbackend.repository.WishlistRepository;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
public class WishlistService {
private final WishlistRepository wishlistRepository;
private final NoticeService noticeService;
public WishlistService(WishlistRepository wishlistRepository, @Lazy NoticeService noticeService) {
this.wishlistRepository = wishlistRepository;
this.noticeService = noticeService;
}
public List<WishlistDTO> getWishlistForClientId(Long clientId) {
List<Wishlist> wishlistEntities = wishlistRepository.findAllByClientId(clientId);
return wishlistEntities.stream()
.map(this::toDTO)
.toList();
}
public boolean toggleWishlist(Client client, Notice notice) {
Optional<Wishlist> existingEntry = wishlistRepository.findByClientAndNotice(client, notice);
if (existingEntry.isPresent()) {
wishlistRepository.delete(existingEntry.get());
return false;
} else {
Wishlist wishlist = new Wishlist();
wishlist.setClient(client);
wishlist.setNotice(notice);
wishlistRepository.save(wishlist);
return true;
}
}
private WishlistDTO toDTO(Wishlist wishlist) {
WishlistDTO dto = new WishlistDTO();
dto.setId(wishlist.getId());
dto.setClientId(wishlist.getClient().getId());
dto.setNoticeId(wishlist.getNotice().getIdNotice());
return dto;
}
public List<NoticeResponseDTO> getNoticesInWishlist(Long clientId) {
List<Wishlist> wishlistEntries = wishlistRepository.findAllByClientId(clientId);
return wishlistEntries.stream()
.map(wishlist -> noticeService.getNoticeById(wishlist.getNotice().getIdNotice()))
.collect(Collectors.toList());
}
}

View File

@@ -1,5 +1,7 @@
package _11.asktpk.artisanconnectbackend.utils;
import java.util.Map;
public class Enums {
public enum Role {
ADMIN, USER
@@ -13,7 +15,48 @@ public class Enums {
Knitting, Carpentry, Other
}
public static final Map<Category, String> categoryPL = Map.ofEntries(
Map.entry(Category.Handmade, "Rękodzieło"),
Map.entry(Category.Woodworking, "Stolarstwo"),
Map.entry(Category.Metalworking, "Obróbka metalu"),
Map.entry(Category.Ceramics, "Ceramika"),
Map.entry(Category.Textiles, "Tekstylia"),
Map.entry(Category.Jewelry, "Biżuteria"),
Map.entry(Category.Leatherwork, "Wyroby skórzane"),
Map.entry(Category.Painting, "Malarstwo"),
Map.entry(Category.Sculpture, "Rzeźbiarstwo"),
Map.entry(Category.Glasswork, "Szklarstwo"),
Map.entry(Category.Furniture, "Meble"),
Map.entry(Category.Restoration, "Renowacja"),
Map.entry(Category.Tailoring, "Krawiectwo"),
Map.entry(Category.Weaving, "Tkactwo"),
Map.entry(Category.Calligraphy, "Kaligrafia"),
Map.entry(Category.Pottery, "Garncarstwo"),
Map.entry(Category.Blacksmithing, "Kowalstwo"),
Map.entry(Category.Basketry, "Koszykarstwo"),
Map.entry(Category.Embroidery, "Hafciarstwo"),
Map.entry(Category.Knitting, "Dzierganie"),
Map.entry(Category.Carpentry, "Ciesielstwo"),
Map.entry(Category.Other, "Inne")
);
public enum Status {
ACTIVE, INACTIVE
}
public enum OrderType {
ACTIVATION,
BOOST
}
public enum OrderStatus {
PENDING, COMPLETED, CANCELLED
}
public enum PaymentStatus{
PENDING, CORRECT, INCORRECT
}
}

View File

@@ -0,0 +1,24 @@
package _11.asktpk.artisanconnectbackend.utils;
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
@Component
public class Tools {
private final JwtUtil jwtUtil;
public Tools(JwtUtil jwtUtil) {
this.jwtUtil = jwtUtil;
}
public Long getClientIdFromRequest(HttpServletRequest request) {
String authorizationHeader = request.getHeader("Authorization");
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
return jwtUtil.extractUserId(authorizationHeader.substring(7));
} else {
return -1L;
}
}
}

View File

@@ -1,15 +1,33 @@
spring.application.name=ArtisanConnectBackend
## PostgreSQL
spring.datasource.url=jdbc:postgresql://localhost:5432/postgres
spring.datasource.username=postgres
spring.datasource.password=postgres
spring.datasource.url=${DB_URL:jdbc:postgresql://db:5432/postgres}
spring.datasource.username=${DB_USER:postgres}
spring.datasource.password=${DB_PASS:postgres}
spring.datasource.driver-class-name=org.postgresql.Driver
spring.sql.init.data-locations=classpath:sql/data.sql
spring.sql.init.mode=always
spring.jpa.defer-datasource-initialization=true
# create and drop table, good for testing, production set to none or comment it
spring.jpa.hibernate.ddl-auto=update
spring.web.resources.static-locations=classpath:/static/,file:images/
file.upload-dir=${IMAGES_UPLOAD_DIR:/app/images}
spring.servlet.multipart.max-file-size=${MAX_FILE_SIZE:10MB}
spring.servlet.multipart.max-request-size=${MAX_REQUEST_SIZE:10MB}
spring.mail.host=${MAIL_HOST}
spring.mail.port=${MAIL_PORT}
spring.mail.username=${MAIL_USER}
spring.mail.password=${MAIL_PASSWORD}
tpay.clientId=${TPAY_CLIENT_ID}
tpay.clientSecret=${TPAY_SECRET}
tpay.authUrl=${TPAY_AUTH_URL}
tpay.transactionUrl=${TPAY_TRANSACTION_URL}
tpay.securityCode = ${TPAY_SECURITY_CODE}
jwt.secret=${JWT_SECRET}
jwt.expiration=1200000
logging.file.name=logs/payment-notifications.log
logging.level.TpayLogger=INFO

View File

@@ -0,0 +1,20 @@
spring.application.name=ArtisanConnectBackend
## PostgreSQL
spring.datasource.url=jdbc:postgresql://db:5432/postgres
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.username=postgres
spring.datasource.password=postgres
#initial data for db injection
spring.sql.init.data-locations=classpath:sql/data.sql
spring.sql.init.mode=always
spring.jpa.defer-datasource-initialization=true
# create and drop table, good for testing, production set to none or comment it
spring.jpa.hibernate.ddl-auto=update
#file.upload-dir=/Users/andsol/Desktop/uploads
file.upload-dir=/app/images
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=10MB

View File

@@ -1,10 +1,15 @@
INSERT INTO clients (email, first_name, image, last_name, password, role)
INSERT INTO roles (id, rolename)
VALUES
('dignissim.tempor.arcu@aol.ca', 'Diana', 'null', 'Harrison', 'password', 'USER'),
('john.doe@example.com', 'John', 'null', 'Doe', 'password123', 'ADMIN'),
('jane.smith@example.com', 'Jane', 'null', 'Smith', 'securepass', 'USER'),
('michael.brown@example.com', 'Michael', 'null', 'Brown', 'mypassword', 'USER'),
('emily.jones@example.com', 'Emily', 'null', 'Jones', 'passw0rd', 'USER');
(1, 'USER'),
(2, 'ADMIN');
INSERT INTO clients (email, first_name, last_name, password, role_id)
VALUES
('dignissim.tempor.arcu@aol.ca', 'Diana', 'Harrison', '', 1),
('john.doe@example.com', 'John', 'Doe', '', 2),
('jane.smith@example.com', 'Jane', 'Smith', '', 1),
('michael.brown@example.com', 'Michael', 'Brown', '', 1),
('emily.jones@example.com', 'Emily', 'Jones', '', 1);
INSERT INTO notice (title, description, client_id, price, category, status, publish_date) VALUES
@@ -12,4 +17,45 @@ INSERT INTO notice (title, description, client_id, price, category, status, publ
('Drewniany stół', 'Solidny stół wykonany z litego drewna dębowego.', 3, 1200.00, 'Furniture', 'ACTIVE', '2023-09-15'),
('Ceramiczna waza', 'Piękna waza ceramiczna, idealna na prezent.', 2, 300.00, 'Ceramics', 'INACTIVE', '2023-08-20'),
('Obraz olejny', 'Obraz olejny przedstawiający krajobraz górski.', 4, 800.00, 'Painting', 'ACTIVE', '2023-07-10'),
('Skórzany portfel', 'Ręcznie wykonany portfel ze skóry naturalnej.', 1, 250.00, 'Leatherwork', 'ACTIVE', '2023-06-05');
('Skórzany portfel', 'Ręcznie wykonany portfel ze skóry naturalnej.', 1, 250.00, 'Leatherwork', 'ACTIVE', '2023-06-05');
insert into attributes (name) values
('Kolor'),
('Materiał');
-- Kolory
insert into attribute_values (value, id_attribute) values
('Zielony', 1),
('Czerwony', 1),
('Niebieski', 1),
('Żółty', 1),
('Biały', 1),
('Czarny', 1),
('Różowy', 1),
('Szary', 1),
('Fioletowy', 1),
('Pomarańczowy', 1),
('Inny', 1);
-- Materiały
insert into attribute_values (value, id_attribute) values
('Bawełna', 2),
('Wełna', 2),
('Syntetyk', 2),
('Skóra', 2),
('Len', 2),
('Jedwab', 2),
('Poliester', 2),
('Akryl', 2),
('Wiskoza', 2),
('Nylon', 2),
('Inny', 2);
insert into attributes_notice (id_value, notice_id) values
(1, 1), -- Ręcznie robiona biżuteria - Zielony
(22, 1),
(2, 2), -- Drewniany stół - Czerwony
(3, 3), -- Ceramiczna waza - Niebieski
(4, 4), -- Obraz olejny - Żółty
(5, 5); -- Skórzany portfel - Biały

View File

@@ -1,33 +1,441 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.dto.*;
import _11.asktpk.artisanconnectbackend.repository.ClientRepository;
import _11.asktpk.artisanconnectbackend.repository.NoticeRepository;
import _11.asktpk.artisanconnectbackend.service.*;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.*;
import _11.asktpk.artisanconnectbackend.entities.Image;
import _11.asktpk.artisanconnectbackend.repository.ImageRepository;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
@SpringBootTest
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.UUID;
import java.util.Comparator;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
/**
* Testy dla funkcjonalności klienta w backendzie.
*/
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class ArtisanConnectBackendApplicationTests {
private static final Logger logger = LogManager.getLogger(ArtisanConnectBackendApplicationTests.class);
// @Test
// void testPostgresDatabase() {
// postgresDatabase.add(new Notice("Test Notice", "Username", "Test Description"));
// Boolean isRecordAvailable = postgresDatabase.get().size() > 0;
// if(isRecordAvailable) {
// logger.info("The record is available in the database");
// } else {
// logger.error("The record is not available in the database");
// }
// assert isRecordAvailable;
// }
//
// @Test
// void getAllNotices() throws IOException {
// OkHttpClient client = new OkHttpClient().newBuilder()
// .build();
// MediaType mediaType = MediaType.parse("text/plain");
// Request request = new Request.Builder()
// .url("http://localhost:8080/api/v1/notices/all")
// .build();
// Response response = client.newCall(request).execute();
// }
}
@Nested
@DisplayName("Testy integracyjne ImageService")
class ImageServiceTest {
private final Logger logger = LogManager.getLogger(ImageServiceTest.class);
private final ImageService imageService;
private final ImageRepository imageRepository;
private final Path testDirectory;
ImageServiceTest() throws Exception {
logger.info("Inicjalizacja testów ImageService");
this.imageRepository = mock(ImageRepository.class);
this.testDirectory = Files.createTempDirectory("test-images");
logger.info("Utworzono katalog testowy: {}", testDirectory);
Constructor<ImageService> constructor = ImageService.class.getDeclaredConstructor(ImageRepository.class);
constructor.setAccessible(true);
this.imageService = constructor.newInstance(imageRepository);
}
@AfterEach
void cleanup() throws IOException {
logger.info("Sprzątanie po teście - usuwanie katalogu testowego: {}", testDirectory);
try (var paths = Files.walk(testDirectory)) {
paths.sorted(Comparator.reverseOrder())
.forEach(path -> {
try {
Files.delete(path);
logger.debug("Usunięto plik: {}", path);
} catch (IOException e) {
logger.warn("Nie można usunąć pliku: {}", path, e);
}
});
}
}
@Test
@DisplayName("Powinien poprawnie zapisać obraz w magazynie plików")
void shouldSaveImageToStorage() throws IOException {
logger.info("Test zapisu obrazu - rozpoczęcie");
final String testFileName = "test.jpg";
final Path testFilePath = testDirectory.resolve(testFileName);
Files.createFile(testFilePath);
Files.write(testFilePath, "test content".getBytes());
logger.debug("Utworzono testowy plik: {}", testFilePath);
final MultipartFile file = mock(MultipartFile.class);
when(file.getOriginalFilename()).thenReturn(testFileName);
when(file.getInputStream()).thenReturn(Files.newInputStream(testFilePath));
final String savedFileName = imageService.saveImageToStorage(testDirectory.toString(), file);
logger.info("Zapisano plik pod nazwą: {}", savedFileName);
assertTrue(savedFileName.endsWith(".jpg"));
assertTrue(Files.exists(testDirectory.resolve(savedFileName)));
logger.info("Test zapisu obrazu - zakończony pomyślnie");
}
@Test
@DisplayName("Powinien poprawnie pobrać obraz")
void shouldGetImage() throws IOException {
logger.info("Test pobierania obrazu - rozpoczęcie");
final String testFileName = "test.jpg";
Files.createFile(testDirectory.resolve(testFileName));
logger.debug("Utworzono testowy plik: {}", testFileName);
final Resource resource = imageService.getImage(testDirectory.toString(), testFileName);
logger.info("Pobrano zasób: {}", resource.getFilename());
assertNotNull(resource);
assertTrue(resource.exists());
assertInstanceOf(UrlResource.class, resource);
logger.info("Test pobierania obrazu - zakończony pomyślnie");
}
@Test
@DisplayName("Powinien zgłosić błąd, gdy obraz nie zostanie znaleziony")
void shouldThrowExceptionWhenImageNotFound() {
logger.info("Test obsługi błędu - rozpoczęcie");
final Exception exception = assertThrows(IOException.class, () ->
imageService.getImage(testDirectory.toString(), "missing.jpg")
);
logger.info("Złapano wyjątek: {}", exception.getMessage());
assertThat(exception).hasMessageContaining("File not found");
logger.info("Test obsługi błędu - zakończony pomyślnie");
}
@Test
@DisplayName("Powinien poprawnie usuwać obraz z magazynu plików")
void shouldDeleteImage() throws IOException {
logger.info("Test usuwania obrazu - rozpoczęcie");
final String testFileName = "test-delete.jpg";
final Path testFilePath = testDirectory.resolve(testFileName);
Files.createFile(testFilePath);
logger.debug("Utworzono testowy plik: {}", testFilePath);
when(imageRepository.existsImageByImageNameEqualsIgnoreCase(testFileName)).thenReturn(true);
imageService.deleteImage(testDirectory.toString(), testFileName);
logger.info("Usunięto plik: {}", testFileName);
assertFalse(Files.exists(testFilePath));
verify(imageRepository).deleteByImageNameEquals(testFileName);
logger.info("Test usuwania obrazu - zakończony pomyślnie");
}
@Test
@DisplayName("Powinien poprawnie zwrócić listę nazw obrazów")
void shouldGetImagesListForNotice() throws Exception {
logger.info("Test pobierania listy obrazów - rozpoczęcie");
final Long noticeId = 1L;
final List<String> expectedNames = List.of("image1.jpg", "image2.jpg");
final List<Image> mockImages = expectedNames.stream()
.map(name -> {
Image img = new Image();
img.setImageName(name);
return img;
})
.collect(Collectors.toList());
when(imageRepository.findByNoticeId(noticeId)).thenReturn(mockImages);
logger.debug("Skonfigurowano mock repository dla noticeId: {}", noticeId);
final List<String> imageNames = imageService.getImagesList(noticeId);
logger.info("Pobrano listę {} obrazów", imageNames.size());
assertThat(imageNames).containsExactlyElementsOf(expectedNames);
logger.info("Test pobierania listy obrazów - zakończony pomyślnie");
}
}
@Nested
@DisplayName("Testy dla VariablesController")
@Transactional
class VariablesControllerTest {
private final int port;
private final TestRestTemplate restTemplate;
@Autowired
public VariablesControllerTest(@LocalServerPort int port, TestRestTemplate restTemplate) {
this.port = port;
this.restTemplate = restTemplate;
logger.info("Inicjalizacja testów VariablesController");
}
private String registerAndGetJwtToken(String emailPrefix) {
logger.info("Rozpoczęcie procesu rejestracji dla prefiksu email: {}", emailPrefix);
String email = emailPrefix + "_" + UUID.randomUUID().toString().substring(0, 8) + "@example.com";
logger.debug("Wygenerowany email: {}", email);
ClientRegistrationDTO registrationDTO = new ClientRegistrationDTO();
registrationDTO.setEmail(email);
registrationDTO.setFirstName("Test");
registrationDTO.setLastName("User");
registrationDTO.setPassword("password123");
ResponseEntity<AuthResponseDTO> response = restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/register"),
registrationDTO,
AuthResponseDTO.class
);
if (response.getStatusCode() == HttpStatus.CONFLICT) {
logger.warn("Użytkownik już istnieje, próba logowania");
AuthRequestDTO loginRequest = new AuthRequestDTO();
loginRequest.setEmail(email);
loginRequest.setPassword("password123");
response = restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/login"),
loginRequest,
AuthResponseDTO.class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
} else {
logger.info("Pomyślnie zarejestrowano nowego użytkownika");
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.CREATED);
}
assertThat(response.getBody()).isNotNull();
logger.debug("Otrzymano token JWT");
return response.getBody().getToken();
}
private HttpEntity<Void> createRequestWithToken(String token) {
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "Bearer " + token);
return new HttpEntity<>(headers);
}
@Test
@DisplayName("Powinien zwrócić kategorie")
void shouldGetCategories() {
logger.info("Test pobierania kategorii - rozpoczęcie");
String token = registerAndGetJwtToken(
"categories"
);
logger.debug("Otrzymano token autoryzacyjny");
String url = createURLWithPort("/api/v1/vars/categories");
logger.debug("Utworzono URL endpointu: {}", url);
HttpEntity<Void> request = createRequestWithToken(token);
ResponseEntity<CategoriesDTO[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
request,
CategoriesDTO[].class
);
logger.info("Wykonano zapytanie o kategorie");
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isNotNull().isNotEmpty();
logger.info("Test pobierania kategorii - zakończony pomyślnie");
}
@Test
@DisplayName("Powinien zwrócić statusy")
void shouldGetStatuses() {
String token = registerAndGetJwtToken(
"statuses"
);
String url = createURLWithPort("/api/v1/vars/statuses");
HttpEntity<Void> request = createRequestWithToken(token);
ResponseEntity<Enums.Status[]> response = restTemplate.exchange(
url,
HttpMethod.GET,
request,
Enums.Status[].class
);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isNotNull().isNotEmpty();
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}
@Nested
@DisplayName("Testy integracyjne AuthController")
@Transactional
class AuthControllerTest {
private final int port;
private final TestRestTemplate restTemplate;
private final ClientRepository clientRepository;
private final NoticeRepository noticeRepository;
private final Logger logger = LogManager.getLogger(AuthControllerTest.class);
@Autowired
public AuthControllerTest(
@LocalServerPort int port,
TestRestTemplate restTemplate,
ClientRepository clientRepository,
NoticeRepository noticeRepository) {
this.port = port;
this.restTemplate = restTemplate;
this.clientRepository = clientRepository;
this.noticeRepository = noticeRepository;
}
@BeforeEach
void cleanDatabase() {
noticeRepository.deleteAll();
clientRepository.deleteAll();
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
@Test
@DisplayName("Powinien zwrócić błąd przy rejestracji z istniejącym emailem")
void shouldFailRegisterWithExistingEmail() {
String email = "user_" + UUID.randomUUID().toString().substring(0, 8) + "@example.com";
ClientRegistrationDTO registrationDTO = new ClientRegistrationDTO();
registrationDTO.setEmail(email);
registrationDTO.setFirstName("Jan");
registrationDTO.setLastName("Kowalski");
registrationDTO.setPassword("password123");
ResponseEntity<AuthResponseDTO> firstResponse = restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/register"),
registrationDTO,
AuthResponseDTO.class
);
assertThat(firstResponse.getStatusCode()).isEqualTo(HttpStatus.CREATED);
ResponseEntity<AuthResponseDTO> secondResponse = restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/register"),
registrationDTO,
AuthResponseDTO.class
);
logger.info("Wysłano żądanie rejestracji");
assertThat(secondResponse.getStatusCode()).isEqualTo(HttpStatus.CONFLICT);
}
@Test
@DisplayName("Powinien poprawnie zalogować istniejącego użytkownika")
void shouldLoginExistingUser() {
logger.info("Test logowania użytkownika - rozpoczęcie");
String email = "user_" + UUID.randomUUID().toString().substring(0, 8) + "@example.com";
String password = "password123";
ClientRegistrationDTO registrationDTO = new ClientRegistrationDTO();
registrationDTO.setEmail(email);
registrationDTO.setFirstName("Jan");
registrationDTO.setLastName("Kowalski");
registrationDTO.setPassword(password);
restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/register"),
registrationDTO,
AuthResponseDTO.class
);
logger.debug("Zarejestrowano testowego użytkownika: {}", email);
AuthRequestDTO loginRequest = new AuthRequestDTO();
loginRequest.setEmail(email);
loginRequest.setPassword(password);
ResponseEntity<AuthResponseDTO> response = restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/login"),
loginRequest,
AuthResponseDTO.class
);
logger.info("Wykonano próbę logowania");
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getToken()).isNotBlank();
logger.info("Test logowania - zakończony pomyślnie");
}
@Test
@DisplayName("Powinien zwrócić błąd przy logowaniu z nieprawidłowym hasłem")
void shouldFailLoginWithIncorrectPassword() {
logger.info("Test obsługi błędnych danych logowania - rozpoczęcie");
String email = "user_" + UUID.randomUUID().toString().substring(0, 8) + "@example.com";
String password = "password123";
ClientRegistrationDTO registrationDTO = new ClientRegistrationDTO();
registrationDTO.setEmail(email);
registrationDTO.setFirstName("Jan");
registrationDTO.setLastName("Kowalski");
registrationDTO.setPassword(password);
restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/register"),
registrationDTO,
AuthResponseDTO.class
);
AuthRequestDTO loginRequest = new AuthRequestDTO();
loginRequest.setEmail(email);
loginRequest.setPassword("wrongPassword");
logger.debug("Przygotowano nieprawidłowe dane logowania");
ResponseEntity<AuthResponseDTO> response = restTemplate.postForEntity(
createURLWithPort("/api/v1/auth/login"),
loginRequest,
AuthResponseDTO.class
);
logger.info("Wykonano próbę logowania z błędnymi danymi");
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.UNAUTHORIZED);
logger.info("Test obsługi błędnych danych - zakończony pomyślnie");
}
}
}

View File

@@ -0,0 +1,120 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.customExceptions.ClientAlreadyExistsException;
import _11.asktpk.artisanconnectbackend.customExceptions.WrongLoginPasswordException;
import _11.asktpk.artisanconnectbackend.dto.AuthResponseDTO;
import _11.asktpk.artisanconnectbackend.dto.ClientDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Role;
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
import _11.asktpk.artisanconnectbackend.service.AuthService;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.mockito.Mockito;
import org.springframework.security.crypto.password.PasswordEncoder;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class AuthServiceTest {
private final ClientService clientService = Mockito.mock(ClientService.class);
private final PasswordEncoder passwordEncoder = Mockito.mock(PasswordEncoder.class);
private final JwtUtil jwtUtil = Mockito.mock(JwtUtil.class);
private final AuthService authService = new AuthService(clientService, jwtUtil, passwordEncoder);
@Test
@DisplayName("Test logowania - poprawne dane")
public void testLoginSuccess() throws Exception {
String email = "test@example.com";
String password = "password";
Client client = new Client();
client.setEmail(email);
client.setPassword("encodedPassword");
client.setRole(new Role());
when(clientService.getClientByEmail(email)).thenReturn(client);
when(passwordEncoder.matches(password, client.getPassword())).thenReturn(true);
when(jwtUtil.generateToken(email, client.getRole().getRole(), client.getId())).thenReturn("token");
AuthResponseDTO response = authService.login(email, password);
assertNotNull(response, "Odpowiedź nie powinna być null");
assertEquals("token", response.getToken(), "Token w odpowiedzi powinien być poprawny");
}
@Test
@DisplayName("Test logowania - niepoprawne hasło")
public void testLoginWrongPassword() {
String email = "test@example.com";
String password = "wrongPassword";
Client client = new Client();
client.setEmail(email);
client.setPassword("encodedPassword");
when(clientService.getClientByEmail(email)).thenReturn(client);
when(passwordEncoder.matches(password, client.getPassword())).thenReturn(false);
assertThrows(WrongLoginPasswordException.class, () -> authService.login(email, password),
"Powinien zostać rzucony WrongLoginPasswordException");
}
@Test
@DisplayName("Test rejestracji - nowy użytkownik")
public void testRegisterNewUser() throws Exception {
String email = "new@example.com";
String password = "password";
String firstName = "Jan";
String lastName = "Kowalski";
when(clientService.getClientByEmail(email)).thenReturn(null);
when(passwordEncoder.encode(password)).thenReturn("encodedPassword");
when(clientService.registerClient(any(Client.class))).thenReturn(new ClientDTO());
AuthResponseDTO response = authService.register(email, password, firstName, lastName);
assertNotNull(response, "Odpowiedź nie powinna być null");
}
@Test
@DisplayName("Test rejestracji - użytkownik już istnieje")
public void testRegisterExistingUser() {
String email = "existing@example.com";
String password = "password";
String firstName = "Jan";
String lastName = "Kowalski";
when(clientService.getClientByEmail(email)).thenReturn(new Client());
assertThrows(ClientAlreadyExistsException.class, () -> authService.register(email, password, firstName, lastName),
"Powinien zostać rzucony ClientAlreadyExistsException");
}
@Test
@DisplayName("Test wylogowania z poprawnym tokenem")
public void testLogoutWithValidToken() {
String token = "valid.token.here";
when(jwtUtil.isBlacklisted(token)).thenReturn(false);
authService.logout(token);
verify(jwtUtil, times(1)).blacklistToken(token);
when(jwtUtil.isBlacklisted(token)).thenReturn(true);
assertTrue(jwtUtil.isBlacklisted(token), "Token powinien być na czarnej liście po wylogowaniu");
}
@Test
@DisplayName("Test wylogowania bez tokena")
public void testLogoutWithoutToken() {
authService.logout(null);
verify(jwtUtil, never()).blacklistToken(anyString());
}
}

View File

@@ -0,0 +1,174 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.controller.ClientController;
import _11.asktpk.artisanconnectbackend.dto.ClientDTO;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.Collections;
import java.util.List;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
class ClientControllerTest {
private MockMvc mockMvc;
private final ObjectMapper objectMapper = new ObjectMapper();
@Mock
private ClientService clientService;
@InjectMocks
private ClientController clientController;
private ClientDTO sampleClientDTO;
@BeforeEach
void setUp() {
System.out.println("Inicjalizacja konfiguracji testu...");
MockitoAnnotations.openMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(clientController).build();
sampleClientDTO = new ClientDTO();
sampleClientDTO.setId(1L);
sampleClientDTO.setEmail("test@example.com");
sampleClientDTO.setFirstName("John");
sampleClientDTO.setLastName("Doe");
sampleClientDTO.setRole("USER");
System.out.println("Konfiguracja testu zakończona z przykładowym klientem: " + sampleClientDTO);
}
@Test
@DisplayName("Powinien zwrócić listę klientów")
void getAllClients_ShouldReturnListOfClients() throws Exception {
System.out.println("Uruchamianie testu: getAllClients_ShouldReturnListOfClients");
List<ClientDTO> clients = Collections.singletonList(sampleClientDTO);
when(clientService.getAllClients()).thenReturn(clients);
System.out.println("Konfiguracja mocka: clientService.getAllClients() zwróci " + clients);
mockMvc.perform(get("/api/v1/clients/get/all"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].id").value(1L))
.andExpect(jsonPath("$[0].email").value("test@example.com"));
verify(clientService, times(1)).getAllClients();
System.out.println("Test zaliczony: Pomyślnie pobrano listę klientów");
}
@Test
@DisplayName("Powinien utworzyć nowego klienta")
void addClient_WhenClientNotExists_ShouldCreateClient() throws Exception {
System.out.println("Uruchamianie testu: addClient_WhenClientNotExists_ShouldCreateClient");
when(clientService.clientExists(anyLong())).thenReturn(false);
when(clientService.addClient(any(ClientDTO.class))).thenReturn(sampleClientDTO);
System.out.println("Konfiguracja mocka: clientService.addClient() zwróci " + sampleClientDTO);
mockMvc.perform(post("/api/v1/clients/add")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(sampleClientDTO)))
.andExpect(status().isCreated())
.andExpect(jsonPath("$.id").value(1L));
verify(clientService, times(1)).addClient(any(ClientDTO.class));
System.out.println("Test zaliczony: Pomyślnie utworzono nowego klienta");
}
@Test
@DisplayName("Powinien zwrócić 409 gdy klient istnieje")
void addClient_WhenClientExists_ShouldReturnConflict() throws Exception {
System.out.println("Uruchamianie testu: addClient_WhenClientExists_ShouldReturnConflict");
when(clientService.clientExists(anyLong())).thenReturn(true);
System.out.println("Konfiguracja mocka: clientService.clientExists() zwróci true");
mockMvc.perform(post("/api/v1/clients/add")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(sampleClientDTO)))
.andExpect(status().isConflict());
verify(clientService, times(0)).addClient(any(ClientDTO.class));
System.out.println("Test zaliczony: Poprawnie zwrócono 409 dla istniejącego klienta");
}
@Test
@DisplayName("Powinien zaktualizować istniejącego klienta")
void updateClient_WhenClientExists_ShouldUpdateClient() throws Exception {
System.out.println("Uruchamianie testu: updateClient_WhenClientExists_ShouldUpdateClient");
when(clientService.clientExists(1L)).thenReturn(true);
when(clientService.updateClient(anyLong(), any(ClientDTO.class))).thenReturn(sampleClientDTO);
System.out.println("Konfiguracja mocka: clientService.updateClient() zwróci " + sampleClientDTO);
mockMvc.perform(put("/api/v1/clients/edit/1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(sampleClientDTO)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(1L));
verify(clientService, times(1)).updateClient(anyLong(), any(ClientDTO.class));
System.out.println("Test zaliczony: Pomyślnie zaktualizowano klienta");
}
@Test
@DisplayName("Powinien zwrócić 404 gdy klient nie istnieje")
void updateClient_WhenClientNotExists_ShouldReturnNotFound() throws Exception {
System.out.println("Uruchamianie testu: updateClient_WhenClientNotExists_ShouldReturnNotFound");
when(clientService.clientExists(1L)).thenReturn(false);
System.out.println("Konfiguracja mocka: clientService.clientExists(1L) zwróci false");
mockMvc.perform(put("/api/v1/clients/edit/1")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(sampleClientDTO)))
.andExpect(status().isNotFound());
verify(clientService, times(0)).updateClient(anyLong(), any(ClientDTO.class));
System.out.println("Test zaliczony: Poprawnie zwrócono 404 dla nieistniejącego klienta");
}
@Test
@DisplayName("Powinien usunąć istniejącego klienta")
void deleteClient_WhenClientExists_ShouldDeleteClient() throws Exception {
System.out.println("Uruchamianie testu: deleteClient_WhenClientExists_ShouldDeleteClient");
when(clientService.clientExists(1L)).thenReturn(true);
doNothing().when(clientService).deleteClient(1L);
System.out.println("Konfiguracja mocka: clientService.deleteClient(1L) nie zrobi nic");
mockMvc.perform(delete("/api/v1/clients/delete/1"))
.andExpect(status().isOk());
verify(clientService, times(1)).deleteClient(1L);
System.out.println("Test zaliczony: Pomyślnie usunięto klienta");
}
@Test
@DisplayName("Powinien zwrócić 404 gdy klient nie istnieje")
void deleteClient_WhenClientNotExists_ShouldReturnNotFound() throws Exception {
System.out.println("Uruchamianie testu: deleteClient_WhenClientNotExists_ShouldReturnNotFound");
when(clientService.clientExists(1L)).thenReturn(false);
System.out.println("Konfiguracja mocka: clientService.clientExists(1L) zwróci false");
mockMvc.perform(delete("/api/v1/clients/delete/1"))
.andExpect(status().isNotFound());
verify(clientService, times(0)).deleteClient(anyLong());
System.out.println("Test zaliczony: Poprawnie zwrócono 404 dla nieistniejącego klienta");
}
}

View File

@@ -0,0 +1,241 @@
package _11.asktpk.artisanconnectbackend;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import _11.asktpk.artisanconnectbackend.dto.ClientDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Role;
import _11.asktpk.artisanconnectbackend.repository.ClientRepository;
import _11.asktpk.artisanconnectbackend.repository.RolesRepository;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import jakarta.persistence.EntityNotFoundException;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class ClientServiceTest {
private final ClientRepository clientRepository = Mockito.mock(ClientRepository.class);
private final RolesRepository rolesRepository = Mockito.mock(RolesRepository.class);
private final ClientService clientService = new ClientService(clientRepository, rolesRepository);
@Test
@DisplayName("Test pobierania wszystkich klientów")
public void testGetAllClients() {
System.out.println("Rozpoczęcie testu: testGetAllClients - Test pobierania wszystkich klientów");
Client client1 = new Client();
client1.setId(1L);
client1.setEmail("client1@example.com");
client1.setRole(new Role());
Client client2 = new Client();
client2.setId(2L);
client2.setEmail("client2@example.com");
client2.setRole(new Role());
when(clientRepository.findAll()).thenReturn(List.of(client1, client2));
List<ClientDTO> clients = clientService.getAllClients();
System.out.println("Pobrano listę klientów, liczba elementów: " + clients.size());
assertEquals(2, clients.size(), "Lista klientów powinna zawierać 2 elementy");
System.out.println("Pierwszy klient na liście: " + clients.getFirst().getEmail());
assertEquals("client1@example.com", clients.getFirst().getEmail(), "Email pierwszego klienta powinien być poprawny");
System.out.println("Test pobierania wszystkich klientów zakończony sukcesem. Zwrócono " + clients.size() + " klientów.");
}
@Test
@DisplayName("Test pobierania klienta po ID - klient istnieje")
public void testGetClientByIdExists() {
Long clientId = 1L;
System.out.println("Rozpoczęcie testu: testGetClientByIdExists - Test pobierania klienta po ID (ID: " + clientId + ")");
Client client = new Client();
client.setId(clientId);
client.setEmail("client@example.com");
client.setRole(new Role());
when(clientRepository.findById(clientId)).thenReturn(Optional.of(client));
Client retrievedClient = clientService.getClientById(clientId);
System.out.println("Pobrano klienta o ID: " + (retrievedClient != null ? retrievedClient.getId() : "null"));
assertNotNull(retrievedClient, "Pobrany klient nie powinien być null");
assertEquals(clientId, retrievedClient.getId(), "ID klienta powinno być zgodne");
System.out.println("Test pobierania klienta po ID (ID: " + clientId + ") zakończony sukcesem. Znaleziono klienta: " + retrievedClient.getEmail());
}
@Test
@DisplayName("Test pobierania klienta po ID - klient nie istnieje")
public void testGetClientByIdNotExists() {
Long clientId = 1L;
System.out.println("Rozpoczęcie testu: testGetClientByIdNotExists - Test pobierania nieistniejącego klienta (ID: " + clientId + ")");
when(clientRepository.findById(clientId)).thenReturn(Optional.empty());
Client retrievedClient = clientService.getClientById(clientId);
System.out.println("Próba pobrania nieistniejącego klienta zwróciła: " + retrievedClient);
assertNull(retrievedClient, "Pobrany klient powinien być null, gdy nie istnieje");
System.out.println("Test pobierania nieistniejącego klienta (ID: " + clientId + ") zakończony sukcesem. Zwrócono null zgodnie z oczekiwaniami.");
}
@Test
@DisplayName("Test pobierania klienta po emailu")
public void testGetClientByEmail() {
String email = "client@example.com";
System.out.println("Rozpoczęcie testu: testGetClientByEmail - Test pobierania klienta po emailu (" + email + ")");
Client client = new Client();
client.setEmail(email);
when(clientRepository.findByEmail(email)).thenReturn(client);
Client retrievedClient = clientService.getClientByEmail(email);
System.out.println("Pobrano klienta o emailu: " + (retrievedClient != null ? retrievedClient.getEmail() : "null"));
assertNotNull(retrievedClient, "Pobrany klient nie powinien być null");
assertEquals(email, retrievedClient.getEmail(), "Email klienta powinien być zgodny");
System.out.println("Test pobierania klienta po emailu (" + email + ") zakończony sukcesem.");
}
@Test
@DisplayName("Test dodawania klienta")
public void testAddClient() {
System.out.println("Rozpoczęcie testu: testAddClient - Test dodawania nowego klienta");
ClientDTO clientDTO = new ClientDTO();
clientDTO.setEmail("newclient@example.com");
clientDTO.setRole("USER");
Client client = new Client();
client.setEmail("newclient@example.com");
client.setRole(new Role());
when(clientRepository.save(any(Client.class))).thenReturn(client);
ClientDTO addedClient = clientService.addClient(clientDTO);
System.out.println("Dodano nowego klienta: " + (addedClient != null ? addedClient.getEmail() : "null"));
assertNotNull(addedClient, "Dodany klient nie powinien być null");
assertEquals("newclient@example.com", addedClient.getEmail(), "Email dodanego klienta powinien być poprawny");
System.out.println("Test dodawania klienta zakończony sukcesem. Dodano klienta: " + addedClient.getEmail());
}
@Test
@DisplayName("Test aktualizacji klienta")
public void testUpdateClient() {
Long clientId = 1L;
System.out.println("Rozpoczęcie testu: testUpdateClient - Test aktualizacji klienta (ID: " + clientId + ")");
Client existingClient = new Client();
existingClient.setId(clientId);
existingClient.setEmail("old@example.com");
ClientDTO updatedDTO = new ClientDTO();
updatedDTO.setEmail("updated@example.com");
updatedDTO.setRole("USER");
Role role = new Role();
role.setRole("USER");
when(clientRepository.findById(clientId)).thenReturn(Optional.of(existingClient));
when(rolesRepository.findRoleByRole("USER")).thenReturn(role);
when(clientRepository.save(any(Client.class))).thenReturn(existingClient);
ClientDTO updatedClient = clientService.updateClient(clientId, updatedDTO);
System.out.println("Zaktualizowano klienta. Nowy email: " + updatedClient.getEmail());
assertEquals("updated@example.com", updatedClient.getEmail(), "Email klienta powinien być zaktualizowany");
System.out.println("Test aktualizacji klienta (ID: " + clientId + ") zakończony sukcesem. Nowy email: " + updatedClient.getEmail());
}
@Test
@DisplayName("Test aktualizacji klienta - klient nie istnieje")
public void testUpdateClientNotExists() {
long clientId = 1L;
System.out.println("Rozpoczęcie testu: testUpdateClientNotExists - Test aktualizacji nieistniejącego klienta (ID: " + clientId + ")");
ClientDTO updatedDTO = new ClientDTO();
updatedDTO.setEmail("updated@example.com");
when(clientRepository.findById(clientId)).thenReturn(Optional.empty());
System.out.println("Oczekiwanie na EntityNotFoundException...");
assertThrows(EntityNotFoundException.class, () -> clientService.updateClient(clientId, updatedDTO),
"Powinien zostać rzucony EntityNotFoundException");
System.out.println("Test aktualizacji nieistniejącego klienta (ID: " + clientId + ") zakończony sukcesem. Rzucono wyjątek EntityNotFoundException zgodnie z oczekiwaniami.");
}
@Test
@DisplayName("Test usuwania klienta")
public void testDeleteClient() {
Long clientId = 1L;
System.out.println("Rozpoczęcie testu: testDeleteClient - Test usuwania klienta (ID: " + clientId + ")");
clientService.deleteClient(clientId);
verify(clientRepository, times(1)).deleteById(clientId);
System.out.println("Weryfikacja: metoda deleteById została wywołana 1 raz z ID: " + clientId);
System.out.println("Test usuwania klienta (ID: " + clientId + ") zakończony sukcesem.");
}
@Test
@DisplayName("Test konwersji encji do DTO")
public void testToDto() {
System.out.println("Rozpoczęcie testu: testToDto - Test konwersji encji Client do ClientDTO");
Client client = new Client();
client.setId(1L);
client.setEmail("client@example.com");
client.setFirstName("Jan");
client.setLastName("Kowalski");
client.setImage("image.jpg");
Role role = new Role();
role.setRole("USER");
client.setRole(role);
System.out.println("Przygotowano encję Client do konwersji:");
System.out.println("ID: " + client.getId());
System.out.println("Email: " + client.getEmail());
System.out.println("Imię: " + client.getFirstName());
System.out.println("Nazwisko: " + client.getLastName());
System.out.println("Obraz: " + client.getImage());
System.out.println("Rola: " + client.getRole().getRole());
ClientDTO dto = clientService.toDto(client);
System.out.println("Wynik konwersji do DTO:");
System.out.println("ID: " + dto.getId());
System.out.println("Email: " + dto.getEmail());
System.out.println("Imię: " + dto.getFirstName());
System.out.println("Nazwisko: " + dto.getLastName());
System.out.println("Obraz: " + dto.getImage());
System.out.println("Rola: " + dto.getRole());
assertEquals(1L, dto.getId(), "ID w DTO powinno być zgodne");
assertEquals("client@example.com", dto.getEmail(), "Email w DTO powinien być zgodny");
assertEquals("Jan", dto.getFirstName(), "Imię w DTO powinno być zgodne");
assertEquals("Kowalski", dto.getLastName(), "Nazwisko w DTO powinno być zgodne");
assertEquals("image.jpg", dto.getImage(), "Obraz w DTO powinien być zgodny");
assertEquals("USER", dto.getRole(), "Rola w DTO powinna być zgodna");
System.out.println("Test konwersji encji do DTO zakończony sukcesem. Wszystkie pola zostały poprawnie zmapowane.");
}
}

View File

@@ -0,0 +1,186 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.controller.NoticeController;
import _11.asktpk.artisanconnectbackend.dto.*;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class NoticeControllerTest {
@Mock
private NoticeService noticeService;
@Mock
private ClientService clientService;
@Mock
private Tools tools;
@Mock
private HttpServletRequest request;
@InjectMocks
private NoticeController noticeController;
private NoticeResponseDTO sampleNotice;
private NoticeRequestDTO sampleNoticeRequest;
@BeforeEach
void setUp() {
System.out.println("Inicjalizacja danych testowych...");
sampleNotice = new NoticeResponseDTO();
sampleNotice.setNoticeId(1L);
sampleNotice.setTitle("Testowe ogłoszenie");
sampleNotice.setClientId(1L);
sampleNotice.setDescription("Opis testowego ogłoszenia");
sampleNotice.setPrice(100.0);
sampleNotice.setCategory(Enums.Category.Woodworking);
sampleNotice.setStatus(Enums.Status.ACTIVE);
sampleNotice.setPublishDate(LocalDateTime.now());
sampleNoticeRequest = new NoticeRequestDTO();
sampleNoticeRequest.setTitle("Testowe ogłoszenie");
sampleNoticeRequest.setClientId(1L);
sampleNoticeRequest.setDescription("Opis testowego ogłoszenia");
sampleNoticeRequest.setPrice(100.0);
sampleNoticeRequest.setCategory(Enums.Category.Woodworking);
sampleNoticeRequest.setStatus(Enums.Status.ACTIVE);
}
@Test
@DisplayName("Pobranie wszystkich ogłoszeń")
void getAllNotices_ShouldReturnListOfNotices() {
when(noticeService.getAllNotices()).thenReturn(List.of(sampleNotice));
List<NoticeResponseDTO> result = noticeController.getAllNotices();
assertNotNull(result);
assertEquals(1, result.size());
System.out.println("Test GET /notices zakończony sukcesem");
}
@Test
@DisplayName("Pobranie istniejącego ogłoszenia")
void getNoticeById_WhenNoticeExists_ShouldReturnNotice() {
when(noticeService.noticeExists(1L)).thenReturn(true);
when(noticeService.getNoticeById(1L)).thenReturn(sampleNotice);
ResponseEntity<?> response = noticeController.getNoticeById(1L);
assertEquals(HttpStatus.OK, response.getStatusCode());
System.out.println("Test GET /notices/{id} (istniejące) zakończony sukcesem");
}
@Test
@DisplayName("Pobranie nieistniejącego ogłoszenia")
void getNoticeById_WhenNoticeNotExists_ShouldReturnNotFound() {
when(noticeService.noticeExists(1L)).thenReturn(false);
ResponseEntity<?> response = noticeController.getNoticeById(1L);
assertEquals(HttpStatus.NOT_FOUND, response.getStatusCode());
System.out.println("Test GET /notices/{id} (nieistniejące) zakończony sukcesem");
}
@Test
@DisplayName("Dodanie poprawnego ogłoszenia")
void addNotice_WithValidData_ShouldCreateNotice() {
when(tools.getClientIdFromRequest(request)).thenReturn(1L);
when(clientService.clientExists(1L)).thenReturn(true);
when(noticeService.addNotice(any(NoticeRequestDTO.class))).thenReturn(1L);
ResponseEntity<NoticeAdditionDTO> response = noticeController.addNotice(sampleNoticeRequest, request);
assertEquals(HttpStatus.CREATED, response.getStatusCode());
System.out.println("Test POST /notices (poprawne dane) zakończony sukcesem");
}
@Test
@DisplayName("Dodanie ogłoszenia z błędną kategorią")
void addNotice_WithInvalidCategory_ShouldReturnBadRequest() {
sampleNoticeRequest.setCategory(null);
when(tools.getClientIdFromRequest(request)).thenReturn(1L);
when(clientService.clientExists(1L)).thenReturn(true);
ResponseEntity<NoticeAdditionDTO> response = noticeController.addNotice(sampleNoticeRequest, request);
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
System.out.println("Test POST /notices (błędna kategoria) zakończony sukcesem");
}
@Test
@DisplayName("Dodanie ogłoszenia przez nieistniejącego klienta")
void addNotice_WhenClientNotExists_ShouldReturnBadRequest() {
when(tools.getClientIdFromRequest(request)).thenReturn(1L);
when(clientService.clientExists(1L)).thenReturn(false);
ResponseEntity<NoticeAdditionDTO> response = noticeController.addNotice(sampleNoticeRequest, request);
assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
System.out.println("Test POST /notices (nieistniejący klient) zakończony sukcesem");
}
@Test
@DisplayName("Aktualizacja własnego ogłoszenia")
void editNotice_WhenNoticeExistsAndOwnedByClient_ShouldUpdateNotice() {
when(tools.getClientIdFromRequest(request)).thenReturn(1L);
when(noticeService.noticeExists(1L)).thenReturn(true);
when(noticeService.isNoticeOwnedByClient(1L, 1L)).thenReturn(true);
when(noticeService.updateNotice(anyLong(), any(NoticeRequestDTO.class))).thenReturn(sampleNotice);
ResponseEntity<Object> response = noticeController.editNotice(1L, sampleNoticeRequest, request);
assertEquals(HttpStatus.OK, response.getStatusCode());
System.out.println("Test PUT /notices/{id} (własne ogłoszenie) zakończony sukcesem");
}
@Test
@DisplayName("Próba aktualizacji cudzego ogłoszenia")
void editNotice_WhenNoticeNotOwnedByClient_ShouldReturnForbidden() {
when(tools.getClientIdFromRequest(request)).thenReturn(2L);
when(noticeService.noticeExists(1L)).thenReturn(true);
when(noticeService.isNoticeOwnedByClient(1L, 2L)).thenReturn(false);
ResponseEntity<Object> response = noticeController.editNotice(1L, sampleNoticeRequest, request);
assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode());
System.out.println("Test PUT /notices/{id} (cudze ogłoszenie) zakończony sukcesem");
}
@Test
@DisplayName("Usunięcie własnego ogłoszenia")
void deleteNotice_WhenNoticeExistsAndOwnedByClient_ShouldDeleteNotice() {
when(tools.getClientIdFromRequest(request)).thenReturn(1L);
when(noticeService.noticeExists(1L)).thenReturn(true);
when(noticeService.isNoticeOwnedByClient(1L, 1L)).thenReturn(true);
ResponseEntity<RequestResponseDTO> response = noticeController.deleteNotice(1L, request);
assertEquals(HttpStatus.OK, response.getStatusCode());
verify(noticeService, times(1)).deleteNotice(1L);
System.out.println("Test DELETE /notices/{id} (własne ogłoszenie) zakończony sukcesem");
}
}

View File

@@ -0,0 +1,174 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.dto.AttributeDto;
import _11.asktpk.artisanconnectbackend.dto.NoticeRequestDTO;
import _11.asktpk.artisanconnectbackend.dto.NoticeResponseDTO;
import _11.asktpk.artisanconnectbackend.entities.*;
import _11.asktpk.artisanconnectbackend.repository.*;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import jakarta.persistence.EntityNotFoundException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class NoticeServiceTest {
@Mock
private NoticeRepository noticeRepository;
@Mock
private ClientRepository clientRepository;
@Mock
private AttributesRepository attributesRepository;
@Mock
private AttributeValuesRepository attributeValuesRepository;
@Mock
private AttributesNoticeRepository attributesNoticeRepository;
@InjectMocks
private NoticeService noticeService;
private Notice sampleNotice;
private NoticeRequestDTO sampleNoticeRequest;
private Client sampleClient;
@BeforeEach
void setUp() {
System.out.println("Przygotowanie danych testowych...");
sampleClient = new Client();
sampleClient.setId(1L);
sampleClient.setEmail("test@example.com");
sampleNotice = new Notice();
sampleNotice.setIdNotice(1L);
sampleNotice.setTitle("Testowe ogłoszenie");
sampleNotice.setClient(sampleClient);
sampleNotice.setDescription("Opis testowego ogłoszenia");
sampleNotice.setPrice(100.0);
sampleNotice.setCategory(Enums.Category.Woodworking);
sampleNotice.setStatus(Enums.Status.ACTIVE);
sampleNotice.setPublishDate(LocalDateTime.now());
sampleNoticeRequest = new NoticeRequestDTO();
sampleNoticeRequest.setTitle("Testowe ogłoszenie");
sampleNoticeRequest.setClientId(1L);
sampleNoticeRequest.setDescription("Opis testowego ogłoszenia");
sampleNoticeRequest.setPrice(100.0);
sampleNoticeRequest.setCategory(Enums.Category.Woodworking);
sampleNoticeRequest.setStatus(Enums.Status.ACTIVE);
}
@Test
@DisplayName("Pobranie wszystkich ogłoszeń - powinno zwrócić listę ogłoszeń")
void getAllNotices_ShouldReturnListOfNotices() {
when(noticeRepository.findAll()).thenReturn(List.of(sampleNotice));
List<NoticeResponseDTO> result = noticeService.getAllNotices();
assertNotNull(result);
assertEquals(1, result.size());
System.out.println("Test pobrania wszystkich ogłoszeń zakończony");
}
@Test
@DisplayName("Pobranie ogłoszenia po ID - gdy istnieje")
void getNoticeById_WhenNoticeExists_ShouldReturnNotice() {
when(noticeRepository.findById(1L)).thenReturn(Optional.of(sampleNotice));
NoticeResponseDTO result = noticeService.getNoticeById(1L);
assertNotNull(result);
System.out.println("Test pobrania istniejącego ogłoszenia zakończony");
}
@Test
@DisplayName("Pobranie ogłoszenia po ID - gdy nie istnieje")
void getNoticeById_WhenNoticeNotExists_ShouldThrowException() {
when(noticeRepository.findById(1L)).thenReturn(Optional.empty());
assertThrows(EntityNotFoundException.class, () -> noticeService.getNoticeById(1L));
System.out.println("Test pobrania nieistniejącego ogłoszenia zakończony");
}
@Test
@DisplayName("Dodanie nowego ogłoszenia - poprawne dane")
void addNotice_WithValidData_ShouldCreateNotice() {
when(clientRepository.findById(1L)).thenReturn(Optional.of(sampleClient));
when(noticeRepository.save(any(Notice.class))).thenReturn(sampleNotice);
Long result = noticeService.addNotice(sampleNoticeRequest);
assertNotNull(result);
System.out.println("Test dodania ogłoszenia zakończony");
}
@Test
@DisplayName("Dodanie ogłoszenia z atrybutami")
void addNotice_WithAttributes_ShouldSaveAttributes() {
AttributeDto attributeDto = new AttributeDto();
attributeDto.setName("Kolor");
attributeDto.setValue("Zielony");
sampleNoticeRequest.setAttributes(List.of(attributeDto));
when(clientRepository.findById(1L)).thenReturn(Optional.of(sampleClient));
when(noticeRepository.save(any(Notice.class))).thenReturn(sampleNotice);
when(attributesRepository.findByName(anyString())).thenReturn(Optional.empty());
when(attributeValuesRepository.findByAttributeAndValue(any(), anyString())).thenReturn(Optional.empty());
Long result = noticeService.addNotice(sampleNoticeRequest);
assertNotNull(result);
System.out.println("Test dodania ogłoszenia z atrybutami zakończony");
}
@Test
@DisplayName("Usunięcie istniejącego ogłoszenia")
void deleteNotice_WhenNoticeExists_ShouldDeleteNotice() {
when(noticeRepository.existsById(1L)).thenReturn(true);
noticeService.deleteNotice(1L);
System.out.println("Test usunięcia ogłoszenia zakończony");
}
@Test
@DisplayName("Sprawdzenie właściciela ogłoszenia - gdy należy do klienta")
void isNoticeOwnedByClient_WhenOwned_ShouldReturnTrue() {
when(noticeRepository.existsByIdNoticeAndClientId(1L, 1L)).thenReturn(true);
boolean result = noticeService.isNoticeOwnedByClient(1L, 1L);
assertTrue(result);
System.out.println("Test sprawdzenia właściciela (true) zakończony");
}
@Test
@DisplayName("Boostowanie ogłoszenia - aktualizacja daty publikacji")
void boostNotice_ShouldUpdatePublishDate() {
when(noticeRepository.findById(1L)).thenReturn(Optional.of(sampleNotice));
when(noticeRepository.save(any(Notice.class))).thenReturn(sampleNotice);
noticeService.boostNotice(1L);
assertNotNull(sampleNotice.getPublishDate());
System.out.println("Test boostowania ogłoszenia zakończony");
}
}

View File

@@ -0,0 +1,235 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.controller.OrderController;
import _11.asktpk.artisanconnectbackend.dto.*;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.entities.Order;
import _11.asktpk.artisanconnectbackend.entities.Payment;
import _11.asktpk.artisanconnectbackend.service.OrderService;
import _11.asktpk.artisanconnectbackend.service.PaymentService;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class OrderControllerTest {
private final OrderService orderService = Mockito.mock(OrderService.class);
private final PaymentService paymentService = Mockito.mock(PaymentService.class);
private final Tools tools = Mockito.mock(Tools.class);
private final HttpServletRequest request = Mockito.mock(HttpServletRequest.class);
private OrderController orderController;
@BeforeEach
public void setUp() {
orderController = new OrderController(orderService, paymentService, tools);
}
@Test
@DisplayName("Test dodawania zamówienia")
public void testAddOrder() {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setClientId(1L);
orderDTO.setNoticeId(1L);
orderDTO.setOrderType(Enums.OrderType.ACTIVATION);
when(tools.getClientIdFromRequest(request)).thenReturn(1L);
when(orderService.addOrder(orderDTO)).thenReturn(1L);
ResponseEntity<?> response = orderController.addClient(orderDTO, request);
assertEquals(HttpStatus.CREATED, response.getStatusCode(), "Status odpowiedzi powinien być 201 CREATED");
assertEquals(1L, response.getBody(), "Ciało odpowiedzi powinno zawierać ID zamówienia");
System.out.println("Test dodawania zamówienia przeszedł pomyślnie.");
}
@Test
@DisplayName("Test zmiany statusu zamówienia")
public void testChangeStatus() {
OrderStatusDTO orderStatusDTO = new OrderStatusDTO();
orderStatusDTO.setId(1L);
orderStatusDTO.setStatus(Enums.OrderStatus.COMPLETED);
when(orderService.changeOrderStatus(1L, Enums.OrderStatus.COMPLETED)).thenReturn(1L);
ResponseEntity<?> response = orderController.changeStatus(orderStatusDTO);
assertEquals(HttpStatus.OK, response.getStatusCode(), "Status odpowiedzi powinien być 200 OK");
assertEquals(1L, response.getBody(), "Ciało odpowiedzi powinno zawierać ID zamówienia");
System.out.println("Test zmiany statusu zamówienia przeszedł pomyślnie.");
}
@Test
@DisplayName("Test pobierania tokena płatności")
public void testFetchToken() {
Long orderId = 1L;
Order order = new Order();
order.setId(orderId);
order.setAmount(10.00);
order.setOrderType(Enums.OrderType.ACTIVATION);
Client client = new Client();
client.setId(1L);
client.setEmail("test@example.com");
client.setFirstName("Jan");
client.setLastName("Kowalski");
Notice notice = new Notice();
notice.setTitle("Test Notice");
order.setClient(client);
order.setNotice(notice);
OAuthPaymentResponseDTO oAuthResponse = new OAuthPaymentResponseDTO();
oAuthResponse.setAccess_token("testAccessToken");
when(orderService.getOrderById(orderId)).thenReturn(order);
when(paymentService.getOAuthToken()).thenReturn(oAuthResponse);
when(paymentService.createTransaction(eq(order), eq("testAccessToken"), any(TransactionPaymentRequestDTO.class)))
.thenReturn("http://payment.url");
ResponseEntity<?> response = orderController.fetchToken(orderId);
assertEquals(HttpStatus.OK, response.getStatusCode(), "Status odpowiedzi powinien być 200 OK");
assertEquals("http://payment.url", response.getBody(), "Ciało odpowiedzi powinno zawierać URL płatności");
System.out.println("Test pobierania tokena płatności przeszedł pomyślnie.");
}
@Test
@DisplayName("Test pobierania wszystkich zamówień")
public void testGetAllOrders() {
Long clientId = 1L;
Order order1 = new Order();
order1.setId(1L);
order1.setOrderType(Enums.OrderType.ACTIVATION);
order1.setStatus(Enums.OrderStatus.PENDING);
order1.setAmount(10.00);
order1.setCreatedAt(LocalDateTime.now());
Order order2 = new Order();
order2.setId(2L);
order2.setOrderType(Enums.OrderType.BOOST);
order2.setStatus(Enums.OrderStatus.COMPLETED);
order2.setAmount(8.00);
order2.setCreatedAt(LocalDateTime.now());
List<Order> orders = List.of(order1, order2);
Payment payment1 = new Payment();
payment1.setIdPayment(1L);
payment1.setAmount(10.00);
payment1.setStatus(Enums.PaymentStatus.PENDING);
payment1.setTransactionPaymentUrl("http://payment.url/1");
payment1.setTransactionId("trans1");
Payment payment2 = new Payment();
payment2.setIdPayment(2L);
payment2.setAmount(8.00);
payment2.setStatus(Enums.PaymentStatus.CORRECT);
payment2.setTransactionPaymentUrl("http://payment.url/2");
payment2.setTransactionId("trans2");
when(tools.getClientIdFromRequest(request)).thenReturn(clientId);
when(orderService.getOrdersByClientId(clientId)).thenReturn(orders);
when(paymentService.getPaymentsByOrderId(1L)).thenReturn(List.of(payment1));
when(paymentService.getPaymentsByOrderId(2L)).thenReturn(List.of(payment2));
ResponseEntity<List<OrderWithPaymentsDTO>> response = orderController.getOrders(request);
assertEquals(HttpStatus.OK, response.getStatusCode(), "Status odpowiedzi powinien być 200 OK");
List<OrderWithPaymentsDTO> dtoList = response.getBody();
assertNotNull(dtoList, "Lista DTO nie powinna być null");
assertEquals(2, dtoList.size(), "Lista DTO powinna zawierać 2 elementy");
OrderWithPaymentsDTO dto1 = dtoList.getFirst();
assertEquals(1L, dto1.getOrderId(), "ID zamówienia w DTO powinno być 1");
assertEquals("ACTIVATION", dto1.getOrderType(), "Typ zamówienia w DTO powinien być ACTIVATION");
assertEquals("PENDING", dto1.getStatus(), "Status zamówienia w DTO powinien być PENDING");
assertEquals(10.00, dto1.getAmount(), "Kwota zamówienia w DTO powinna być 10.00");
assertEquals(1, dto1.getPayments().size(), "Liczba płatności w DTO powinna być 1");
System.out.println("Test pobierania wszystkich zamówień przeszedł pomyślnie.");
}
@Test
@DisplayName("Test pobierania zamówienia po ID")
public void testGetOrderById() {
Long clientId = 1L;
Long orderId = 1L;
Order order = new Order();
order.setId(orderId);
order.setOrderType(Enums.OrderType.ACTIVATION);
order.setStatus(Enums.OrderStatus.PENDING);
order.setAmount(10.00);
order.setCreatedAt(LocalDateTime.now());
Client client = new Client();
client.setId(clientId);
order.setClient(client);
Payment payment = new Payment();
payment.setIdPayment(1L);
payment.setAmount(10.00);
payment.setStatus(Enums.PaymentStatus.PENDING);
payment.setTransactionPaymentUrl("http://payment.url/1");
payment.setTransactionId("trans1");
when(tools.getClientIdFromRequest(request)).thenReturn(clientId);
when(orderService.getOrderById(orderId)).thenReturn(order);
when(paymentService.getPaymentsByOrderId(orderId)).thenReturn(List.of(payment));
ResponseEntity<OrderWithPaymentsDTO> response = orderController.getOrderById(request, orderId);
assertEquals(HttpStatus.OK, response.getStatusCode(), "Status odpowiedzi powinien być 200 OK");
OrderWithPaymentsDTO dto = response.getBody();
assertNotNull(dto, "DTO nie powinno być null");
assertEquals(orderId, dto.getOrderId(), "ID zamówienia w DTO powinno być równe podanemu");
System.out.println("Test pobierania zamówienia po ID przeszedł pomyślnie.");
}
@Test
@DisplayName("Test pobierania zamówienia po ID - brak uprawnień")
public void testGetOrderByIdForbidden() {
Long clientId = 1L;
Long orderId = 1L;
Order order = new Order();
order.setId(orderId);
order.setOrderType(Enums.OrderType.ACTIVATION);
order.setStatus(Enums.OrderStatus.PENDING);
order.setAmount(10.00);
order.setCreatedAt(LocalDateTime.now());
Client client = new Client();
client.setId(2L);
order.setClient(client);
when(tools.getClientIdFromRequest(request)).thenReturn(clientId);
when(orderService.getOrderById(orderId)).thenReturn(order);
ResponseEntity<OrderWithPaymentsDTO> response = orderController.getOrderById(request, orderId);
assertEquals(HttpStatus.FORBIDDEN, response.getStatusCode(), "Status odpowiedzi powinien być 403 FORBIDDEN");
System.out.println("Test pobierania zamówienia po ID - brak uprawnień przeszedł pomyślnie.");
}
}

View File

@@ -0,0 +1,123 @@
package _11.asktpk.artisanconnectbackend;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import _11.asktpk.artisanconnectbackend.dto.OrderDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.entities.Order;
import _11.asktpk.artisanconnectbackend.repository.ClientRepository;
import _11.asktpk.artisanconnectbackend.repository.NoticeRepository;
import _11.asktpk.artisanconnectbackend.repository.OrderRepository;
import _11.asktpk.artisanconnectbackend.service.OrderService;
import _11.asktpk.artisanconnectbackend.utils.Enums;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public class OrderServiceTest {
private final OrderRepository orderRepository = Mockito.mock(OrderRepository.class);
private final ClientRepository clientRepository = Mockito.mock(ClientRepository.class);
private final NoticeRepository noticeRepository = Mockito.mock(NoticeRepository.class);
private final OrderService orderService = new OrderService(orderRepository, clientRepository, noticeRepository);
@Test
@DisplayName("Test dodawania zamówienia")
public void testAddOrder() {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setClientId(1L);
orderDTO.setNoticeId(1L);
orderDTO.setOrderType(Enums.OrderType.ACTIVATION);
Client client = new Client();
client.setId(1L);
Notice notice = new Notice();
notice.setIdNotice(1L);
Order savedOrder = new Order();
savedOrder.setId(1L);
savedOrder.setClient(client);
savedOrder.setNotice(notice);
savedOrder.setOrderType(Enums.OrderType.ACTIVATION);
savedOrder.setStatus(Enums.OrderStatus.PENDING);
savedOrder.setAmount(10.00);
savedOrder.setCreatedAt(LocalDateTime.now());
savedOrder.setUpdatedAt(LocalDateTime.now());
when(clientRepository.findById(1L)).thenReturn(Optional.of(client));
when(noticeRepository.findById(1L)).thenReturn(Optional.of(notice));
when(orderRepository.save(any(Order.class))).thenReturn(savedOrder);
Long orderId = orderService.addOrder(orderDTO);
assertNotNull(orderId, "ID zamówienia nie powinno być null");
assertEquals(1L, orderId, "ID zamówienia powinno być równe 1");
verify(orderRepository, times(1)).save(any(Order.class));
System.out.println("Test dodawania zamówienia przeszedł pomyślnie.");
}
@Test
@DisplayName("Test zmiany statusu zamówienia")
public void testChangeOrderStatus() {
Long orderId = 1L;
Enums.OrderStatus newStatus = Enums.OrderStatus.COMPLETED;
Order existingOrder = new Order();
existingOrder.setId(orderId);
existingOrder.setStatus(Enums.OrderStatus.PENDING);
when(orderRepository.findById(orderId)).thenReturn(Optional.of(existingOrder));
when(orderRepository.save(any(Order.class))).thenReturn(existingOrder);
Long updatedOrderId = orderService.changeOrderStatus(orderId, newStatus);
assertNotNull(updatedOrderId, "ID zaktualizowanego zamówienia nie powinno być null");
assertEquals(orderId, updatedOrderId, "ID zaktualizowanego zamówienia powinno być równe podanemu");
assertEquals(newStatus, existingOrder.getStatus(), "Status zamówienia powinien zostać zaktualizowany");
verify(orderRepository, times(1)).save(existingOrder);
System.out.println("Test zmiany statusu zamówienia przeszedł pomyślnie.");
}
@Test
@DisplayName("Test pobierania zamówienia po ID")
public void testGetOrderById() {
Long orderId = 1L;
Order order = new Order();
order.setId(orderId);
when(orderRepository.findById(orderId)).thenReturn(Optional.of(order));
Order retrievedOrder = orderService.getOrderById(orderId);
assertNotNull(retrievedOrder, "Pobrane zamówienie nie powinno być null");
assertEquals(orderId, retrievedOrder.getId(), "ID pobranego zamówienia powinno być równe podanemu");
System.out.println("Test pobierania zamówienia po ID przeszedł pomyślnie.");
}
@Test
@DisplayName("Test pobierania zamówień po ID klienta")
public void testGetOrdersByClientId() {
Long clientId = 1L;
List<Order> orders = List.of(new Order(), new Order());
when(orderRepository.findByClientId(clientId)).thenReturn(orders);
List<Order> retrievedOrders = orderService.getOrdersByClientId(clientId);
assertNotNull(retrievedOrders, "Lista zamówień nie powinna być null");
assertEquals(2, retrievedOrders.size(), "Lista zamówień powinna zawierać 2 elementy");
System.out.println("Test pobierania zamówień po ID klienta przeszedł pomyślnie.");
}
}

View File

@@ -0,0 +1,45 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.security.JwtUtil;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class ToolsTest {
@Mock
private JwtUtil jwtUtil;
@Mock
private HttpServletRequest request;
@InjectMocks
private Tools tools;
@Test
@DisplayName("Pobieranie ID klienta z requestu - powinno zwrócić ID gdy token jest poprawny")
void getClientIdFromRequest_shouldReturnClientIdWhenTokenValid() {
System.out.println("Rozpoczęcie testu getClientIdFromRequest_shouldReturnClientIdWhenTokenValid");
String token = "valid.token.here";
Long expectedClientId = 1L;
when(request.getHeader("Authorization")).thenReturn("Bearer " + token);
when(jwtUtil.extractUserId(token)).thenReturn(expectedClientId);
Long result = tools.getClientIdFromRequest(request);
assertEquals(expectedClientId, result);
System.out.println("Test zakończony powodzeniem: Poprawnie pobrano ID klienta z tokenu");
}
}

View File

@@ -0,0 +1,129 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.controller.WishlistController;
import _11.asktpk.artisanconnectbackend.dto.NoticeResponseDTO;
import _11.asktpk.artisanconnectbackend.dto.RequestResponseDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.service.ClientService;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import _11.asktpk.artisanconnectbackend.service.WishlistService;
import _11.asktpk.artisanconnectbackend.utils.Tools;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.http.ResponseEntity;
import java.util.Collections;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class WishlistControllerTest {
@Mock
private WishlistService wishlistService;
@Mock
private ClientService clientService;
@Mock
private NoticeService noticeService;
@Mock
private Tools tools;
@Mock
private HttpServletRequest request;
@InjectMocks
private WishlistController wishlistController;
private final Long testClientId = 1L;
private final Long testNoticeId = 1L;
@BeforeEach
void setUp() {
System.out.println("[Konfiguracja] Przygotowanie środowiska testowego...");
when(tools.getClientIdFromRequest(request)).thenReturn(testClientId);
}
@Test
@DisplayName("Dodanie/Usunięcie z wishlisty - powinno zwrócić sukces gdy ogłoszenie istnieje")
void toggleWishlist_shouldReturnSuccessWhenNoticeExists() {
System.out.println("Rozpoczęcie testu toggleWishlist_shouldReturnSuccessWhenNoticeExists");
NoticeResponseDTO noticeResponse = new NoticeResponseDTO();
noticeResponse.setNoticeId(testNoticeId);
when(noticeService.getNoticeById(testNoticeId)).thenReturn(noticeResponse);
when(clientService.getClientById(testClientId)).thenReturn(new Client());
when(noticeService.getNoticeByIdEntity(testNoticeId)).thenReturn(new Notice());
when(wishlistService.toggleWishlist(any(), any())).thenReturn(true);
ResponseEntity<RequestResponseDTO> response = wishlistController.toggleWishlist(testNoticeId, request);
assertEquals(200, response.getStatusCode().value());
assertNotNull(response.getBody());
assertEquals("Wishlist entry added", response.getBody().getMessage());
System.out.println("Test zakończony powodzeniem: Poprawnie obsłużono dodanie/usunięcie z wishlisty");
}
@Test
@DisplayName("Dodanie/Usunięcie z wishlisty - powinno zwrócić błąd gdy ogłoszenie nie istnieje")
void toggleWishlist_shouldReturnBadRequestWhenNoticeNotFound() {
System.out.println("Rozpoczęcie testu toggleWishlist_shouldReturnBadRequestWhenNoticeNotFound");
when(noticeService.getNoticeById(testNoticeId)).thenReturn(null);
ResponseEntity<RequestResponseDTO> response = wishlistController.toggleWishlist(testNoticeId, request);
assertEquals(400, response.getStatusCode().value());
assertNotNull(response.getBody());
assertEquals("Notice not found", response.getBody().getMessage());
System.out.println("Test zakończony powodzeniem: Poprawnie obsłużono brak ogłoszenia");
}
@Test
@DisplayName("Pobieranie wishlisty - powinno zwrócić listę ogłoszeń")
void getWishlistForClient_shouldReturnNoticeList() {
System.out.println("Rozpoczęcie testu getWishlistForClient_shouldReturnNoticeList");
NoticeResponseDTO noticeResponse = new NoticeResponseDTO();
noticeResponse.setNoticeId(testNoticeId);
when(wishlistService.getNoticesInWishlist(testClientId)).thenReturn(Collections.singletonList(noticeResponse));
List<NoticeResponseDTO> result = wishlistController.getWishlistForClient(request);
assertNotNull(result);
assertEquals(1, result.size());
assertEquals(testNoticeId, result.getFirst().getNoticeId());
System.out.println("Test zakończony powodzeniem: Poprawnie pobrano listę ogłoszeń");
}
@Test
@DisplayName("Pobieranie wishlisty - powinno zwrócić pustą listę gdy brak wpisów")
void getWishlistForClient_shouldReturnEmptyListWhenNoEntries() {
System.out.println("Rozpoczęcie testu getWishlistForClient_shouldReturnEmptyListWhenNoEntries");
when(wishlistService.getNoticesInWishlist(testClientId)).thenReturn(Collections.emptyList());
List<NoticeResponseDTO> result = wishlistController.getWishlistForClient(request);
assertNotNull(result);
assertTrue(result.isEmpty());
System.out.println("Test zakończony powodzeniem: Poprawnie zwrócono pustą wishlistę");
}
}

View File

@@ -0,0 +1,126 @@
package _11.asktpk.artisanconnectbackend;
import _11.asktpk.artisanconnectbackend.dto.NoticeResponseDTO;
import _11.asktpk.artisanconnectbackend.entities.Client;
import _11.asktpk.artisanconnectbackend.entities.Notice;
import _11.asktpk.artisanconnectbackend.entities.Wishlist;
import _11.asktpk.artisanconnectbackend.repository.WishlistRepository;
import _11.asktpk.artisanconnectbackend.service.NoticeService;
import _11.asktpk.artisanconnectbackend.service.WishlistService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;
@ExtendWith(MockitoExtension.class)
class WishlistServiceTest {
@Mock
private WishlistRepository wishlistRepository;
@Mock
private NoticeService noticeService;
@InjectMocks
private WishlistService wishlistService;
private Client testClient;
private Notice testNotice;
private Wishlist testWishlist;
@BeforeEach
void setUp() {
System.out.println("Przygotowanie danych testowych...");
testClient = new Client();
testClient.setId(1L);
testClient.setEmail("test@example.com");
testNotice = new Notice();
testNotice.setIdNotice(1L);
testNotice.setTitle("Test Notice");
testWishlist = new Wishlist();
testWishlist.setId(1L);
testWishlist.setClient(testClient);
testWishlist.setNotice(testNotice);
System.out.println("[Konfiguracja] Dane testowe gotowe");
}
@Test
@DisplayName("Przełączanie wishlisty - powinno dodać gdy wpis nie istnieje")
void toggleWishlist_shouldAddWhenNotExists() {
System.out.println("Rozpoczęcie testu toggleWishlist_shouldAddWhenNotExists");
when(wishlistRepository.findByClientAndNotice(testClient, testNotice)).thenReturn(Optional.empty());
when(wishlistRepository.save(any(Wishlist.class))).thenReturn(testWishlist);
boolean result = wishlistService.toggleWishlist(testClient, testNotice);
assertTrue(result);
verify(wishlistRepository, times(1)).save(any(Wishlist.class));
System.out.println("Test zakończony powodzeniem: Poprawnie dodano do wishlisty");
}
@Test
@DisplayName("Przełączanie wishlisty - powinno usunąć gdy wpis istnieje")
void toggleWishlist_shouldRemoveWhenExists() {
System.out.println("Rozpoczęcie testu toggleWishlist_shouldRemoveWhenExists");
when(wishlistRepository.findByClientAndNotice(testClient, testNotice)).thenReturn(Optional.of(testWishlist));
boolean result = wishlistService.toggleWishlist(testClient, testNotice);
assertFalse(result);
verify(wishlistRepository, times(1)).delete(testWishlist);
System.out.println("Test zakończony powodzeniem: Poprawnie usunięto z wishlisty");
}
@Test
@DisplayName("Pobieranie ogłoszeń z wishlisty - powinno zwrócić listę ogłoszeń")
void getNoticesInWishlist_shouldReturnNoticeList() {
System.out.println("Rozpoczęcie testu getNoticesInWishlist_shouldReturnNoticeList");
List<Wishlist> wishlistEntries = new ArrayList<>();
wishlistEntries.add(testWishlist);
when(wishlistRepository.findAllByClientId(1L)).thenReturn(wishlistEntries);
when(noticeService.getNoticeById(1L)).thenReturn(new NoticeResponseDTO());
List<NoticeResponseDTO> result = wishlistService.getNoticesInWishlist(1L);
assertNotNull(result);
assertEquals(1, result.size());
System.out.println(" Test zakończony powodzeniem: Poprawnie zwrócono listę ogłoszeń");
}
@Test
@DisplayName("Pobieranie ogłoszeń z wishlisty - powinno zwrócić pustą listę gdy brak wpisów")
void getNoticesInWishlist_shouldReturnEmptyListWhenNoEntries() {
System.out.println("Rozpoczęcie testu getNoticesInWishlist_shouldReturnEmptyListWhenNoEntries");
when(wishlistRepository.findAllByClientId(1L)).thenReturn(new ArrayList<>());
List<NoticeResponseDTO> result = wishlistService.getNoticesInWishlist(1L);
assertNotNull(result);
assertTrue(result.isEmpty());
System.out.println("Test zakończony powodzeniem: Poprawnie zwrócono pustą listę");
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

BIN
src/test/resources/test.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

BIN
src/test/resources/test.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 KiB

View File

@@ -0,0 +1,122 @@
<mxfile host="Electron" agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/26.2.2 Chrome/134.0.6998.178 Electron/35.1.2 Safari/537.36" version="26.2.2">
<diagram name="Strona-1" id="y3JY7GFactLq4jGyxg2V">
<mxGraphModel dx="2180" dy="884" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="Ht36qwYIb0A0iwGBjog0-3" value="&lt;font style=&quot;font-size: 15px;&quot;&gt;&lt;b&gt;Backend&lt;/b&gt;&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#f5f5f5;fillStyle=auto;strokeColor=#666666;shadow=0;glass=0;fontColor=#333333;" vertex="1" parent="1">
<mxGeometry x="270" y="520" width="534" height="270" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-4" value="&lt;font style=&quot;font-size: 15px;&quot;&gt;&lt;b&gt;Backend&lt;/b&gt;&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#f5f5f5;fillStyle=auto;strokeColor=#666666;shadow=0;glass=0;fontColor=#333333;" parent="1" vertex="1">
<mxGeometry x="324" y="100" width="470" height="230" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="HPrCYg6BNmEDSauX9FRR-2" target="HPrCYg6BNmEDSauX9FRR-7" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-2" value="Postman" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="34" y="250" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="HPrCYg6BNmEDSauX9FRR-7" target="HPrCYg6BNmEDSauX9FRR-10" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-7" value="Controller" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="364" y="250" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" parent="1" source="HPrCYg6BNmEDSauX9FRR-10" target="HPrCYg6BNmEDSauX9FRR-11" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-10" value="Service" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="554" y="250" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-11" value="Repository" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="664" y="130" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-17" value="DTO" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="504" y="270" width="30" height="20" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-19" value="Entity" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="704" y="230" width="40" height="20" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-1" value="DTO" style="rounded=0;whiteSpace=wrap;html=1;" parent="1" vertex="1">
<mxGeometry x="224" y="270" width="40" height="20" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-44" value="Przesyłanie danych na serwer" style="text;strokeColor=none;fillColor=none;html=1;fontSize=24;fontStyle=1;verticalAlign=middle;align=center;" parent="1" vertex="1">
<mxGeometry x="226" y="40" width="376" height="40" as="geometry" />
</mxCell>
<mxCell id="HPrCYg6BNmEDSauX9FRR-50" value="" style="sketch=0;pointerEvents=1;shadow=0;dashed=0;html=1;strokeColor=none;fillColor=#DF8C42;labelPosition=center;verticalLabelPosition=bottom;verticalAlign=top;align=center;outlineConnect=0;shape=mxgraph.veeam2.restful_api;" parent="1" vertex="1">
<mxGeometry x="10" y="10" width="80" height="80" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-1" value="Przesyłanie zdjęć na backend" style="text;strokeColor=none;fillColor=none;html=1;fontSize=24;fontStyle=1;verticalAlign=middle;align=center;" vertex="1" parent="1">
<mxGeometry x="194" y="460" width="440" height="40" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-6" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="Ht36qwYIb0A0iwGBjog0-2" target="Ht36qwYIb0A0iwGBjog0-4">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-2" value="Postman" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="-20" y="625" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-7" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="Ht36qwYIb0A0iwGBjog0-4" target="Ht36qwYIb0A0iwGBjog0-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-4" value="ImageController&lt;div&gt;(Validation)&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="307" y="625" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-5" value="ImageService" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;align=center;" vertex="1" parent="1">
<mxGeometry x="550" y="580" width="196" height="150" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-9" value="MultipartFile + PathVariable" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="140" y="640" width="110" height="30" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-17" value="saveImageToStorage()" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="580" y="620" width="136" height="30" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-18" value="addImageNameToDB()" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="582" y="680" width="132" height="30" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-20" value="Pobieranie zdjęć z backendu" style="text;strokeColor=none;fillColor=none;html=1;fontSize=24;fontStyle=1;verticalAlign=middle;align=center;" vertex="1" parent="1">
<mxGeometry x="194" y="1010" width="440" height="40" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-22" value="&lt;font style=&quot;font-size: 15px;&quot;&gt;&lt;b&gt;Backend&lt;/b&gt;&lt;/font&gt;" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;fillColor=#f5f5f5;fillStyle=auto;strokeColor=#666666;shadow=0;glass=0;fontColor=#333333;" vertex="1" parent="1">
<mxGeometry x="260" y="1079" width="534" height="290" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-29" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0.75;exitDx=0;exitDy=0;entryX=0;entryY=0.75;entryDx=0;entryDy=0;" edge="1" parent="1" source="Ht36qwYIb0A0iwGBjog0-23" target="Ht36qwYIb0A0iwGBjog0-26">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-30" value="GetRequest" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Ht36qwYIb0A0iwGBjog0-29">
<mxGeometry x="0.2401" relative="1" as="geometry">
<mxPoint x="-19" as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-23" value="Postman" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="-110" y="1197" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-24" value="/api/v1/images/get/{filename}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="-135" y="1160" width="170" height="30" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-35" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.25;exitDx=0;exitDy=0;entryX=1;entryY=0.25;entryDx=0;entryDy=0;" edge="1" parent="1" source="Ht36qwYIb0A0iwGBjog0-26" target="Ht36qwYIb0A0iwGBjog0-23">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-36" value="MultipartFile(content-type image/jpeg)" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" vertex="1" connectable="0" parent="Ht36qwYIb0A0iwGBjog0-35">
<mxGeometry x="0.0779" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-26" value="ImageController" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="294" y="1197" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-37" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" edge="1" parent="1" source="Ht36qwYIb0A0iwGBjog0-31" target="Ht36qwYIb0A0iwGBjog0-26">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-31" value="ImageService" style="rounded=0;whiteSpace=wrap;html=1;verticalAlign=top;align=center;" vertex="1" parent="1">
<mxGeometry x="534" y="1152" width="196" height="150" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-32" value="getImage()" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="564" y="1209" width="136" height="30" as="geometry" />
</mxCell>
<mxCell id="Ht36qwYIb0A0iwGBjog0-38" value="/api/v1/images/upload/{noticeID}" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="-60" y="590" width="200" height="30" as="geometry" />
</mxCell>
</root>
</mxGraphModel>
</diagram>
</mxfile>