diff --git a/front/.env b/front/.env new file mode 100644 index 0000000..e69de29 diff --git a/front/Dockerfile b/front/Dockerfile index d9052db..4ecf20d 100644 --- a/front/Dockerfile +++ b/front/Dockerfile @@ -1,5 +1,3 @@ FROM nginx:1.16.0-alpine -COPY default.conf /etc/nginx/conf.d -COPY build /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/front/package.json b/front/package.json index 27949b9..1034a42 100644 --- a/front/package.json +++ b/front/package.json @@ -41,7 +41,7 @@ }, "scripts": { "start": "react-scripts start", - "build": "CI=false && react-scripts build", + "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" }, diff --git a/front/src/app/layout/PublicLayout.js b/front/src/app/layout/PublicLayout.js index 74aa4f6..3d3a1d9 100644 --- a/front/src/app/layout/PublicLayout.js +++ b/front/src/app/layout/PublicLayout.js @@ -41,9 +41,6 @@ export function PublicLayout({ children }) { Добро пожаловать в бар - - Самый большой выбор честно спизженных коктейлей - { api().get(requests.bar.ingredientList) @@ -77,6 +76,14 @@ export function IngredientsPage() { const handleOpenModal = (i) => { selectIngredient(i) } + const handleDelete = (id) => { + const newState = ingredients.filter((ingredient) => ingredient.id !== id); + setIngredients(newState) + + api().delete(`${requests.bar.ingredient}/${id}`) + .then((r) => createSuccess("Ингредиент удален")) + .catch(() => createError("Ошибка удаления ингредиента. Перезагрузите страницу")) + } return ( @@ -136,7 +143,7 @@ export function IngredientsPage() { {/*Загрузчик*/} {/*Модальное окно информации об ингредиенте*/} - + ) } \ No newline at end of file diff --git a/front/src/components/Ingredients/IngredientAlert.js b/front/src/components/Ingredients/IngredientAlert.js new file mode 100644 index 0000000..0f78ba4 --- /dev/null +++ b/front/src/components/Ingredients/IngredientAlert.js @@ -0,0 +1,39 @@ +import * as React from 'react'; +import Button from '@mui/material/Button'; +import Dialog from '@mui/material/Dialog'; +import DialogActions from '@mui/material/DialogActions'; +import DialogContent from '@mui/material/DialogContent'; +import DialogContentText from '@mui/material/DialogContentText'; +import DialogTitle from '@mui/material/DialogTitle'; + +export function IngredientAlert({open, handleClose, handleDelete, id, handleCloseParent}) { + return ( + + + + {"Вы готовы удалить ингредиент?"} + + + + После удаления ингредиента, удаляться все рецепты и коктейли связанные с ним! + + + + + + + + + ); +} \ No newline at end of file diff --git a/front/src/components/Ingredients/IngredientInfoModal.js b/front/src/components/Ingredients/IngredientInfoModal.js index 103ab14..65c7ec6 100644 --- a/front/src/components/Ingredients/IngredientInfoModal.js +++ b/front/src/components/Ingredients/IngredientInfoModal.js @@ -13,11 +13,19 @@ import {requests} from "../../requests"; import {useAlert} from "../../hooks/useAlert"; import ListItem from "@mui/material/ListItem"; import {useSelect} from "../../hooks/useSelect"; +import {IngredientAlert} from "./IngredientAlert"; +import {useUser} from "../../hooks/useUser"; -export function IngredientInfoModal({ingredient}) { +export function IngredientInfoModal({ingredient, handleDelete}) { + const {user} = useUser(); const [cocktails, setCocktails] = useState([]); const {closeIngredient, getOpenIngredient, selectCocktail} = useSelect(); const {createError} = useAlert(); + const [open, setOpen] = React.useState(false); + + const handleClose = () => { + setOpen(false); + }; useEffect(() => { if(!ingredient) { @@ -72,8 +80,10 @@ export function IngredientInfoModal({ingredient}) { )} - + {user.role !== 'USER' && } + + ); } \ No newline at end of file diff --git a/front/src/components/cocktails/Cocktail.js b/front/src/components/cocktails/Cocktail.js index ec82a54..6289f6a 100644 --- a/front/src/components/cocktails/Cocktail.js +++ b/front/src/components/cocktails/Cocktail.js @@ -12,6 +12,7 @@ import DeleteIcon from '@mui/icons-material/Delete'; import LocalBarIcon from '@mui/icons-material/LocalBar'; import {paths} from "../../path"; import {useAlert} from "../../hooks/useAlert"; +import {useUser} from "../../hooks/useUser"; function renderFavouriteBadge(handleFavourite, row) { const childIcon = row.rating.favourite ? : ; @@ -35,6 +36,7 @@ function renderRating(handleChangeRating, row) { export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect, deleteHandler}) { const {notImplement} = useAlert(); + const {user} = useUser(); return ( @@ -63,12 +65,17 @@ export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect {renderFavouriteBadge(handleFavourite, row)} {renderRating(handleChangeRating, row)} - - - - deleteHandler(row)}> - - + {user.role !== 'USER' && + <> + + + + deleteHandler(row)}> + + + + + } {row.name} diff --git a/front/src/components/core/UserPopover.js b/front/src/components/core/UserPopover.js index a0b2805..8c271c9 100644 --- a/front/src/components/core/UserPopover.js +++ b/front/src/components/core/UserPopover.js @@ -86,7 +86,6 @@ function userDescriptor(user, session) { <> {user.name + " " + user.lastName} {user.id} - {`Бар ${open}`} ); } diff --git a/front/src/lib/clients/api.js b/front/src/lib/clients/api.js index 7952708..d7c859a 100644 --- a/front/src/lib/clients/api.js +++ b/front/src/lib/clients/api.js @@ -1,9 +1,9 @@ import axios from "axios"; import {tokenUtil} from "../TokenUtil"; -// const host = "localhost:8080"; //дебаг вместе с беком +const host = "localhost:8080"; //дебаг вместе с беком // const host = "192.168.1.100:8091"; //дебаг фронта -const host = "bar.kayashov.keenetic.pro"; //прод +// const host = "bar.kayashov.keenetic.pro"; //прод export const api = () => { const result = axios; result.defaults.baseURL = `${window.location.protocol}//${host}/`; diff --git a/src/main/java/ru/kayashov/bar/controller/BarController.java b/src/main/java/ru/kayashov/bar/controller/BarController.java index 15a091c..d8edcad 100644 --- a/src/main/java/ru/kayashov/bar/controller/BarController.java +++ b/src/main/java/ru/kayashov/bar/controller/BarController.java @@ -79,9 +79,7 @@ public class BarController { @GetMapping("/getMe") public VisitorResponseDto getMe() { Visitor visitor = visitorService.getCurrentVisitor(); - String role; - role = UserRole.ADMIN.toString(); - VisitorResponseDto dto = VisitorResponseDto.mapToDto(visitor, true, role, true); + VisitorResponseDto dto = VisitorResponseDto.mapToDto(visitor, true, visitor.getRole().toString(), true); log.info("Запрос информации о пользователе: {}-{} {}, вошел в бар", dto.getId(), dto.getName().strip(), diff --git a/src/main/java/ru/kayashov/bar/controller/IngredientController.java b/src/main/java/ru/kayashov/bar/controller/IngredientController.java index 786cf4f..47f1b38 100644 --- a/src/main/java/ru/kayashov/bar/controller/IngredientController.java +++ b/src/main/java/ru/kayashov/bar/controller/IngredientController.java @@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -64,6 +65,11 @@ public class IngredientController { ingredientService.changeBarIngredient(id, false); } + @DeleteMapping("/{id}") + public void removeIngredient(@PathVariable Long id) { + ingredientService.removeIngredient(id); + } + @PutMapping public void putIngredient(@RequestParam Long id) { ingredientService.changeBarIngredient(id, true); diff --git a/src/main/java/ru/kayashov/bar/model/entity/IngredientEntity.java b/src/main/java/ru/kayashov/bar/model/entity/IngredientEntity.java index 9e46e77..f866d79 100644 --- a/src/main/java/ru/kayashov/bar/model/entity/IngredientEntity.java +++ b/src/main/java/ru/kayashov/bar/model/entity/IngredientEntity.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; @@ -43,7 +44,7 @@ public class IngredientEntity { @JoinColumn(name = "type") private TypeEntity type; - @ManyToMany + @ManyToMany(cascade = CascadeType.REMOVE) @JoinTable( name = "bar_ingredient", joinColumns = @JoinColumn(name = "ingredient"), diff --git a/src/main/java/ru/kayashov/bar/model/entity/Visitor.java b/src/main/java/ru/kayashov/bar/model/entity/Visitor.java index 1519670..f81b82b 100644 --- a/src/main/java/ru/kayashov/bar/model/entity/Visitor.java +++ b/src/main/java/ru/kayashov/bar/model/entity/Visitor.java @@ -7,6 +7,8 @@ import org.springframework.security.core.userdetails.UserDetails; import javax.persistence.CascadeType; import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; import javax.persistence.Id; import javax.persistence.OneToMany; import java.time.LocalDateTime; @@ -21,6 +23,8 @@ public class Visitor implements UserDetails { private Long id; private String name; private String lastName; + @Enumerated(EnumType.STRING) + private UserRole role; private Integer code; private String login; private String password; @@ -28,7 +32,8 @@ public class Visitor implements UserDetails { @Override public Collection getAuthorities() { - return UserRole.ADMIN.getAuthorities(); + return role.getAuthorities(); +// return UserRole.ADMIN.getAuthorities(); // return residents.stream() // .filter(BarResident::getActive) // .map(BarResident::getRole) diff --git a/src/main/java/ru/kayashov/bar/service/IngredientService.java b/src/main/java/ru/kayashov/bar/service/IngredientService.java index 9a9263e..77e77f3 100644 --- a/src/main/java/ru/kayashov/bar/service/IngredientService.java +++ b/src/main/java/ru/kayashov/bar/service/IngredientService.java @@ -3,14 +3,20 @@ package ru.kayashov.bar.service; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import ru.kayashov.bar.controller.dto.ingredient.IngredientResponseDto; import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto; import ru.kayashov.bar.mapper.IngredientMapper; +import ru.kayashov.bar.model.Ingredient; import ru.kayashov.bar.model.entity.BarEntity; +import ru.kayashov.bar.model.entity.CocktailEntity; import ru.kayashov.bar.model.entity.IngredientEntity; +import ru.kayashov.bar.model.entity.ReceiptEntity; import ru.kayashov.bar.model.entity.TypeEntity; import ru.kayashov.bar.repository.BarEntityRepository; +import ru.kayashov.bar.repository.CocktailRepository; import ru.kayashov.bar.repository.IngredientRepository; +import ru.kayashov.bar.repository.ReceiptRepository; import ru.kayashov.bar.repository.TypeRepository; import java.util.ArrayList; @@ -26,6 +32,8 @@ public class IngredientService { private final IngredientMapper mapper; private final BarEntityRepository barEntityRepository; private final IngredientRepository ingredientRepository; + private final ReceiptRepository receiptRepository; + private final CocktailRepository cocktailRepository; private TypeEntity findTypeByName(String name) { return typeRepository.findByName(name) @@ -86,4 +94,21 @@ public class IngredientService { repository.save(entity); return true; } + + @Transactional + public void removeIngredient(Long id) { + IngredientEntity ingredient = ingredientRepository.findById(id).orElseThrow(); + + List cocktails = ingredient.getReceipts() + .stream() + .map(ReceiptEntity::getCocktail) + .toList(); + + receiptRepository.deleteAll(ingredient.getReceipts()); + cocktailRepository.deleteAll(cocktails); + + log.info("Удалены коктейли {}", cocktails.stream().map(c -> c.getId() + "-" + c.getName()).toList()); + repository.delete(ingredient); + log.info("Удален ингредиент {}-{}", id, ingredient.getName()); + } }