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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 18 additions & 15 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
version: '3.8'
services:
mysqldb:
image: mysql:8.0.21
ports:
- "3307:3307"
environment:
MYSQL_ROOT_PASSWORD: "root"
MYSQL_DATABASE: "device_shop"
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_PASSWORD: "root"
app:
build:
context: .
dockerfile: Dockerfile
ports:
- "8081:8081"
depends_on:
- localhost

localhost:
image: mysql:8.0.21
ports:
- "3306:3306"
mysqldb:
condition: service_completed_successfully
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://localhost:3306/device_shop?serverTimezone=UTC
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: root
flyway:
build:
context: .
dockerfile: Dockerfile.flyway
depends_on:
- localhost
SPRING_APPLICATION_JSON: '{
"spring.datasource.url" : "jdbc:mysql://mysqldb:3307/device_shop?serverTimezone=UTC",
"spring.datasource.username" : "root",
"spring.datasource.password" : "root",
"spring.jpa.properties.hibernate.dialect" : "org.hibernate.dialect.MySQL5Dialect",
"spring.jpa.hibernate.ddl-auto" : "update"
}'
23 changes: 21 additions & 2 deletions src/main/java/com/device/shop/configuration/WebSecurityConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,33 @@ protected void configure(HttpSecurity http) throws Exception {
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/login", "/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html", "/resources/**", "/static/**", "/js/**", "/img/**", "/css/**", "/ui", "/products", "/product/{id}", "/search/{name}", "/create", "/cart/{id}/items", "/{sessionId}", "/cart/items/{id}").permitAll()
.antMatchers("/login",
"/v3/api-docs/**",
"/swagger-ui/**",
"/swagger-ui.html",
"/resources/**",
"/static/**",
"/js/**",
"/img/**",
"/css/**",
"/ui",
"/products",
"/upload",
"/product/{id}",
"/search/{name}",
"/create",
"/cart/{id}/items",
"/{sessionId}",
"/cart/items/{id}",
"/users"/*,
"/product"*/).permitAll()
.antMatchers(HttpMethod.POST, "/users").permitAll()
.anyRequest().authenticated();

http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}

@Bean
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();

Expand Down
20 changes: 16 additions & 4 deletions src/main/java/com/device/shop/controller/AuthController.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package com.device.shop.controller;

import com.device.shop.security.JwtUtils;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
Expand All @@ -15,17 +18,26 @@
@RestController
@AllArgsConstructor
public class AuthController {

private final AuthenticationManager authenticationManager;

private final JwtUtils jwtUtils;

@PostMapping("/login")
public ResponseEntity<String> authenticateUser(@RequestParam MultiValueMap body) {
public ResponseEntity<String> authenticateUser(
@RequestParam @Parameter(
description = "User's username",
required = true,
content = @Content(schema = @Schema(type = "string"))
) String username,
@RequestParam @Parameter(
description = "User's password",
required = true,
content = @Content(schema = @Schema(type = "string", format = "password"))
) String password) {

Authentication authentication = authenticationManager
.authenticate(new UsernamePasswordAuthenticationToken(String.valueOf(body.get("username"))
,String.valueOf(body.get("password"))));
.authenticate(new UsernamePasswordAuthenticationToken(username, password));

SecurityContextHolder.getContext().setAuthentication(authentication);
String jwt = jwtUtils.generateJwtToken(authentication);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package com.device.shop.controller;

import com.device.shop.service.ProductPhotoService;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
Expand All @@ -11,7 +13,6 @@
import java.io.IOException;

@RestController

public class ProductPhotoController {

private final ProductPhotoService productPhotoService;
Expand All @@ -22,9 +23,9 @@ public ProductPhotoController(ProductPhotoService productPhotoService) {
}

@SecurityRequirement(name = "bearerAuth")
@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping("/upload")
public ResponseEntity<Long> uploadPhoto(@RequestParam("image") MultipartFile image) throws IOException {
//@PreAuthorize("hasRole('ROLE_ADMIN')")
@PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Long> uploadPhoto(@RequestPart("image") MultipartFile image) throws IOException {
Long photoId = productPhotoService.uploadPhoto(image);
return ResponseEntity.ok(photoId);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
public class UserController {

private final UserService userService;

@SecurityRequirement(name = "bearerAuth")
@PostMapping("/users")
public ResponseEntity<UserDTO> createUser(@RequestBody UserDTO userDTO) throws BadRequestException {
UserDTO savedUserDTO = userService.createUser(userDTO);
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/device/shop/entity/CartItem.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class CartItem {
@JoinColumn(name = "session_id")
ShoppingSession shoppingSession;

@OneToOne
@ManyToOne
@JoinColumn(name = "product_id")
Product product;

Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/device/shop/mapper/ProductMapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ public ProductDTO toDTO(Product product) {
.deletedAt(product.getDeletedAt())
.discountId(Optional.ofNullable(product.getDiscount())
.map(Discount::getId)
.orElse(null))
.photoId(product.getProductPhoto().getId());
.orElse(null));

if (product.getProductPhoto() != null) {
builder.imageData(product.getProductPhoto().getPhotoData());
builder
.photoId(product.getProductPhoto().getId())
.imageData(product.getProductPhoto().getPhotoData());
}

return builder.build();
Expand All @@ -44,5 +45,4 @@ public Product toEntity(ProductDTO productDTO) {
.deletedAt(productDTO.getDeletedAt())
.build();
}

}
18 changes: 11 additions & 7 deletions src/main/java/com/device/shop/service/impl/ProductServiceImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -107,18 +107,22 @@ public void save(MultipartFile file) throws IOException, BadRequestException {
public ResponseEntity<ProductDTO> addProduct(ProductDTO productDTO) {
Product product = productMapper.toEntity(productDTO);

if (productDTO.getPhotoId() != null) {
ProductPhoto productPhoto = productPhotoRepository.findById(productDTO.getPhotoId())
.orElseThrow(() -> new EntityNotFoundException("Фото з id " + productDTO.getPhotoId() + " не знайдено"));
if (productDTO.getImageData() != null) {
ProductPhoto productPhoto = ProductPhoto.builder()
.photoData(productDTO.getImageData())
.build();
product.setProductPhoto(productPhoto);
}

Discount discount = discountRepository.findById(productDTO.getDiscountId())
.orElseThrow(() -> new EntityNotFoundException("Discount with id " + productDTO.getDiscountId() + " not found"));
product.setDiscount(discount);
if (productDTO.getDiscountId() != null) {
Discount discount = discountRepository.findById(productDTO.getDiscountId())
.orElseThrow(() -> new EntityNotFoundException("Discount with id " + productDTO.getDiscountId() + " not found"));
product.setDiscount(discount);
} else {
product.setDiscount(null);
}

productRepository.save(product);
return ResponseEntity.ok(productMapper.toDTO(product));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ public UserDTO createUser(UserDTO userDTO) throws BadRequestException {
user.setPassword(encodedPassword);

User savedUser = userRepository.save(user);
//todo move send email via spring AOP and remove flush operation
/* //todo move send email via spring AOP and remove flush operation
userRepository.flush();
try {
emailService.sendRegistrationEmail(savedUser.getEmail(), savedUser.getName());
} catch (MessagingException e) {

}
}*/

return userMapper.toDTO(savedUser);
}
Expand Down Expand Up @@ -104,7 +104,7 @@ private void validateUserFields(UserDTO userDTO) throws BadRequestException {
if (!emailMatcher.matches()) {
throw new BadRequestException("Invalid email format");
}
String phoneRegex = "^\\+380\\s\\d{2}\\s\\d{3}\\s\\d{2}\\s\\d{2}$|^\\+380-\\d{2}-\\d{3}-\\d{2}-\\d{2}$";
String phoneRegex = "^(\\+380\\s\\d{2}\\s\\d{3}\\s\\d{2}\\s\\d{2}|\\+380-\\d{2}-\\d{3}-\\d{2}-\\d{2}|\\+380\\d{9})$";
Pattern phonePattern = Pattern.compile(phoneRegex);
Matcher phoneMatcher = phonePattern.matcher(userDTO.getPhone());
if (!phoneMatcher.matches()) {
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/META-INF/MANIFEST.MF
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.device.shop.MyProjectWithSpring2Application

Binary file added src/main/resources/backup_data_only.sql
Binary file not shown.
94 changes: 94 additions & 0 deletions src/main/resources/static/js/Test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('productForm');
const submitButton = document.getElementById('submitButton');

submitButton.addEventListener('click', function () {
const formData = {
name: document.getElementById('name').value,
description: document.getElementById('description').value,
sku: document.getElementById('sku').value,
price: parseFloat(document.getElementById('price').value),
quantity: parseInt(document.getElementById('quantity').value),
};

// Отримуємо токен з локального сховища
const token = localStorage.getItem('token'); // Перед цим ви маєте зберегти токен в локальному сховищі

// Перевірка, чи є токен
if (!token) {
console.error('Токен не знайдено');
return;
}

// Відправляємо POST-запит на бекенд разом із токеном
fetch('http://localhost:8081/product', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`, // Додаємо токен до заголовків
},
body: JSON.stringify(formData),
})
.then(response => response.json())
.then(data => {
console.log('Дані успішно відправлені на бекенд:', data);
// Додайте код для відображення успішного повідомлення користувачу
})
.catch(error => {
console.error('Помилка під час відправлення запиту:', error);
// Додайте код для відображення повідомлення про помилку користувачу
});
});
});







/*

document.addEventListener('DOMContentLoaded', function () {
const form = document.getElementById('productForm');
const submitButton = document.getElementById('submitButton');

submitButton.addEventListener('click', function () {
const formData = {
name: document.getElementById('name').value,
description: document.getElementById('description').value,
sku: document.getElementById('sku').value,
price: parseFloat(document.getElementById('price').value),
quantity: parseInt(document.getElementById('quantity').value),
};

// Отримуємо токен з локального сховища
const token = localStorage.getItem('token');

// Відправляємо POST-запит на бекенд з токеном у заголовку
fetch('http://localhost:8081/product', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}` // Додаємо токен у заголовок
},
body: JSON.stringify(formData),
})
.then(response => response.json())
.then(data => {
console.log('Дані успішно відправлені на бекенд:', data);
// Додайте код для відображення успішного повідомлення користувачу
})
.catch(error => {
console.error('Помилка під час відправлення запиту:', error);
// Додайте код для відображення повідомлення про помилку користувачу
});
});
});
*/






Loading