добавлена работа со списками продуктов, попытка оптимизировать запрос по поиску коктейлей
This commit is contained in:
0
front/.env
Normal file
0
front/.env
Normal file
@@ -1,5 +1,3 @@
|
|||||||
FROM nginx:1.16.0-alpine
|
FROM nginx:1.16.0-alpine
|
||||||
COPY default.conf /etc/nginx/conf.d
|
|
||||||
COPY build /usr/share/nginx/html
|
|
||||||
EXPOSE 80
|
EXPOSE 80
|
||||||
CMD ["nginx", "-g", "daemon off;"]
|
CMD ["nginx", "-g", "daemon off;"]
|
||||||
@@ -41,7 +41,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "react-scripts start",
|
"start": "react-scripts start",
|
||||||
"build": "CI=false && react-scripts build",
|
"build": "react-scripts build",
|
||||||
"test": "react-scripts test",
|
"test": "react-scripts test",
|
||||||
"eject": "react-scripts eject"
|
"eject": "react-scripts eject"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,9 +41,6 @@ export function PublicLayout({ children }) {
|
|||||||
Добро пожаловать в бар
|
Добро пожаловать в бар
|
||||||
</Box>
|
</Box>
|
||||||
</Typography>
|
</Typography>
|
||||||
<Typography align="center" variant="subtitle1">
|
|
||||||
Самый большой выбор честно спизженных коктейлей
|
|
||||||
</Typography>
|
|
||||||
<Box
|
<Box
|
||||||
component="img"
|
component="img"
|
||||||
alt="Under development"
|
alt="Under development"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import Box from "@mui/material/Box";
|
|||||||
import Typography from "@mui/material/Typography";
|
import Typography from "@mui/material/Typography";
|
||||||
import Toolbar from "@mui/material/Toolbar";
|
import Toolbar from "@mui/material/Toolbar";
|
||||||
import Paper from "@mui/material/Paper";
|
import Paper from "@mui/material/Paper";
|
||||||
import {Fab, FormControl, FormControlLabel, InputAdornment, InputLabel, OutlinedInput, Tabs} from "@mui/material";
|
import {Fab, FormControl, InputAdornment, InputLabel, OutlinedInput, Tabs} from "@mui/material";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import SearchIcon from "@mui/icons-material/Search";
|
import SearchIcon from "@mui/icons-material/Search";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
@@ -18,7 +18,6 @@ import {CustomTabPanel} from "../../../components/core/TabPanel";
|
|||||||
import {IngredientList} from "../../../components/Ingredients/IngredientList";
|
import {IngredientList} from "../../../components/Ingredients/IngredientList";
|
||||||
import {blue} from "@mui/material/colors";
|
import {blue} from "@mui/material/colors";
|
||||||
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
import UpIcon from "@mui/icons-material/KeyboardArrowUp";
|
||||||
import Switch from "@mui/material/Switch";
|
|
||||||
import {useSelect} from "../../../hooks/useSelect";
|
import {useSelect} from "../../../hooks/useSelect";
|
||||||
|
|
||||||
export function IngredientsPage() {
|
export function IngredientsPage() {
|
||||||
@@ -28,7 +27,7 @@ export function IngredientsPage() {
|
|||||||
const [findString, setFindString] = useState("");
|
const [findString, setFindString] = useState("");
|
||||||
const [ingredients, setIngredients] = useState([]);
|
const [ingredients, setIngredients] = useState([]);
|
||||||
const {getIngredient, selectIngredient} = useSelect();
|
const {getIngredient, selectIngredient} = useSelect();
|
||||||
const {createError} = useAlert();
|
const {createError, createSuccess} = useAlert();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
api().get(requests.bar.ingredientList)
|
api().get(requests.bar.ingredientList)
|
||||||
@@ -77,6 +76,14 @@ export function IngredientsPage() {
|
|||||||
const handleOpenModal = (i) => {
|
const handleOpenModal = (i) => {
|
||||||
selectIngredient(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 (
|
return (
|
||||||
<Box>
|
<Box>
|
||||||
@@ -136,7 +143,7 @@ export function IngredientsPage() {
|
|||||||
{/*Загрузчик*/}
|
{/*Загрузчик*/}
|
||||||
<Loading loading={loading}/>
|
<Loading loading={loading}/>
|
||||||
{/*Модальное окно информации об ингредиенте*/}
|
{/*Модальное окно информации об ингредиенте*/}
|
||||||
<IngredientInfoModal ingredient={getIngredient()}/>
|
<IngredientInfoModal ingredient={getIngredient()} handleDelete={handleDelete}/>
|
||||||
</Box>
|
</Box>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
39
front/src/components/Ingredients/IngredientAlert.js
Normal file
39
front/src/components/Ingredients/IngredientAlert.js
Normal file
@@ -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 (
|
||||||
|
<React.Fragment>
|
||||||
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
aria-labelledby="Предупреждение об удалении"
|
||||||
|
aria-describedby="alert-dialog-description"
|
||||||
|
>
|
||||||
|
<DialogTitle id="alert-dialog-title">
|
||||||
|
{"Вы готовы удалить ингредиент?"}
|
||||||
|
</DialogTitle>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogContentText id="alert-dialog-description">
|
||||||
|
После удаления ингредиента, удаляться все рецепты и коктейли связанные с ним!
|
||||||
|
</DialogContentText>
|
||||||
|
</DialogContent>
|
||||||
|
<DialogActions>
|
||||||
|
<Button onClick={handleClose}>Отмена</Button>
|
||||||
|
<Button color='error' onClick={() => {
|
||||||
|
handleClose();
|
||||||
|
handleCloseParent();
|
||||||
|
handleDelete(id)
|
||||||
|
}} autoFocus>
|
||||||
|
Удалить
|
||||||
|
</Button>
|
||||||
|
</DialogActions>
|
||||||
|
</Dialog>
|
||||||
|
</React.Fragment>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -13,11 +13,19 @@ import {requests} from "../../requests";
|
|||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
import ListItem from "@mui/material/ListItem";
|
import ListItem from "@mui/material/ListItem";
|
||||||
import {useSelect} from "../../hooks/useSelect";
|
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 [cocktails, setCocktails] = useState([]);
|
||||||
const {closeIngredient, getOpenIngredient, selectCocktail} = useSelect();
|
const {closeIngredient, getOpenIngredient, selectCocktail} = useSelect();
|
||||||
const {createError} = useAlert();
|
const {createError} = useAlert();
|
||||||
|
const [open, setOpen] = React.useState(false);
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setOpen(false);
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if(!ingredient) {
|
if(!ingredient) {
|
||||||
@@ -72,8 +80,10 @@ export function IngredientInfoModal({ingredient}) {
|
|||||||
)}
|
)}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
<Button onClick={closeIngredient}>Close</Button>
|
{user.role !== 'USER' && <Button onClick={() => setOpen(true)}>Удалить</Button>}
|
||||||
|
<Button onClick={closeIngredient}>Закрыть</Button>
|
||||||
</DialogActions>
|
</DialogActions>
|
||||||
|
<IngredientAlert handleDelete={handleDelete} handleClose={handleClose} open={open} id={ingredient.id} handleCloseParent={closeIngredient}/>
|
||||||
</Dialog>
|
</Dialog>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -12,6 +12,7 @@ import DeleteIcon from '@mui/icons-material/Delete';
|
|||||||
import LocalBarIcon from '@mui/icons-material/LocalBar';
|
import LocalBarIcon from '@mui/icons-material/LocalBar';
|
||||||
import {paths} from "../../path";
|
import {paths} from "../../path";
|
||||||
import {useAlert} from "../../hooks/useAlert";
|
import {useAlert} from "../../hooks/useAlert";
|
||||||
|
import {useUser} from "../../hooks/useUser";
|
||||||
|
|
||||||
function renderFavouriteBadge(handleFavourite, row) {
|
function renderFavouriteBadge(handleFavourite, row) {
|
||||||
const childIcon = row.rating.favourite ? <FavoriteIcon/> : <FavoriteBorderIcon/>;
|
const childIcon = row.rating.favourite ? <FavoriteIcon/> : <FavoriteBorderIcon/>;
|
||||||
@@ -35,6 +36,7 @@ function renderRating(handleChangeRating, row) {
|
|||||||
|
|
||||||
export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect, deleteHandler}) {
|
export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect, deleteHandler}) {
|
||||||
const {notImplement} = useAlert();
|
const {notImplement} = useAlert();
|
||||||
|
const {user} = useUser();
|
||||||
return (
|
return (
|
||||||
<Grid item sx={{pr: 2}}>
|
<Grid item sx={{pr: 2}}>
|
||||||
<CocktailItemStyled>
|
<CocktailItemStyled>
|
||||||
@@ -63,12 +65,17 @@ export function Cocktail({row, handleFavourite, handleChangeRating, handleSelect
|
|||||||
{renderFavouriteBadge(handleFavourite, row)}
|
{renderFavouriteBadge(handleFavourite, row)}
|
||||||
{renderRating(handleChangeRating, row)}
|
{renderRating(handleChangeRating, row)}
|
||||||
|
|
||||||
|
{user.role !== 'USER' &&
|
||||||
|
<>
|
||||||
<IconButton size='small' href={`${paths.bar.cocktailEdit}?id=${row.id}`}>
|
<IconButton size='small' href={`${paths.bar.cocktailEdit}?id=${row.id}`}>
|
||||||
<EditIcon fontSize='small'/>
|
<EditIcon fontSize='small'/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
<IconButton size='small' onClick={() => deleteHandler(row)}>
|
<IconButton size='small' onClick={() => deleteHandler(row)}>
|
||||||
<DeleteIcon fontSize='small'/>
|
<DeleteIcon fontSize='small'/>
|
||||||
</IconButton>
|
</IconButton>
|
||||||
|
</>
|
||||||
|
|
||||||
|
}
|
||||||
</CardActions>
|
</CardActions>
|
||||||
<CardContent sx={{pb: 0, pl: 2, pt: 0}}>
|
<CardContent sx={{pb: 0, pl: 2, pt: 0}}>
|
||||||
<Typography variant="h5" minHeight={'50px'} mt={2}>{row.name} </Typography>
|
<Typography variant="h5" minHeight={'50px'} mt={2}>{row.name} </Typography>
|
||||||
|
|||||||
@@ -86,7 +86,6 @@ function userDescriptor(user, session) {
|
|||||||
<>
|
<>
|
||||||
<Typography variant="subtitle1">{user.name + " " + user.lastName}</Typography>
|
<Typography variant="subtitle1">{user.name + " " + user.lastName}</Typography>
|
||||||
<Typography color="text.secondary" variant="body2">{user.id}</Typography>
|
<Typography color="text.secondary" variant="body2">{user.id}</Typography>
|
||||||
<Typography color="text.secondary" variant="body2">{`Бар ${open}`}</Typography>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import {tokenUtil} from "../TokenUtil";
|
import {tokenUtil} from "../TokenUtil";
|
||||||
|
|
||||||
// const host = "localhost:8080"; //дебаг вместе с беком
|
const host = "localhost:8080"; //дебаг вместе с беком
|
||||||
// const host = "192.168.1.100:8091"; //дебаг фронта
|
// const host = "192.168.1.100:8091"; //дебаг фронта
|
||||||
const host = "bar.kayashov.keenetic.pro"; //прод
|
// const host = "bar.kayashov.keenetic.pro"; //прод
|
||||||
export const api = () => {
|
export const api = () => {
|
||||||
const result = axios;
|
const result = axios;
|
||||||
result.defaults.baseURL = `${window.location.protocol}//${host}/`;
|
result.defaults.baseURL = `${window.location.protocol}//${host}/`;
|
||||||
|
|||||||
@@ -79,9 +79,7 @@ public class BarController {
|
|||||||
@GetMapping("/getMe")
|
@GetMapping("/getMe")
|
||||||
public VisitorResponseDto getMe() {
|
public VisitorResponseDto getMe() {
|
||||||
Visitor visitor = visitorService.getCurrentVisitor();
|
Visitor visitor = visitorService.getCurrentVisitor();
|
||||||
String role;
|
VisitorResponseDto dto = VisitorResponseDto.mapToDto(visitor, true, visitor.getRole().toString(), true);
|
||||||
role = UserRole.ADMIN.toString();
|
|
||||||
VisitorResponseDto dto = VisitorResponseDto.mapToDto(visitor, true, role, true);
|
|
||||||
log.info("Запрос информации о пользователе: {}-{} {}, вошел в бар",
|
log.info("Запрос информации о пользователе: {}-{} {}, вошел в бар",
|
||||||
dto.getId(),
|
dto.getId(),
|
||||||
dto.getName().strip(),
|
dto.getName().strip(),
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import org.springframework.web.bind.annotation.CrossOrigin;
|
|||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PatchMapping;
|
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.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -64,6 +65,11 @@ public class IngredientController {
|
|||||||
ingredientService.changeBarIngredient(id, false);
|
ingredientService.changeBarIngredient(id, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("/{id}")
|
||||||
|
public void removeIngredient(@PathVariable Long id) {
|
||||||
|
ingredientService.removeIngredient(id);
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public void putIngredient(@RequestParam Long id) {
|
public void putIngredient(@RequestParam Long id) {
|
||||||
ingredientService.changeBarIngredient(id, true);
|
ingredientService.changeBarIngredient(id, true);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import lombok.Getter;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
@@ -43,7 +44,7 @@ public class IngredientEntity {
|
|||||||
@JoinColumn(name = "type")
|
@JoinColumn(name = "type")
|
||||||
private TypeEntity type;
|
private TypeEntity type;
|
||||||
|
|
||||||
@ManyToMany
|
@ManyToMany(cascade = CascadeType.REMOVE)
|
||||||
@JoinTable(
|
@JoinTable(
|
||||||
name = "bar_ingredient",
|
name = "bar_ingredient",
|
||||||
joinColumns = @JoinColumn(name = "ingredient"),
|
joinColumns = @JoinColumn(name = "ingredient"),
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import org.springframework.security.core.userdetails.UserDetails;
|
|||||||
|
|
||||||
import javax.persistence.CascadeType;
|
import javax.persistence.CascadeType;
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.EnumType;
|
||||||
|
import javax.persistence.Enumerated;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@@ -21,6 +23,8 @@ public class Visitor implements UserDetails {
|
|||||||
private Long id;
|
private Long id;
|
||||||
private String name;
|
private String name;
|
||||||
private String lastName;
|
private String lastName;
|
||||||
|
@Enumerated(EnumType.STRING)
|
||||||
|
private UserRole role;
|
||||||
private Integer code;
|
private Integer code;
|
||||||
private String login;
|
private String login;
|
||||||
private String password;
|
private String password;
|
||||||
@@ -28,7 +32,8 @@ public class Visitor implements UserDetails {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||||
return UserRole.ADMIN.getAuthorities();
|
return role.getAuthorities();
|
||||||
|
// return UserRole.ADMIN.getAuthorities();
|
||||||
// return residents.stream()
|
// return residents.stream()
|
||||||
// .filter(BarResident::getActive)
|
// .filter(BarResident::getActive)
|
||||||
// .map(BarResident::getRole)
|
// .map(BarResident::getRole)
|
||||||
|
|||||||
@@ -3,14 +3,20 @@ package ru.kayashov.bar.service;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Service;
|
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.IngredientResponseDto;
|
||||||
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
import ru.kayashov.bar.controller.dto.ingredient.IngredientSimpleResponseDto;
|
||||||
import ru.kayashov.bar.mapper.IngredientMapper;
|
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.BarEntity;
|
||||||
|
import ru.kayashov.bar.model.entity.CocktailEntity;
|
||||||
import ru.kayashov.bar.model.entity.IngredientEntity;
|
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.model.entity.TypeEntity;
|
||||||
import ru.kayashov.bar.repository.BarEntityRepository;
|
import ru.kayashov.bar.repository.BarEntityRepository;
|
||||||
|
import ru.kayashov.bar.repository.CocktailRepository;
|
||||||
import ru.kayashov.bar.repository.IngredientRepository;
|
import ru.kayashov.bar.repository.IngredientRepository;
|
||||||
|
import ru.kayashov.bar.repository.ReceiptRepository;
|
||||||
import ru.kayashov.bar.repository.TypeRepository;
|
import ru.kayashov.bar.repository.TypeRepository;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@@ -26,6 +32,8 @@ public class IngredientService {
|
|||||||
private final IngredientMapper mapper;
|
private final IngredientMapper mapper;
|
||||||
private final BarEntityRepository barEntityRepository;
|
private final BarEntityRepository barEntityRepository;
|
||||||
private final IngredientRepository ingredientRepository;
|
private final IngredientRepository ingredientRepository;
|
||||||
|
private final ReceiptRepository receiptRepository;
|
||||||
|
private final CocktailRepository cocktailRepository;
|
||||||
|
|
||||||
private TypeEntity findTypeByName(String name) {
|
private TypeEntity findTypeByName(String name) {
|
||||||
return typeRepository.findByName(name)
|
return typeRepository.findByName(name)
|
||||||
@@ -86,4 +94,21 @@ public class IngredientService {
|
|||||||
repository.save(entity);
|
repository.save(entity);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void removeIngredient(Long id) {
|
||||||
|
IngredientEntity ingredient = ingredientRepository.findById(id).orElseThrow();
|
||||||
|
|
||||||
|
List<CocktailEntity> 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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user