diff --git a/build.gradle.kts b/build.gradle.kts index d40b7a7..4544a44 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,6 @@ plugins { id("java") id("org.jetbrains.kotlin.jvm") version "1.4.30" id("org.jetbrains.dokka") version "1.4.20" - id("com.leobia.gradle.sassjavacompiler") version "0.2.1" id("org.springframework.boot") version "2.3.4.RELEASE" id("org.jetbrains.kotlin.plugin.spring") version "1.4.30" id("org.jetbrains.kotlin.plugin.jpa") version "1.4.30" diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/TouchUpKitService.java b/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/TouchUpKitService.java index 24f906c..93df0aa 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/TouchUpKitService.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/TouchUpKitService.java @@ -1,6 +1,5 @@ package dev.fyloz.colorrecipesexplorer.service.files; -import dev.fyloz.colorrecipesexplorer.utils.PdfBuilder; import dev.fyloz.colorrecipesexplorer.utils.PdfBuilder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.ResourceLoader; @@ -15,7 +14,7 @@ public class TouchUpKitService { private static final String TOUCH_UP_EN = "TOUCH UP KIT"; public static final int FONT_SIZE = 42; - private ResourceLoader resourceLoader; + private final ResourceLoader resourceLoader; @Autowired public TouchUpKitService(ResourceLoader resourceLoader) { diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/XlsService.java b/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/XlsService.java index 0083e8b..50553b6 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/XlsService.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/service/files/XlsService.java @@ -1,8 +1,5 @@ package dev.fyloz.colorrecipesexplorer.service.files; -import dev.fyloz.colorrecipesexplorer.model.Recipe; -import dev.fyloz.colorrecipesexplorer.service.RecipeService; -import dev.fyloz.colorrecipesexplorer.xlsx.XlsxExporter; import dev.fyloz.colorrecipesexplorer.model.Recipe; import dev.fyloz.colorrecipesexplorer.service.RecipeService; import dev.fyloz.colorrecipesexplorer.xlsx.XlsxExporter; @@ -19,8 +16,8 @@ import java.util.zip.ZipOutputStream; @Service public class XlsService { - private RecipeService recipeService; - private Logger logger; + private final RecipeService recipeService; + private final Logger logger; @Autowired public XlsService(RecipeService recipeService, Logger logger) { diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/utils/PdfBuilder.java b/src/main/java/dev/fyloz/colorrecipesexplorer/utils/PdfBuilder.java index 559ab00..39ea4ec 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/utils/PdfBuilder.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/utils/PdfBuilder.java @@ -16,14 +16,14 @@ public class PdfBuilder { private static final String PATH_FONT_ARIAL_BOLD = "classpath:fonts/arialbd.ttf"; - private PDFont font; - private PDDocument document = new PDDocument(); - private PDPage page = new PDPage(); - private Collection lines = new ArrayList<>(); - private boolean duplicated; - private int fontSize; - private int fontSizeBold; - private int lineSpacing; + private final PDFont font; + private final PDDocument document = new PDDocument(); + private final PDPage page = new PDPage(); + private final Collection lines = new ArrayList<>(); + private final boolean duplicated; + private final int fontSize; + private final int fontSizeBold; + private final int lineSpacing; public PdfBuilder(ResourceLoader resourceLoader, boolean duplicated, int fontSize) throws IOException { this.duplicated = duplicated; diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/XlsxExporter.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/XlsxExporter.java index 05dbab1..79b54e4 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/XlsxExporter.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/XlsxExporter.java @@ -1,22 +1,12 @@ package dev.fyloz.colorrecipesexplorer.xlsx; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Sheet; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Table; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.DescriptionCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.SectionTitleCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.TitleCell; -import dev.fyloz.colorrecipesexplorer.xlsx.util.Position; import dev.fyloz.colorrecipesexplorer.model.Mix; import dev.fyloz.colorrecipesexplorer.model.MixMaterial; import dev.fyloz.colorrecipesexplorer.model.Recipe; -import dev.fyloz.colorrecipesexplorer.model.RecipeStep; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Catalog; import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; import dev.fyloz.colorrecipesexplorer.xlsx.component.Sheet; import dev.fyloz.colorrecipesexplorer.xlsx.component.Table; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.DescriptionCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.NoteCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.SectionTitleCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.TitleCell; import dev.fyloz.colorrecipesexplorer.xlsx.util.Position; @@ -27,7 +17,7 @@ import java.io.IOException; import java.util.Collection; public class XlsxExporter { - private Logger logger; + private final Logger logger; public XlsxExporter(Logger logger) { this.logger = logger; diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/CellBuilder.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/CellBuilder.java index 658b2fa..1020043 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/CellBuilder.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/CellBuilder.java @@ -1,10 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.builder; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; -import dev.fyloz.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; @@ -18,9 +13,9 @@ import org.apache.poi.xssf.usermodel.XSSFFont; public class CellBuilder { - private Document document; - private Cell cell; - private XSSFCell xcell; + private final Document document; + private final Cell cell; + private final XSSFCell xcell; public CellBuilder(Document document, Cell cell, int x, int y) { this.document = document; diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/SheetBuilder.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/SheetBuilder.java index 020135c..1947319 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/SheetBuilder.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/builder/SheetBuilder.java @@ -1,10 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.builder; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Sheet; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; import dev.fyloz.colorrecipesexplorer.xlsx.component.Sheet; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; @@ -15,8 +10,8 @@ import org.apache.poi.ss.util.CellRangeAddress; public class SheetBuilder { - private Sheet sheet; - private Iterable cells; + private final Sheet sheet; + private final Iterable cells; public SheetBuilder(Sheet sheet) { this.sheet = sheet; diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Catalog.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Catalog.java index c8fea6f..4e8bc2b 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Catalog.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Catalog.java @@ -1,8 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; @@ -14,7 +11,7 @@ import java.util.List; public class Catalog { - private List content; + private final List content; public Catalog() { content = new ArrayList<>(); @@ -39,7 +36,7 @@ public class Catalog { private class CatalogValueCell extends Cell implements IBiggerCell, IFontCell { - private String value; + private final String value; public CatalogValueCell(String value) { super(CellType.STRING); diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Document.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Document.java index a29e9c3..ad27dcb 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Document.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Document.java @@ -1,6 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component; -import dev.fyloz.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; import dev.fyloz.colorrecipesexplorer.xlsx.builder.SheetBuilder; import dev.fyloz.colorrecipesexplorer.xlsx.exception.InvalidCellTypeException; import org.apache.poi.xssf.usermodel.XSSFWorkbook; @@ -12,8 +11,8 @@ public class Document extends XSSFWorkbook { public static final int WIDTH = 8; private static final XSSFWorkbookType WORKBOOK_TYPE = XSSFWorkbookType.XLSX; - private Sheet sheet; - private Logger logger; + private final Sheet sheet; + private final Logger logger; public Document(String name, Logger logger) { super(WORKBOOK_TYPE); diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Sheet.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Sheet.java index a576e66..77cba39 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Sheet.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Sheet.java @@ -1,6 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.xssf.usermodel.XSSFCell; @@ -11,11 +10,11 @@ import java.util.*; public class Sheet { - private Document document; - private XSSFSheet xsheet; + private final Document document; + private final XSSFSheet xsheet; - private Map rows; - private List registeredCells; + private final Map rows; + private final List registeredCells; Sheet(Document document, XSSFSheet xsheet) { this.document = document; diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Table.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Table.java index 7973c59..4fc2c6f 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Table.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/Table.java @@ -1,10 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; -import dev.fyloz.colorrecipesexplorer.xlsx.exception.IndexOutOfTableBoundsException; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.Cell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; @@ -19,16 +14,16 @@ import java.util.*; public class Table { - private static DecimalFormat format = new DecimalFormat("#.###"); + private static final DecimalFormat format = new DecimalFormat("#.###"); - private int width; - private int height; - private int cellWidth; + private final int width; + private final int height; + private final int cellWidth; - private Map content; + private final Map content; - private List columns; - private List rows; + private final List columns; + private final List rows; public Table(int width, int height, String name) { this.width = width; @@ -140,9 +135,9 @@ public class Table { private final IndexedColors COLOR = IndexedColors.GREY_40_PERCENT; - private String name; - private int width; - private int height = 2; + private final String name; + private final int width; + private final int height = 2; public TableNameCell(String name, int width) { super(CellType.STRING); @@ -175,8 +170,8 @@ public class Table { private class TableSubNameCell extends Cell implements IFontCell, IBiggerCell, IColoredCell { private String name; - private int width; - private int height = 2; + private final int width; + private final int height = 2; public TableSubNameCell(String name, int width) { super(CellType.STRING); @@ -212,9 +207,9 @@ public class Table { private class TableStringValueCell extends Cell implements IFontCell, IBiggerCell { - private String value; - private int width; - private int height = 2; + private final String value; + private final int width; + private final int height = 2; public TableStringValueCell(String value, int width) { super(CellType.STRING); @@ -246,9 +241,9 @@ public class Table { private class TableNumValueCell extends Cell implements IFontCell, IBiggerCell { - private double value; - private int width; - private int height = 2; + private final double value; + private final int width; + private final int height = 2; public TableNumValueCell(double value, int width) { super(CellType.NUMERIC); diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java index 87af00b..0184fc3 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/DescriptionCell.java @@ -1,8 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component.cells; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; @@ -17,7 +14,7 @@ public class DescriptionCell extends Cell implements IColoredCell, IBiggerCell, private static final IndexedColors BG_COLOR_NAME = IndexedColors.GREY_40_PERCENT; private static final short FONT_HEIGHT = 18; - private DescriptionCellType type; + private final DescriptionCellType type; private String valueStr; private double valueNbr; diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/NoteCell.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/NoteCell.java index 7b81584..998f129 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/NoteCell.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/NoteCell.java @@ -1,7 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component.cells; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; @@ -9,7 +7,7 @@ import org.apache.poi.ss.usermodel.CellType; public class NoteCell extends Cell implements IBiggerCell, IFontCell { - private String value; + private final String value; public NoteCell(String value) { super(CellType.STRING); diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java index fcde067..1c4b1bd 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/SectionTitleCell.java @@ -1,8 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component.cells; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; @@ -19,7 +16,7 @@ public class SectionTitleCell extends Cell implements IColoredCell, IBiggerCell, private static final IndexedColors FONT_COLOR = IndexedColors.WHITE; private static final int FONT_HEIGHT = 24; - private String title; + private final String title; public SectionTitleCell(String title) { super(CellType.STRING); diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/TitleCell.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/TitleCell.java index cf82182..bfcec7d 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/TitleCell.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/component/cells/TitleCell.java @@ -1,8 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.component.cells; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; -import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IFontCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.Document; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IBiggerCell; import dev.fyloz.colorrecipesexplorer.xlsx.component.cells.styles.IColoredCell; @@ -18,7 +15,7 @@ public class TitleCell extends Cell implements IColoredCell, IBiggerCell, IFontC private static final IndexedColors FONT_COLOR = IndexedColors.WHITE; private static IndexedColors BACKGROUND_COLOR = IndexedColors.BLACK; - private String title; + private final String title; public TitleCell(String title) { super(TYPE); diff --git a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/util/CellUtils.java b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/util/CellUtils.java index 28dc3b1..bf1f35e 100644 --- a/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/util/CellUtils.java +++ b/src/main/java/dev/fyloz/colorrecipesexplorer/xlsx/util/CellUtils.java @@ -1,6 +1,5 @@ package dev.fyloz.colorrecipesexplorer.xlsx.util; -import dev.fyloz.colorrecipesexplorer.xlsx.component.Sheet; import dev.fyloz.colorrecipesexplorer.xlsx.component.Sheet; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.util.CellRangeAddress; @@ -28,11 +27,7 @@ public class CellUtils { return true; } - if (cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty()) { - return true; - } - - return false; + return cell.getCellType() == CellType.STRING && cell.getStringCellValue().trim().isEmpty(); } public static boolean isCellInMergedCell(Sheet sheet, int x, int y) { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/ColorRecipesExplorerApplication.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/ColorRecipesExplorerApplication.kt index 1a8579c..17c867a 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/ColorRecipesExplorerApplication.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/ColorRecipesExplorerApplication.kt @@ -1,7 +1,7 @@ package dev.fyloz.colorrecipesexplorer -import dev.fyloz.colorrecipesexplorer.config.properties.MaterialTypeProperties import dev.fyloz.colorrecipesexplorer.config.properties.CreProperties +import dev.fyloz.colorrecipesexplorer.config.properties.MaterialTypeProperties import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration import org.springframework.boot.context.properties.EnableConfigurationProperties @@ -9,9 +9,9 @@ import org.springframework.boot.runApplication @SpringBootApplication(exclude = [LiquibaseAutoConfiguration::class]) @EnableConfigurationProperties( - MaterialTypeProperties::class, - CreProperties::class, - DatabaseUpdaterProperties::class + MaterialTypeProperties::class, + CreProperties::class, + DatabaseUpdaterProperties::class ) class ColorRecipesExplorerApplication diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/DatabaseVersioning.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/DatabaseVersioning.kt index 4e818c6..81d6419 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/DatabaseVersioning.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/DatabaseVersioning.kt @@ -20,18 +20,18 @@ class DataSourceConfiguration { @Bean(name = ["dataSource"]) @ConfigurationProperties(prefix = "spring.datasource") fun customDataSource( - logger: Logger, - environment: Environment, - databaseUpdaterProperties: DatabaseUpdaterProperties + logger: Logger, + environment: Environment, + databaseUpdaterProperties: DatabaseUpdaterProperties ): DataSource { val databaseUrl: String = environment.getProperty("spring.datasource.url")!! runDatabaseVersionCheck(logger, databaseUrl, databaseUpdaterProperties) return DataSourceBuilder - .create() - .url(databaseUrl) // Hikari won't start without that - .build() + .create() + .url(databaseUrl) // Hikari won't start without that + .build() } } @@ -75,24 +75,24 @@ fun runDatabaseUpdate(logger: Logger, database: CreDatabase) { } fun getDatabase( - databaseUrl: String, - databaseUpdaterProperties: DatabaseUpdaterProperties, - logger: Logger + databaseUrl: String, + databaseUpdaterProperties: DatabaseUpdaterProperties, + logger: Logger ): CreDatabase { val databaseName = - (DATABASE_NAME_REGEX.find(databaseUrl) ?: throw DatabaseVersioningException.InvalidUrl(databaseUrl)).value + (DATABASE_NAME_REGEX.find(databaseUrl) ?: throw DatabaseVersioningException.InvalidUrl(databaseUrl)).value return CreDatabase( - databaseContext( - properties = databaseUpdaterProperties( - targetVersion = SUPPORTED_DATABASE_VERSION, - url = databaseUrl.removeSuffix(databaseName), - dbName = databaseName, - username = databaseUpdaterProperties.username, - password = databaseUpdaterProperties.password - ), - logger - ) + databaseContext( + properties = databaseUpdaterProperties( + targetVersion = SUPPORTED_DATABASE_VERSION, + url = databaseUrl.removeSuffix(databaseName), + dbName = databaseName, + username = databaseUpdaterProperties.username, + password = databaseUpdaterProperties.password + ), + logger + ) ) } @@ -101,7 +101,7 @@ fun throwUnsupportedDatabaseVersion(version: Int, logger: Logger) { logger.error("Version $version of the database is not supported; Only version $SUPPORTED_DATABASE_VERSION is currently supported; Update this application to use the database.") } else { logger.error( - """Version $version of the database is not supported; Only version $SUPPORTED_DATABASE_VERSION is currently supported. + """Version $version of the database is not supported; Only version $SUPPORTED_DATABASE_VERSION is currently supported. |You can update the database to the supported version by either: | - Setting the environment variable '$ENV_VAR_ENABLE_DATABASE_UPDATE_NAME' to '1' to update the database automatically | - Updating the database manually with the database manager utility (https://git.fyloz.dev/color-recipes-explorer/database-manager) @@ -122,5 +122,5 @@ class DatabaseUpdaterProperties { sealed class DatabaseVersioningException(message: String) : Exception(message) { class InvalidUrl(url: String) : DatabaseVersioningException("Invalid database url: $url") class UnsupportedDatabaseVersion(version: Int) : - DatabaseVersioningException("Unsupported database version: $version; Only version $SUPPORTED_DATABASE_VERSION is currently supported") + DatabaseVersioningException("Unsupported database version: $version; Only version $SUPPORTED_DATABASE_VERSION is currently supported") } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/InitialDataLoader.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/InitialDataLoader.kt index 6db1101..0e1ca4b 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/InitialDataLoader.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/InitialDataLoader.kt @@ -11,9 +11,9 @@ import org.springframework.core.annotation.Order @Configuration @Order(Ordered.HIGHEST_PRECEDENCE) class InitialDataLoader( - private val materialTypeService: MaterialTypeService, - private val materialTypeProperties: MaterialTypeProperties + private val materialTypeService: MaterialTypeService, + private val materialTypeProperties: MaterialTypeProperties ) : ApplicationListener { override fun onApplicationEvent(event: ApplicationReadyEvent) = - materialTypeService.saveSystemTypes(materialTypeProperties.systemTypes) + materialTypeService.saveSystemTypes(materialTypeProperties.systemTypes) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/WebSecurityConfig.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/WebSecurityConfig.kt index a780be3..681bf0e 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/WebSecurityConfig.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/WebSecurityConfig.kt @@ -51,11 +51,11 @@ import javax.servlet.http.HttpServletResponse @EnableGlobalMethodSecurity(prePostEnabled = true) @EnableConfigurationProperties(SecurityConfigurationProperties::class) class WebSecurityConfig( - val securityConfigurationProperties: SecurityConfigurationProperties, - @Lazy val userDetailsService: EmployeeUserDetailsServiceImpl, - @Lazy val employeeService: EmployeeServiceImpl, - val environment: Environment, - val logger: Logger + val securityConfigurationProperties: SecurityConfigurationProperties, + @Lazy val userDetailsService: EmployeeUserDetailsServiceImpl, + @Lazy val employeeService: EmployeeServiceImpl, + val environment: Environment, + val logger: Logger ) : WebSecurityConfigurerAdapter() { var debugMode = false @@ -65,36 +65,36 @@ class WebSecurityConfig( @Bean fun passwordEncoder() = - BCryptPasswordEncoder() + BCryptPasswordEncoder() @Bean override fun authenticationManagerBean(): AuthenticationManager = - super.authenticationManagerBean() + super.authenticationManagerBean() @Bean fun corsConfigurationSource() = - UrlBasedCorsConfigurationSource().apply { - registerCorsConfiguration("/**", CorsConfiguration().apply { - allowedOrigins = listOf("http://localhost:4200") // Angular development server - allowedMethods = listOf( - HttpMethod.GET.name, - HttpMethod.POST.name, - HttpMethod.PUT.name, - HttpMethod.DELETE.name, - HttpMethod.OPTIONS.name, - HttpMethod.HEAD.name - ) - allowCredentials = true - }.applyPermitDefaultValues()) - } + UrlBasedCorsConfigurationSource().apply { + registerCorsConfiguration("/**", CorsConfiguration().apply { + allowedOrigins = listOf("http://localhost:4200") // Angular development server + allowedMethods = listOf( + HttpMethod.GET.name, + HttpMethod.POST.name, + HttpMethod.PUT.name, + HttpMethod.DELETE.name, + HttpMethod.OPTIONS.name, + HttpMethod.HEAD.name + ) + allowCredentials = true + }.applyPermitDefaultValues()) + } @PostConstruct fun initWebSecurity() { fun createUser( - credentials: SecurityConfigurationProperties.SystemUserCredentials?, - firstName: String, - lastName: String, - permissions: List + credentials: SecurityConfigurationProperties.SystemUserCredentials?, + firstName: String, + lastName: String, + permissions: List ) { Assert.notNull(credentials, "No root user has been defined.") credentials!! @@ -102,14 +102,14 @@ class WebSecurityConfig( Assert.notNull(credentials.password, "The root user has no password defined.") if (!employeeService.existsById(credentials.id!!)) { employeeService.save( - Employee( - id = credentials.id!!, - firstName = firstName, - lastName = lastName, - password = passwordEncoder().encode(credentials.password!!), - isSystemUser = true, - permissions = permissions.toMutableSet() - ) + Employee( + id = credentials.id!!, + firstName = firstName, + lastName = lastName, + password = passwordEncoder().encode(credentials.password!!), + isSystemUser = true, + permissions = permissions.toMutableSet() + ) ) } } @@ -121,37 +121,37 @@ class WebSecurityConfig( override fun configure(http: HttpSecurity) { http - .headers().frameOptions().disable() - .and() - .csrf().disable() - .addFilter( - JwtAuthenticationFilter( - authenticationManager(), - employeeService, - securityConfigurationProperties - ) + .headers().frameOptions().disable() + .and() + .csrf().disable() + .addFilter( + JwtAuthenticationFilter( + authenticationManager(), + employeeService, + securityConfigurationProperties ) - .addFilter( - JwtAuthorizationFilter( - userDetailsService, - securityConfigurationProperties, - authenticationManager() - ) + ) + .addFilter( + JwtAuthorizationFilter( + userDetailsService, + securityConfigurationProperties, + authenticationManager() ) - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + ) + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) if (!debugMode) { http.authorizeRequests() - .antMatchers("/api/login").permitAll() - .antMatchers("/api/logout").authenticated() - .antMatchers("/api/employee/current").authenticated() - .anyRequest().authenticated() + .antMatchers("/api/login").permitAll() + .antMatchers("/api/logout").authenticated() + .antMatchers("/api/employee/current").authenticated() + .anyRequest().authenticated() } else { http - .cors() - .and() - .authorizeRequests() - .antMatchers("**").permitAll() + .cors() + .and() + .authorizeRequests() + .antMatchers("**").permitAll() } } } @@ -159,9 +159,9 @@ class WebSecurityConfig( @Component class RestAuthenticationEntryPoint : AuthenticationEntryPoint { override fun commence( - request: HttpServletRequest, - response: HttpServletResponse, - authException: AuthenticationException + request: HttpServletRequest, + response: HttpServletResponse, + authException: AuthenticationException ) = response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized") } @@ -170,9 +170,9 @@ const val defaultGroupCookieName = "Default-Group" val blacklistedJwtTokens = mutableListOf() class JwtAuthenticationFilter( - private val authManager: AuthenticationManager, - private val employeeService: EmployeeService, - private val securityConfigurationProperties: SecurityConfigurationProperties + private val authManager: AuthenticationManager, + private val employeeService: EmployeeService, + private val securityConfigurationProperties: SecurityConfigurationProperties ) : UsernamePasswordAuthenticationFilter() { private var debugMode = false @@ -187,10 +187,10 @@ class JwtAuthenticationFilter( } override fun successfulAuthentication( - request: HttpServletRequest, - response: HttpServletResponse, - chain: FilterChain, - authResult: Authentication + request: HttpServletRequest, + response: HttpServletResponse, + chain: FilterChain, + authResult: Authentication ) { val jwtSecret = securityConfigurationProperties.jwtSecret val jwtDuration = securityConfigurationProperties.jwtDuration @@ -201,17 +201,17 @@ class JwtAuthenticationFilter( val expirationMs = System.currentTimeMillis() + jwtDuration!! val expirationDate = Date(expirationMs) val token = Jwts.builder() - .setSubject(employeeId) - .setExpiration(expirationDate) - .signWith(SignatureAlgorithm.HS512, jwtSecret!!.toByteArray()) - .compact() + .setSubject(employeeId) + .setExpiration(expirationDate) + .signWith(SignatureAlgorithm.HS512, jwtSecret!!.toByteArray()) + .compact() response.addHeader("Access-Control-Expose-Headers", "X-Authentication-Expiration") var bearerCookie = - "$authorizationCookieName=Bearer$token; Max-Age=${jwtDuration / 1000}; HttpOnly; SameSite=strict" + "$authorizationCookieName=Bearer$token; Max-Age=${jwtDuration / 1000}; HttpOnly; SameSite=strict" if (!debugMode) bearerCookie += "; Secure;" response.addHeader( - "Set-Cookie", - bearerCookie + "Set-Cookie", + bearerCookie ) response.addHeader(authorizationCookieName, "Bearer $token") response.addHeader("X-Authentication-Expiration", "$expirationMs") @@ -219,9 +219,9 @@ class JwtAuthenticationFilter( } class JwtAuthorizationFilter( - private val userDetailsService: EmployeeUserDetailsServiceImpl, - private val securityConfigurationProperties: SecurityConfigurationProperties, - authenticationManager: AuthenticationManager + private val userDetailsService: EmployeeUserDetailsServiceImpl, + private val securityConfigurationProperties: SecurityConfigurationProperties, + authenticationManager: AuthenticationManager ) : BasicAuthenticationFilter(authenticationManager) { override fun doFilterInternal(request: HttpServletRequest, response: HttpServletResponse, chain: FilterChain) { fun tryLoginFromBearer(): Boolean { @@ -259,10 +259,10 @@ class JwtAuthorizationFilter( Assert.notNull(jwtSecret, "No JWT secret has been defined.") return try { val employeeId = Jwts.parser() - .setSigningKey(jwtSecret!!.toByteArray()) - .parseClaimsJws(token.replace("Bearer", "")) - .body - .subject + .setSigningKey(jwtSecret!!.toByteArray()) + .parseClaimsJws(token.replace("Bearer", "")) + .body + .subject if (employeeId != null) getAuthenticationToken(employeeId) else null } catch (_: ExpiredJwtException) { null diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/properties/MaterialTypeProperties.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/properties/MaterialTypeProperties.kt index 870bd39..728fb75 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/properties/MaterialTypeProperties.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/config/properties/MaterialTypeProperties.kt @@ -13,9 +13,9 @@ class MaterialTypeProperties { var baseName: String = "" data class MaterialTypeProperty( - var name: String = "", - var prefix: String = "", - var usePercentages: Boolean = false + var name: String = "", + var prefix: String = "", + var usePercentages: Boolean = false ) { fun toMaterialType(): MaterialType { Assert.hasText(name, "A system material type has an empty name") diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/exception/RestException.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/exception/RestException.kt index 03067f2..2732f61 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/exception/RestException.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/exception/RestException.kt @@ -1,7 +1,5 @@ package dev.fyloz.colorrecipesexplorer.exception -import dev.fyloz.colorrecipesexplorer.model.Material -import dev.fyloz.colorrecipesexplorer.model.MaterialQuantityDto import org.springframework.http.HttpHeaders import org.springframework.http.HttpStatus import org.springframework.http.ResponseEntity @@ -14,63 +12,63 @@ import org.springframework.web.context.request.WebRequest import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler abstract class RestException( - val errorCode: String, - val title: String, - val status: HttpStatus, - val details: String, - val extensions: Map = mapOf() + val errorCode: String, + val title: String, + val status: HttpStatus, + val details: String, + val extensions: Map = mapOf() ) : RuntimeException(details) { fun buildExceptionBody() = mapOf( - "type" to errorCode, - "title" to title, - "status" to status.value(), - "detail" to details, + "type" to errorCode, + "title" to title, + "status" to status.value(), + "detail" to details, - *extensions.map { it.key to it.value }.toTypedArray() + *extensions.map { it.key to it.value }.toTypedArray() ) } class NotFoundException( - errorCode: String, - title: String, - details: String, - identifierValue: Any, - identifierName: String = "id" + errorCode: String, + title: String, + details: String, + identifierValue: Any, + identifierName: String = "id" ) : RestException( - errorCode = "notfound-$errorCode-$identifierName", - title = title, - status = HttpStatus.NOT_FOUND, - details = details, - extensions = mapOf( - identifierName to identifierValue - ) + errorCode = "notfound-$errorCode-$identifierName", + title = title, + status = HttpStatus.NOT_FOUND, + details = details, + extensions = mapOf( + identifierName to identifierValue + ) ) class AlreadyExistsException( - errorCode: String, - title: String, - details: String, - identifierValue: Any, - identifierName: String = "id" + errorCode: String, + title: String, + details: String, + identifierValue: Any, + identifierName: String = "id" ) : RestException( - errorCode = "exists-$errorCode-$identifierName", - title = title, - status = HttpStatus.CONFLICT, - details = details, - extensions = mapOf( - identifierName to identifierValue - ) + errorCode = "exists-$errorCode-$identifierName", + title = title, + status = HttpStatus.CONFLICT, + details = details, + extensions = mapOf( + identifierName to identifierValue + ) ) class CannotDeleteException( - errorCode: String, - title: String, - details: String + errorCode: String, + title: String, + details: String ) : RestException( - errorCode = "cannotdelete-$errorCode", - title = title, - status = HttpStatus.CONFLICT, - details = details + errorCode = "cannotdelete-$errorCode", + title = title, + status = HttpStatus.CONFLICT, + details = details ) @ControllerAdvice @@ -81,19 +79,19 @@ class RestResponseEntityExceptionHandler : ResponseEntityExceptionHandler() { finalBody["instance"] = (request as ServletWebRequest).request.requestURI return handleExceptionInternal( - exception, - finalBody, - HttpHeaders(), - exception.status, - request + exception, + finalBody, + HttpHeaders(), + exception.status, + request ) } override fun handleMethodArgumentNotValid( - ex: MethodArgumentNotValidException, - headers: HttpHeaders, - status: HttpStatus, - request: WebRequest + ex: MethodArgumentNotValidException, + headers: HttpHeaders, + status: HttpStatus, + request: WebRequest ): ResponseEntity { val errors = hashMapOf() ex.bindingResult.allErrors.forEach { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Company.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Company.kt index 1d75903..c6b1fdf 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Company.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Company.kt @@ -14,49 +14,49 @@ private const val COMPANY_NAME_NULL_MESSAGE = "Un nom est requis" @Entity @Table(name = "company") data class Company( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - @Column(unique = true) - override val name: String + @Column(unique = true) + override val name: String ) : NamedModel open class CompanySaveDto( - @field:NotBlank(message = COMPANY_NAME_NULL_MESSAGE) - val name: String + @field:NotBlank(message = COMPANY_NAME_NULL_MESSAGE) + val name: String ) : EntityDto { override fun toEntity(): Company = Company(null, name) } open class CompanyUpdateDto( - @field:NotNull(message = COMPANY_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = COMPANY_ID_NULL_MESSAGE) + val id: Long, - @field:NullOrNotBlank(message = COMPANY_NAME_NULL_MESSAGE) - val name: String? + @field:NullOrNotBlank(message = COMPANY_NAME_NULL_MESSAGE) + val name: String? ) : EntityDto { override fun toEntity(): Company = Company(id, name ?: "") } // ==== DSL ==== fun company( - id: Long? = null, - name: String = "name", - op: Company.() -> Unit = {} + id: Long? = null, + name: String = "name", + op: Company.() -> Unit = {} ) = Company(id, name).apply(op) fun companySaveDto( - name: String = "name", - op: CompanySaveDto.() -> Unit = {} + name: String = "name", + op: CompanySaveDto.() -> Unit = {} ) = CompanySaveDto(name).apply(op) fun companyUpdateDto( - id: Long = 0L, - name: String? = "name", - op: CompanyUpdateDto.() -> Unit = {} + id: Long = 0L, + name: String? = "name", + op: CompanyUpdateDto.() -> Unit = {} ) = CompanyUpdateDto(id, name).apply(op) // ==== Exceptions ==== @@ -66,34 +66,42 @@ private const val COMPANY_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete company private const val COMPANY_EXCEPTION_ERROR_CODE = "company" fun companyIdNotFoundException(id: Long) = - NotFoundException( - COMPANY_EXCEPTION_ERROR_CODE, - COMPANY_NOT_FOUND_EXCEPTION_TITLE, - "A company with the id $id could not be found", - id - ) + NotFoundException( + COMPANY_EXCEPTION_ERROR_CODE, + COMPANY_NOT_FOUND_EXCEPTION_TITLE, + "A company with the id $id could not be found", + id + ) fun companyNameNotFoundException(name: String) = - NotFoundException( - COMPANY_EXCEPTION_ERROR_CODE, - COMPANY_NOT_FOUND_EXCEPTION_TITLE, - "A company with the name $name could not be found", - name, - "name" - ) + NotFoundException( + COMPANY_EXCEPTION_ERROR_CODE, + COMPANY_NOT_FOUND_EXCEPTION_TITLE, + "A company with the name $name could not be found", + name, + "name" + ) + +fun companyIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + COMPANY_EXCEPTION_ERROR_CODE, + COMPANY_ALREADY_EXISTS_EXCEPTION_TITLE, + "A company with the id $id already exists", + id + ) fun companyNameAlreadyExistsException(name: String) = - AlreadyExistsException( - COMPANY_EXCEPTION_ERROR_CODE, - COMPANY_ALREADY_EXISTS_EXCEPTION_TITLE, - "A company with the name $name already exists", - name, - "name" - ) + AlreadyExistsException( + COMPANY_EXCEPTION_ERROR_CODE, + COMPANY_ALREADY_EXISTS_EXCEPTION_TITLE, + "A company with the name $name already exists", + name, + "name" + ) fun cannotDeleteCompany(company: Company) = - CannotDeleteException( - COMPANY_EXCEPTION_ERROR_CODE, - COMPANY_CANNOT_DELETE_EXCEPTION_TITLE, - "Cannot delete the company ${company.name} because one or more recipes depends on it" - ) + CannotDeleteException( + COMPANY_EXCEPTION_ERROR_CODE, + COMPANY_CANNOT_DELETE_EXCEPTION_TITLE, + "Cannot delete the company ${company.name} because one or more recipes depends on it" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Employee.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Employee.kt index b65e73b..fa564eb 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Employee.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Employee.kt @@ -25,51 +25,51 @@ private const val EMPLOYEE_PASSWORD_TOO_SHORT_MESSAGE = "Le mot de passe doit co @Entity @Table(name = "employee") data class Employee( - @Id - override val id: Long, + @Id + override val id: Long, - @Column(name = "first_name") - val firstName: String = "", + @Column(name = "first_name") + val firstName: String = "", - @Column(name = "last_name") - val lastName: String = "", + @Column(name = "last_name") + val lastName: String = "", - @JsonIgnore - val password: String = "", + @JsonIgnore + val password: String = "", - @JsonIgnore - @Column(name = "default_group_user") - val isDefaultGroupUser: Boolean = false, + @JsonIgnore + @Column(name = "default_group_user") + val isDefaultGroupUser: Boolean = false, - @JsonIgnore - @Column(name = "system_user") - val isSystemUser: Boolean = false, + @JsonIgnore + @Column(name = "system_user") + val isSystemUser: Boolean = false, - @ManyToOne - @JoinColumn(name = "group_id") - @Fetch(FetchMode.SELECT) - var group: EmployeeGroup? = null, + @ManyToOne + @JoinColumn(name = "group_id") + @Fetch(FetchMode.SELECT) + var group: EmployeeGroup? = null, - @Enumerated(EnumType.STRING) - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "employee_permission", joinColumns = [JoinColumn(name = "employee_id")]) - @Column(name = "permission") - @Fetch(FetchMode.SUBSELECT) - @get:JsonProperty("explicitPermissions") - val permissions: MutableSet = mutableSetOf(), + @Enumerated(EnumType.STRING) + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "employee_permission", joinColumns = [JoinColumn(name = "employee_id")]) + @Column(name = "permission") + @Fetch(FetchMode.SUBSELECT) + @get:JsonProperty("explicitPermissions") + val permissions: MutableSet = mutableSetOf(), - @Column(name = "last_login_time") - var lastLoginTime: LocalDateTime? = null + @Column(name = "last_login_time") + var lastLoginTime: LocalDateTime? = null ) : Model { @get:JsonProperty("permissions") val flatPermissions: Set get() = permissions - .flatMap { it.flat() } - .filter { !it.deprecated } - .toMutableSet() - .apply { - if (group != null) this.addAll(group!!.flatPermissions) - } + .flatMap { it.flat() } + .filter { !it.deprecated } + .toMutableSet() + .apply { + if (group != null) this.addAll(group!!.flatPermissions) + } @get:JsonIgnore val authorities: Set @@ -78,86 +78,86 @@ data class Employee( /** DTO for creating employees. Allows a [password] a [groupId]. */ open class EmployeeSaveDto( - @field:NotNull(message = EMPLOYEE_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = EMPLOYEE_ID_NULL_MESSAGE) + val id: Long, - @field:NotBlank(message = EMPLOYEE_FIRST_NAME_EMPTY_MESSAGE) - val firstName: String, + @field:NotBlank(message = EMPLOYEE_FIRST_NAME_EMPTY_MESSAGE) + val firstName: String, - @field:NotBlank(message = EMPLOYEE_LAST_NAME_EMPTY_MESSAGE) - val lastName: String, + @field:NotBlank(message = EMPLOYEE_LAST_NAME_EMPTY_MESSAGE) + val lastName: String, - @field:NotBlank(message = EMPLOYEE_PASSWORD_EMPTY_MESSAGE) - @field:Size(min = 8, message = EMPLOYEE_PASSWORD_TOO_SHORT_MESSAGE) - val password: String, + @field:NotBlank(message = EMPLOYEE_PASSWORD_EMPTY_MESSAGE) + @field:Size(min = 8, message = EMPLOYEE_PASSWORD_TOO_SHORT_MESSAGE) + val password: String, - val groupId: Long?, + val groupId: Long?, - @Enumerated(EnumType.STRING) - val permissions: MutableSet = mutableSetOf() + @Enumerated(EnumType.STRING) + val permissions: MutableSet = mutableSetOf() ) : EntityDto open class EmployeeUpdateDto( - @field:NotNull(message = EMPLOYEE_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = EMPLOYEE_ID_NULL_MESSAGE) + val id: Long, - @field:NullOrNotBlank(message = EMPLOYEE_FIRST_NAME_EMPTY_MESSAGE) - val firstName: String?, + @field:NullOrNotBlank(message = EMPLOYEE_FIRST_NAME_EMPTY_MESSAGE) + val firstName: String?, - @field:NullOrNotBlank(message = EMPLOYEE_LAST_NAME_EMPTY_MESSAGE) - val lastName: String?, + @field:NullOrNotBlank(message = EMPLOYEE_LAST_NAME_EMPTY_MESSAGE) + val lastName: String?, - val groupId: Long?, + val groupId: Long?, - @Enumerated(EnumType.STRING) - val permissions: Set? + @Enumerated(EnumType.STRING) + val permissions: Set? ) : EntityDto data class EmployeeLoginRequest(val id: Long, val password: String) // ==== DSL ==== fun employee( - passwordEncoder: PasswordEncoder = BCryptPasswordEncoder(), - id: Long = 0L, - firstName: String = "firstName", - lastName: String = "lastName", - password: String = passwordEncoder.encode("password"), - isDefaultGroupUser: Boolean = false, - isSystemUser: Boolean = false, - group: EmployeeGroup? = null, - permissions: MutableSet = mutableSetOf(), - lastLoginTime: LocalDateTime? = null, - op: Employee.() -> Unit = {} + passwordEncoder: PasswordEncoder = BCryptPasswordEncoder(), + id: Long = 0L, + firstName: String = "firstName", + lastName: String = "lastName", + password: String = passwordEncoder.encode("password"), + isDefaultGroupUser: Boolean = false, + isSystemUser: Boolean = false, + group: EmployeeGroup? = null, + permissions: MutableSet = mutableSetOf(), + lastLoginTime: LocalDateTime? = null, + op: Employee.() -> Unit = {} ) = Employee( - id, - firstName, - lastName, - password, - isDefaultGroupUser, - isSystemUser, - group, - permissions, - lastLoginTime + id, + firstName, + lastName, + password, + isDefaultGroupUser, + isSystemUser, + group, + permissions, + lastLoginTime ).apply(op) fun employeeSaveDto( - passwordEncoder: PasswordEncoder = BCryptPasswordEncoder(), - id: Long = 0L, - firstName: String = "firstName", - lastName: String = "lastName", - password: String = passwordEncoder.encode("password"), - groupId: Long? = null, - permissions: MutableSet = mutableSetOf(), - op: EmployeeSaveDto.() -> Unit = {} + passwordEncoder: PasswordEncoder = BCryptPasswordEncoder(), + id: Long = 0L, + firstName: String = "firstName", + lastName: String = "lastName", + password: String = passwordEncoder.encode("password"), + groupId: Long? = null, + permissions: MutableSet = mutableSetOf(), + op: EmployeeSaveDto.() -> Unit = {} ) = EmployeeSaveDto(id, firstName, lastName, password, groupId, permissions).apply(op) fun employeeUpdateDto( - id: Long = 0L, - firstName: String = "firstName", - lastName: String = "lastName", - groupId: Long? = null, - permissions: MutableSet = mutableSetOf(), - op: EmployeeUpdateDto.() -> Unit = {} + id: Long = 0L, + firstName: String = "firstName", + lastName: String = "lastName", + groupId: Long? = null, + permissions: MutableSet = mutableSetOf(), + op: EmployeeUpdateDto.() -> Unit = {} ) = EmployeeUpdateDto(id, firstName, lastName, groupId, permissions).apply(op) // ==== Exceptions ==== @@ -166,26 +166,26 @@ private const val EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE = "Employee already ex private const val EMPLOYEE_EXCEPTION_ERROR_CODE = "employee" fun employeeIdNotFoundException(id: Long) = - NotFoundException( - EMPLOYEE_EXCEPTION_ERROR_CODE, - EMPLOYEE_NOT_FOUND_EXCEPTION_TITLE, - "An employee with the id $id could not be found", - id - ) + NotFoundException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_NOT_FOUND_EXCEPTION_TITLE, + "An employee with the id $id could not be found", + id + ) fun employeeIdAlreadyExistsException(id: Long) = - AlreadyExistsException( - EMPLOYEE_EXCEPTION_ERROR_CODE, - EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, - "An employee with the id $id already exists", - id - ) + AlreadyExistsException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, + "An employee with the id $id already exists", + id + ) fun employeeFullNameAlreadyExistsException(firstName: String, lastName: String) = - AlreadyExistsException( - EMPLOYEE_EXCEPTION_ERROR_CODE, - EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, - "An employee with the name '$firstName $lastName' already exists", - "$firstName $lastName", - "fullName" - ) + AlreadyExistsException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, + "An employee with the name '$firstName $lastName' already exists", + "$firstName $lastName", + "fullName" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeeGroup.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeeGroup.kt index 32e91bf..a0d467e 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeeGroup.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeeGroup.kt @@ -19,74 +19,74 @@ private const val GROUP_PERMISSIONS_EMPTY_MESSAGE = "Au moins une permission est @Entity @Table(name = "employee_group") data class EmployeeGroup( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override var id: Long? = null, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override var id: Long? = null, - @Column(unique = true) - override val name: String = "", + @Column(unique = true) + override val name: String = "", - @Enumerated(EnumType.STRING) - @ElementCollection(fetch = FetchType.EAGER) - @CollectionTable(name = "group_permission", joinColumns = [JoinColumn(name = "group_id")]) - @Column(name = "permission") - @Fetch(FetchMode.SUBSELECT) - @get:JsonProperty("explicitPermissions") - val permissions: MutableSet = mutableSetOf(), + @Enumerated(EnumType.STRING) + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable(name = "group_permission", joinColumns = [JoinColumn(name = "group_id")]) + @Column(name = "permission") + @Fetch(FetchMode.SUBSELECT) + @get:JsonProperty("explicitPermissions") + val permissions: MutableSet = mutableSetOf(), ) : NamedModel { @get:JsonProperty("permissions") val flatPermissions: Set get() = this.permissions - .flatMap { it.flat() } - .filter { !it.deprecated } - .toSet() + .flatMap { it.flat() } + .filter { !it.deprecated } + .toSet() } open class EmployeeGroupSaveDto( - @field:NotBlank(message = GROUP_NAME_NULL_MESSAGE) - @field:Size(min = 3) - val name: String, + @field:NotBlank(message = GROUP_NAME_NULL_MESSAGE) + @field:Size(min = 3) + val name: String, - @field:Size(min = 1, message = GROUP_PERMISSIONS_EMPTY_MESSAGE) - val permissions: MutableSet + @field:Size(min = 1, message = GROUP_PERMISSIONS_EMPTY_MESSAGE) + val permissions: MutableSet ) : EntityDto { override fun toEntity(): EmployeeGroup = - EmployeeGroup(null, name, permissions) + EmployeeGroup(null, name, permissions) } open class EmployeeGroupUpdateDto( - @field:NotNull(message = GROUP_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = GROUP_ID_NULL_MESSAGE) + val id: Long, - @field:NotBlank(message = GROUP_NAME_NULL_MESSAGE) - @field:Size(min = 3) - val name: String, + @field:NotBlank(message = GROUP_NAME_NULL_MESSAGE) + @field:Size(min = 3) + val name: String, - @field:Size(min = 1, message = GROUP_PERMISSIONS_EMPTY_MESSAGE) - val permissions: MutableSet + @field:Size(min = 1, message = GROUP_PERMISSIONS_EMPTY_MESSAGE) + val permissions: MutableSet ) : EntityDto { override fun toEntity(): EmployeeGroup = - EmployeeGroup(id, name, permissions) + EmployeeGroup(id, name, permissions) } fun employeeGroup( - id: Long? = null, - name: String = "name", - permissions: MutableSet = mutableSetOf(), - op: EmployeeGroup.() -> Unit = {} + id: Long? = null, + name: String = "name", + permissions: MutableSet = mutableSetOf(), + op: EmployeeGroup.() -> Unit = {} ) = EmployeeGroup(id, name, permissions).apply(op) fun employeeGroupSaveDto( - name: String = "name", - permissions: MutableSet = mutableSetOf(), - op: EmployeeGroupSaveDto.() -> Unit = {} + name: String = "name", + permissions: MutableSet = mutableSetOf(), + op: EmployeeGroupSaveDto.() -> Unit = {} ) = EmployeeGroupSaveDto(name, permissions).apply(op) fun employeeGroupUpdateDto( - id: Long = 0L, - name: String = "name", - permissions: MutableSet = mutableSetOf(), - op: EmployeeGroupUpdateDto.() -> Unit = {} + id: Long = 0L, + name: String = "name", + permissions: MutableSet = mutableSetOf(), + op: EmployeeGroupUpdateDto.() -> Unit = {} ) = EmployeeGroupUpdateDto(id, name, permissions).apply(op) // ==== Exceptions ==== @@ -95,35 +95,42 @@ private const val EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE = "Employee group alre private const val EMPLOYEE_EXCEPTION_ERROR_CODE = "employeegroup" class NoDefaultGroupException : RestException( - "nodefaultgroup", - "No default group", - HttpStatus.NOT_FOUND, - "No default group cookie is defined in the current request" + "nodefaultgroup", + "No default group", + HttpStatus.NOT_FOUND, + "No default group cookie is defined in the current request" ) fun employeeGroupIdNotFoundException(id: Long) = - NotFoundException( - EMPLOYEE_EXCEPTION_ERROR_CODE, - EMPLOYEE_NOT_FOUND_EXCEPTION_TITLE, - "An employee group with the id $id could not be found", - id - ) + NotFoundException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_NOT_FOUND_EXCEPTION_TITLE, + "An employee group with the id $id could not be found", + id + ) fun employeeGroupNameNotFoundException(name: String) = - NotFoundException( - EMPLOYEE_EXCEPTION_ERROR_CODE, - EMPLOYEE_NOT_FOUND_EXCEPTION_TITLE, - "An employee group with the name $name could not be found", - name, - "name" - ) + NotFoundException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_NOT_FOUND_EXCEPTION_TITLE, + "An employee group with the name $name could not be found", + name, + "name" + ) + +fun employeeGroupIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, + "An employee group with the id $id already exists", + id, + ) fun employeeGroupNameAlreadyExistsException(name: String) = - AlreadyExistsException( - EMPLOYEE_EXCEPTION_ERROR_CODE, - EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, - "An employee group with the name $name already exists", - name, - "name" - ) - + AlreadyExistsException( + EMPLOYEE_EXCEPTION_ERROR_CODE, + EMPLOYEE_ALREADY_EXISTS_EXCEPTION_TITLE, + "An employee group with the name $name already exists", + name, + "name" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeePermission.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeePermission.kt index 3bcfd42..a12ae7b 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeePermission.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/EmployeePermission.kt @@ -4,8 +4,8 @@ import org.springframework.security.core.GrantedAuthority import org.springframework.security.core.authority.SimpleGrantedAuthority enum class EmployeePermission( - val impliedPermissions: List = listOf(), - val deprecated: Boolean = false + val impliedPermissions: List = listOf(), + val deprecated: Boolean = false ) { VIEW_RECIPES, VIEW_CATALOG, @@ -32,17 +32,17 @@ enum class EmployeePermission( REMOVE_CATALOG(listOf(REMOVE_MATERIALS, REMOVE_MATERIAL_TYPES, REMOVE_COMPANIES)), ADMIN( - listOf( - EDIT_CATALOG, + listOf( + EDIT_CATALOG, - REMOVE_RECIPES, - REMOVE_USERS, - REMOVE_CATALOG, + REMOVE_RECIPES, + REMOVE_USERS, + REMOVE_CATALOG, - PRINT_MIXES, - ADD_TO_INVENTORY, - DEDUCT_FROM_INVENTORY - ) + PRINT_MIXES, + ADD_TO_INVENTORY, + DEDUCT_FROM_INVENTORY + ) ), // deprecated permissions diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Material.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Material.kt index c28e1cd..3b060a1 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Material.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Material.kt @@ -24,103 +24,103 @@ private const val MATERIAL_QUANTITY_QUANTITY_NEGATIVE_MESSAGE = "La quantité do @Entity @Table(name = "material") data class Material( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - @Column(unique = true) - override var name: String, + @Column(unique = true) + override var name: String, - @Column(name = "inventory_quantity") - var inventoryQuantity: Float, + @Column(name = "inventory_quantity") + var inventoryQuantity: Float, - @Column(name = "mix_type") - val isMixType: Boolean, + @Column(name = "mix_type") + val isMixType: Boolean, - @ManyToOne - @JoinColumn(name = "material_type_id") - var materialType: MaterialType? + @ManyToOne + @JoinColumn(name = "material_type_id") + var materialType: MaterialType? ) : NamedModel open class MaterialSaveDto( - @field:NotBlank(message = MATERIAL_NAME_NULL_MESSAGE) - val name: String, + @field:NotBlank(message = MATERIAL_NAME_NULL_MESSAGE) + val name: String, - @field:NotNull(message = MATERIAL_INVENTORY_QUANTITY_NULL_MESSAGE) - @field:Min(value = 0, message = MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE) - val inventoryQuantity: Float, + @field:NotNull(message = MATERIAL_INVENTORY_QUANTITY_NULL_MESSAGE) + @field:Min(value = 0, message = MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE) + val inventoryQuantity: Float, - @field:NotNull(message = MATERIAL_TYPE_NULL_MESSAGE) - val materialTypeId: Long, + @field:NotNull(message = MATERIAL_TYPE_NULL_MESSAGE) + val materialTypeId: Long, - val simdutFile: MultipartFile? = null + val simdutFile: MultipartFile? = null ) : EntityDto open class MaterialUpdateDto( - @field:NotNull(message = MATERIAL_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = MATERIAL_ID_NULL_MESSAGE) + val id: Long, - @field:NullOrNotBlank(message = MATERIAL_NAME_NULL_MESSAGE) - val name: String?, + @field:NullOrNotBlank(message = MATERIAL_NAME_NULL_MESSAGE) + val name: String?, - @field:NullOrSize(min = 0, message = MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE) - val inventoryQuantity: Float?, + @field:NullOrSize(min = 0, message = MATERIAL_INVENTORY_QUANTITY_NEGATIVE_MESSAGE) + val inventoryQuantity: Float?, - val materialTypeId: Long?, + val materialTypeId: Long?, - val simdutFile: MultipartFile? = null + val simdutFile: MultipartFile? = null ) : EntityDto data class MaterialQuantityDto( - @field:NotNull(message = MATERIAL_QUANTITY_MATERIAL_NULL_MESSAGE) - val material: Long, + @field:NotNull(message = MATERIAL_QUANTITY_MATERIAL_NULL_MESSAGE) + val material: Long, - @field:NotNull(message = MATERIAL_QUANTITY_QUANTITY_NULL_MESSAGE) - @field:Min(value = 0, message = MATERIAL_QUANTITY_QUANTITY_NEGATIVE_MESSAGE) - val quantity: Float + @field:NotNull(message = MATERIAL_QUANTITY_QUANTITY_NULL_MESSAGE) + @field:Min(value = 0, message = MATERIAL_QUANTITY_QUANTITY_NEGATIVE_MESSAGE) + val quantity: Float ) // === DSL === fun material( - id: Long? = null, - name: String = "name", - inventoryQuantity: Float = 0f, - isMixType: Boolean = false, - materialType: MaterialType? = materialType(), - op: Material.() -> Unit = {} + id: Long? = null, + name: String = "name", + inventoryQuantity: Float = 0f, + isMixType: Boolean = false, + materialType: MaterialType? = materialType(), + op: Material.() -> Unit = {} ) = Material(id, name, inventoryQuantity, isMixType, materialType).apply(op) fun material( - material: Material, - id: Long? = null, - name: String? = null, + material: Material, + id: Long? = null, + name: String? = null, ) = Material( - id ?: material.id, name - ?: material.name, material.inventoryQuantity, material.isMixType, material.materialType + id ?: material.id, name + ?: material.name, material.inventoryQuantity, material.isMixType, material.materialType ) fun materialSaveDto( - name: String = "name", - inventoryQuantity: Float = 0f, - materialTypeId: Long = 0L, - simdutFile: MultipartFile? = null, - op: MaterialSaveDto.() -> Unit = {} + name: String = "name", + inventoryQuantity: Float = 0f, + materialTypeId: Long = 0L, + simdutFile: MultipartFile? = null, + op: MaterialSaveDto.() -> Unit = {} ) = MaterialSaveDto(name, inventoryQuantity, materialTypeId, simdutFile).apply(op) fun materialUpdateDto( - id: Long = 0L, - name: String? = "name", - inventoryQuantity: Float? = 0f, - materialTypeId: Long? = 0L, - simdutFile: MultipartFile? = null, - op: MaterialUpdateDto.() -> Unit = {} + id: Long = 0L, + name: String? = "name", + inventoryQuantity: Float? = 0f, + materialTypeId: Long? = 0L, + simdutFile: MultipartFile? = null, + op: MaterialUpdateDto.() -> Unit = {} ) = MaterialUpdateDto(id, name, inventoryQuantity, materialTypeId, simdutFile).apply(op) fun materialQuantityDto( - materialId: Long, - quantity: Float, - op: MaterialQuantityDto.() -> Unit = {} + materialId: Long, + quantity: Float, + op: MaterialQuantityDto.() -> Unit = {} ) = MaterialQuantityDto(materialId, quantity).apply(op) // ==== Exceptions ==== @@ -130,34 +130,42 @@ private const val MATERIAL_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete materi private const val MATERIAL_EXCEPTION_ERROR_CODE = "material" fun materialIdNotFoundException(id: Long) = - NotFoundException( - MATERIAL_EXCEPTION_ERROR_CODE, - MATERIAL_NOT_FOUND_EXCEPTION_TITLE, - "A material with the id $id could not be found", - id - ) + NotFoundException( + MATERIAL_EXCEPTION_ERROR_CODE, + MATERIAL_NOT_FOUND_EXCEPTION_TITLE, + "A material with the id $id could not be found", + id + ) fun materialNameNotFoundException(name: String) = - NotFoundException( - MATERIAL_EXCEPTION_ERROR_CODE, - MATERIAL_NOT_FOUND_EXCEPTION_TITLE, - "A material with the name $name could not be found", - name, - "name" - ) + NotFoundException( + MATERIAL_EXCEPTION_ERROR_CODE, + MATERIAL_NOT_FOUND_EXCEPTION_TITLE, + "A material with the name $name could not be found", + name, + "name" + ) + +fun materialIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + MATERIAL_EXCEPTION_ERROR_CODE, + MATERIAL_ALREADY_EXISTS_EXCEPTION_TITLE, + "A material with the id $id already exists", + id + ) fun materialNameAlreadyExistsException(name: String) = - AlreadyExistsException( - MATERIAL_EXCEPTION_ERROR_CODE, - MATERIAL_ALREADY_EXISTS_EXCEPTION_TITLE, - "A material with the name $name already exists", - name, - "name" - ) + AlreadyExistsException( + MATERIAL_EXCEPTION_ERROR_CODE, + MATERIAL_ALREADY_EXISTS_EXCEPTION_TITLE, + "A material with the name $name already exists", + name, + "name" + ) fun cannotDeleteMaterialException(material: Material) = - CannotDeleteException( - MATERIAL_EXCEPTION_ERROR_CODE, - MATERIAL_CANNOT_DELETE_EXCEPTION_TITLE, - "Cannot delete the material ${material.name} because one or more recipes depends on it" - ) + CannotDeleteException( + MATERIAL_EXCEPTION_ERROR_CODE, + MATERIAL_CANNOT_DELETE_EXCEPTION_TITLE, + "Cannot delete the material ${material.name} because one or more recipes depends on it" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MaterialType.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MaterialType.kt index 30beff6..c8f5e80 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MaterialType.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MaterialType.kt @@ -19,90 +19,90 @@ private const val MATERIAL_TYPE_PREFIX_SIZE_MESSAGE = "Le préfixe doit faire ex @Entity @Table(name = "material_type") data class MaterialType( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long? = null, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long? = null, - @Column(unique = true) - override val name: String = "", + @Column(unique = true) + override val name: String = "", - @Column(unique = true) - val prefix: String = "", + @Column(unique = true) + val prefix: String = "", - @Column(name = "use_percentages") - @ColumnDefault("false") - val usePercentages: Boolean = false, + @Column(name = "use_percentages") + @ColumnDefault("false") + val usePercentages: Boolean = false, - @Column(name = "system_type") - @ColumnDefault("false") - val systemType: Boolean = false + @Column(name = "system_type") + @ColumnDefault("false") + val systemType: Boolean = false ) : NamedModel open class MaterialTypeSaveDto( - @field:NotBlank(message = MATERIAL_TYPE_NAME_NULL_MESSAGE) - val name: String, + @field:NotBlank(message = MATERIAL_TYPE_NAME_NULL_MESSAGE) + val name: String, - @field:NotBlank(message = MATERIAL_TYPE_PREFIX_NULL_MESSAGE) - @field:Size(min = 3, max = 3, message = MATERIAL_TYPE_PREFIX_SIZE_MESSAGE) - val prefix: String, + @field:NotBlank(message = MATERIAL_TYPE_PREFIX_NULL_MESSAGE) + @field:Size(min = 3, max = 3, message = MATERIAL_TYPE_PREFIX_SIZE_MESSAGE) + val prefix: String, - val usePercentages: Boolean = false + val usePercentages: Boolean = false ) : EntityDto { override fun toEntity(): MaterialType = - MaterialType(null, name, prefix, usePercentages) + MaterialType(null, name, prefix, usePercentages) } open class MaterialTypeUpdateDto( - @field:NotNull(message = MATERIAL_TYPE_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = MATERIAL_TYPE_ID_NULL_MESSAGE) + val id: Long, - @field:NullOrNotBlank(message = MATERIAL_TYPE_NAME_NULL_MESSAGE) - val name: String?, + @field:NullOrNotBlank(message = MATERIAL_TYPE_NAME_NULL_MESSAGE) + val name: String?, - @field:NullOrSize(min = 3, max = 3, message = MATERIAL_TYPE_PREFIX_NULL_MESSAGE) - val prefix: String? + @field:NullOrSize(min = 3, max = 3, message = MATERIAL_TYPE_PREFIX_NULL_MESSAGE) + val prefix: String? ) : EntityDto { override fun toEntity(): MaterialType = - MaterialType(id, name ?: "", prefix ?: "") + MaterialType(id, name ?: "", prefix ?: "") } // ==== DSL ==== fun materialType( - id: Long? = null, - name: String = "name", - prefix: String = "PRE", - usePercentages: Boolean = false, - systemType: Boolean = false, - op: MaterialType.() -> Unit = {} + id: Long? = null, + name: String = "name", + prefix: String = "PRE", + usePercentages: Boolean = false, + systemType: Boolean = false, + op: MaterialType.() -> Unit = {} ) = MaterialType(id, name, prefix, usePercentages, systemType).apply(op) fun materialType( - materialType: MaterialType, - newId: Long? = null, - newName: String? = null, - newSystemType: Boolean? = null + materialType: MaterialType, + newId: Long? = null, + newName: String? = null, + newSystemType: Boolean? = null ) = with(materialType) { MaterialType( - newId ?: id, - newName ?: name, - prefix, - usePercentages, - newSystemType ?: systemType + newId ?: id, + newName ?: name, + prefix, + usePercentages, + newSystemType ?: systemType ) } fun materialTypeSaveDto( - name: String = "name", - prefix: String = "PRE", - usePercentages: Boolean = false, - op: MaterialTypeSaveDto.() -> Unit = {} + name: String = "name", + prefix: String = "PRE", + usePercentages: Boolean = false, + op: MaterialTypeSaveDto.() -> Unit = {} ) = MaterialTypeSaveDto(name, prefix, usePercentages).apply(op) fun materialTypeUpdateDto( - id: Long = 0L, - name: String? = null, - prefix: String? = null, - op: MaterialTypeUpdateDto.() -> Unit = {} + id: Long = 0L, + name: String? = null, + prefix: String? = null, + op: MaterialTypeUpdateDto.() -> Unit = {} ) = MaterialTypeUpdateDto(id, name, prefix).apply(op) // ==== Exceptions ==== @@ -112,43 +112,51 @@ private const val MATERIAL_TYPE_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete m private const val MATERIAL_TYPE_EXCEPTION_ERROR_CODE = "materialtype" fun materialTypeIdNotFoundException(id: Long) = - NotFoundException( - MATERIAL_TYPE_EXCEPTION_ERROR_CODE, - MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE, - "A material type with the id $id could not be found", - id - ) + NotFoundException( + MATERIAL_TYPE_EXCEPTION_ERROR_CODE, + MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE, + "A material type with the id $id could not be found", + id + ) fun materialTypeNameNotFoundException(name: String) = - NotFoundException( - MATERIAL_TYPE_EXCEPTION_ERROR_CODE, - MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE, - "A material type with the name $name could not be found", - name, - "name" - ) + NotFoundException( + MATERIAL_TYPE_EXCEPTION_ERROR_CODE, + MATERIAL_TYPE_NOT_FOUND_EXCEPTION_TITLE, + "A material type with the name $name could not be found", + name, + "name" + ) + +fun materialTypeIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + MATERIAL_TYPE_EXCEPTION_ERROR_CODE, + MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, + "A material type with the id $id already exists", + id + ) fun materialTypeNameAlreadyExistsException(name: String) = - AlreadyExistsException( - MATERIAL_TYPE_EXCEPTION_ERROR_CODE, - MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, - "A material type with the name $name already exists", - name, - "name" - ) + AlreadyExistsException( + MATERIAL_TYPE_EXCEPTION_ERROR_CODE, + MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, + "A material type with the name $name already exists", + name, + "name" + ) fun materialTypePrefixAlreadyExistsException(prefix: String) = - AlreadyExistsException( - MATERIAL_TYPE_EXCEPTION_ERROR_CODE, - MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, - "A material type with the prefix $prefix already exists", - prefix, - "prefix" - ) + AlreadyExistsException( + MATERIAL_TYPE_EXCEPTION_ERROR_CODE, + MATERIAL_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, + "A material type with the prefix $prefix already exists", + prefix, + "prefix" + ) fun cannotDeleteMaterialTypeException(materialType: MaterialType) = - CannotDeleteException( - MATERIAL_TYPE_EXCEPTION_ERROR_CODE, - MATERIAL_TYPE_CANNOT_DELETE_EXCEPTION_TITLE, - "Cannot delete material type ${materialType.name} because one or more materials depends on it" - ) + CannotDeleteException( + MATERIAL_TYPE_EXCEPTION_ERROR_CODE, + MATERIAL_TYPE_CANNOT_DELETE_EXCEPTION_TITLE, + "Cannot delete material type ${materialType.name} because one or more materials depends on it" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Mix.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Mix.kt index 6178a54..4dcb08f 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Mix.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Mix.kt @@ -1,6 +1,7 @@ package dev.fyloz.colorrecipesexplorer.model import com.fasterxml.jackson.annotation.JsonIgnore +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.CannotDeleteException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.model.validation.NullOrNotBlank @@ -21,125 +22,134 @@ private const val MIX_DEDUCT_RATION_NEGATIVE_MESSAGE = "Le ratio doit être éga @Entity @Table(name = "mix") data class Mix( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - var location: String?, + var location: String?, - @JsonIgnore - @ManyToOne - @JoinColumn(name = "recipe_id") - val recipe: Recipe, + @JsonIgnore + @ManyToOne + @JoinColumn(name = "recipe_id") + val recipe: Recipe, - @ManyToOne - @JoinColumn(name = "mix_type_id") - var mixType: MixType, + @ManyToOne + @JoinColumn(name = "mix_type_id") + var mixType: MixType, - @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true) - @JoinColumn(name = "mix_id") - var mixMaterials: MutableSet, + @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true) + @JoinColumn(name = "mix_id") + var mixMaterials: MutableSet, ) : Model open class MixSaveDto( - @field:NotBlank(message = MIX_NAME_NULL_MESSAGE) - val name: String, + @field:NotBlank(message = MIX_NAME_NULL_MESSAGE) + val name: String, - @field:NotNull(message = MIX_RECIPE_NULL_MESSAGE) - val recipeId: Long, + @field:NotNull(message = MIX_RECIPE_NULL_MESSAGE) + val recipeId: Long, - @field:NotNull(message = MIX_MATERIAL_TYPE_NULL_MESSAGE) - val materialTypeId: Long, + @field:NotNull(message = MIX_MATERIAL_TYPE_NULL_MESSAGE) + val materialTypeId: Long, - val mixMaterials: Set? + val mixMaterials: Set? ) : EntityDto { override fun toEntity(): Mix = throw UnsupportedOperationException() } open class MixUpdateDto( - @field:NotNull(message = MIX_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = MIX_ID_NULL_MESSAGE) + val id: Long, - @field:NullOrNotBlank(message = MIX_NAME_NULL_MESSAGE) - val name: String?, + @field:NullOrNotBlank(message = MIX_NAME_NULL_MESSAGE) + val name: String?, - val materialTypeId: Long?, + val materialTypeId: Long?, - var mixMaterials: Set? + var mixMaterials: Set? ) : EntityDto { override fun toEntity(): Mix = throw UnsupportedOperationException() } data class MixDeductDto( - @field:NotNull(message = MIX_DEDUCT_MIX_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = MIX_DEDUCT_MIX_ID_NULL_MESSAGE) + val id: Long, - @field:NotNull(message = MIX_DEDUCT_RATIO_NULL_MESSAGE) - @field:Min(value = 0, message = MIX_DEDUCT_RATION_NEGATIVE_MESSAGE) - val ratio: Float + @field:NotNull(message = MIX_DEDUCT_RATIO_NULL_MESSAGE) + @field:Min(value = 0, message = MIX_DEDUCT_RATION_NEGATIVE_MESSAGE) + val ratio: Float ) data class MixLocationDto( - @field:NotNull(message = MIX_DEDUCT_MIX_ID_NULL_MESSAGE) - val mixId: Long, + @field:NotNull(message = MIX_DEDUCT_MIX_ID_NULL_MESSAGE) + val mixId: Long, - val location: String? + val location: String? ) // ==== DSL ==== fun mix( - id: Long? = null, - location: String? = "location", - recipe: Recipe = recipe(), - mixType: MixType = mixType(), - mixMaterials: MutableSet = mutableSetOf(), - op: Mix.() -> Unit = {} + id: Long? = null, + location: String? = "location", + recipe: Recipe = recipe(), + mixType: MixType = mixType(), + mixMaterials: MutableSet = mutableSetOf(), + op: Mix.() -> Unit = {} ) = Mix(id, location, recipe, mixType, mixMaterials).apply(op) fun mixSaveDto( - name: String = "name", - recipeId: Long = 0L, - materialTypeId: Long = 0L, - mixMaterials: Set? = setOf(), - op: MixSaveDto.() -> Unit = {} + name: String = "name", + recipeId: Long = 0L, + materialTypeId: Long = 0L, + mixMaterials: Set? = setOf(), + op: MixSaveDto.() -> Unit = {} ) = MixSaveDto(name, recipeId, materialTypeId, mixMaterials).apply(op) fun mixUpdateDto( - id: Long = 0L, - name: String? = "name", - materialTypeId: Long? = 0L, - mixMaterials: Set? = setOf(), - op: MixUpdateDto.() -> Unit = {} + id: Long = 0L, + name: String? = "name", + materialTypeId: Long? = 0L, + mixMaterials: Set? = setOf(), + op: MixUpdateDto.() -> Unit = {} ) = MixUpdateDto(id, name, materialTypeId, mixMaterials).apply(op) fun mixRatio( - id: Long = 0L, - ratio: Float = 1f, - op: MixDeductDto.() -> Unit = {} + id: Long = 0L, + ratio: Float = 1f, + op: MixDeductDto.() -> Unit = {} ) = MixDeductDto(id, ratio).apply(op) fun mixLocationDto( - mixId: Long = 0L, - location: String? = "location", - op: MixLocationDto.() -> Unit = {} + mixId: Long = 0L, + location: String? = "location", + op: MixLocationDto.() -> Unit = {} ) = MixLocationDto(mixId, location).apply(op) // ==== Exceptions ==== private const val MIX_NOT_FOUND_EXCEPTION_TITLE = "Mix not found" +private const val MIX_ALREADY_EXISTS_EXCEPTION_TITLE = "Mix already exists" private const val MIX_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete mix" private const val MIX_EXCEPTION_ERROR_CODE = "mix" fun mixIdNotFoundException(id: Long) = - NotFoundException( - MIX_EXCEPTION_ERROR_CODE, - MIX_NOT_FOUND_EXCEPTION_TITLE, - "A mix with the id $id could not be found", - id - ) + NotFoundException( + MIX_EXCEPTION_ERROR_CODE, + MIX_NOT_FOUND_EXCEPTION_TITLE, + "A mix with the id $id could not be found", + id + ) + +fun mixIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + MIX_EXCEPTION_ERROR_CODE, + MIX_ALREADY_EXISTS_EXCEPTION_TITLE, + "A mix with the id $id already exists", + id + ) fun cannotDeleteMixException(mix: Mix) = - CannotDeleteException( - MIX_EXCEPTION_ERROR_CODE, - MIX_CANNOT_DELETE_EXCEPTION_TITLE, - "Cannot delete the mix ${mix.mixType.name} because one or more mixes depends on it" - ) + CannotDeleteException( + MIX_EXCEPTION_ERROR_CODE, + MIX_CANNOT_DELETE_EXCEPTION_TITLE, + "Cannot delete the mix ${mix.mixType.name} because one or more mixes depends on it" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixMaterial.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixMaterial.kt index 90d9614..090a9bd 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixMaterial.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixMaterial.kt @@ -1,5 +1,6 @@ package dev.fyloz.colorrecipesexplorer.model +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import javax.persistence.* import javax.validation.constraints.Min @@ -12,54 +13,63 @@ private const val MIX_MATERIAL_DTO_QUANTITY_NEGATIVE_MESSAGE = "La quantité ne @Entity @Table(name = "mix_material") data class MixMaterial( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - @ManyToOne - @JoinColumn(name = "material_id") - val material: Material, + @ManyToOne + @JoinColumn(name = "material_id") + val material: Material, - var quantity: Float, + var quantity: Float, - var position: Int + var position: Int ) : Model data class MixMaterialDto( - @field:NotNull(message = MIX_MATERIAL_DTO_MATERIAL_ID_NULL_MESSAGE) - val materialId: Long, + @field:NotNull(message = MIX_MATERIAL_DTO_MATERIAL_ID_NULL_MESSAGE) + val materialId: Long, - @field:NotNull(message = MIX_MATERIAL_DTO_QUANTITY_NULL_MESSAGE) - @field:Min(value = 0, message = MIX_MATERIAL_DTO_QUANTITY_NEGATIVE_MESSAGE) - val quantity: Float, + @field:NotNull(message = MIX_MATERIAL_DTO_QUANTITY_NULL_MESSAGE) + @field:Min(value = 0, message = MIX_MATERIAL_DTO_QUANTITY_NEGATIVE_MESSAGE) + val quantity: Float, - val position: Int + val position: Int ) // ==== DSL ==== fun mixMaterial( - id: Long? = null, - material: Material = material(), - quantity: Float = 0f, - position: Int = 0, - op: MixMaterial.() -> Unit = {} + id: Long? = null, + material: Material = material(), + quantity: Float = 0f, + position: Int = 0, + op: MixMaterial.() -> Unit = {} ) = MixMaterial(id, material, quantity, position).apply(op) fun mixMaterialDto( - materialId: Long = 0L, - quantity: Float = 0f, - position: Int = 0, - op: MixMaterialDto.() -> Unit = {} + materialId: Long = 0L, + quantity: Float = 0f, + position: Int = 0, + op: MixMaterialDto.() -> Unit = {} ) = MixMaterialDto(materialId, quantity, position).apply(op) // ==== Exceptions ==== private const val MIX_MATERIAL_NOT_FOUND_EXCEPTION_TITLE = "Mix material not found" +private const val MIX_MATERIAL_ALREADY_EXISTS_EXCEPTION_TITLE = "Mix material already exists" private const val MIX_MATERIAL_EXCEPTION_ERROR_CODE = "mixmaterial" fun mixMaterialIdNotFoundException(id: Long) = - NotFoundException( - MIX_MATERIAL_EXCEPTION_ERROR_CODE, - MIX_MATERIAL_NOT_FOUND_EXCEPTION_TITLE, - "A mix material with the id $id could not be found", - id - ) + NotFoundException( + MIX_MATERIAL_EXCEPTION_ERROR_CODE, + MIX_MATERIAL_NOT_FOUND_EXCEPTION_TITLE, + "A mix material with the id $id could not be found", + id + ) + +fun mixMaterialIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + MIX_MATERIAL_EXCEPTION_ERROR_CODE, + MIX_MATERIAL_ALREADY_EXISTS_EXCEPTION_TITLE, + "A mix material with the id $id already exists", + id + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixType.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixType.kt index 8fa0bfc..6281099 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixType.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/MixType.kt @@ -10,34 +10,34 @@ import javax.persistence.* @Entity @Table(name = "mix_type") data class MixType( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - @Column(unique = true) - override var name: String, + @Column(unique = true) + override var name: String, - @OneToOne(cascade = [CascadeType.ALL]) - @JoinColumn(name = "material_id") - var material: Material + @OneToOne(cascade = [CascadeType.ALL]) + @JoinColumn(name = "material_id") + var material: Material ) : NamedModel // ==== DSL ==== fun mixType( - id: Long? = null, - name: String = "name", - material: Material = material(), - op: MixType.() -> Unit = {} + id: Long? = null, + name: String = "name", + material: Material = material(), + op: MixType.() -> Unit = {} ) = MixType(id, name, material).apply(op) fun mixType( - name: String = "name", - materialType: MaterialType = materialType(), - op: MixType.() -> Unit = {} + name: String = "name", + materialType: MaterialType = materialType(), + op: MixType.() -> Unit = {} ) = mixType( - id = null, - name, - material = material(name = name, inventoryQuantity = 0f, isMixType = true, materialType = materialType) + id = null, + name, + material = material(name = name, inventoryQuantity = 0f, isMixType = true, materialType = materialType) ).apply(op) // ==== Exceptions ==== @@ -47,46 +47,54 @@ private const val MIX_TYPE_CANNOT_DELETE_EXCEPTION_TITLE = "Cannot delete mix ty private const val MIX_TYPE_EXCEPTION_ERROR_CODE = "mixtype" class MixTypeNameAndMaterialTypeNotFoundException(name: String, materialType: MaterialType) : - RestException( - "notfound-mixtype-namematerialtype", - MIX_TYPE_NOT_FOUND_EXCEPTION_TITLE, - HttpStatus.NOT_FOUND, - "A mix type with the name $name and material type ${materialType.name} could not be found", - mapOf( - "name" to name, - "materialType" to materialType.name - ) + RestException( + "notfound-mixtype-namematerialtype", + MIX_TYPE_NOT_FOUND_EXCEPTION_TITLE, + HttpStatus.NOT_FOUND, + "A mix type with the name $name and material type ${materialType.name} could not be found", + mapOf( + "name" to name, + "materialType" to materialType.name ) + ) fun mixTypeIdNotFoundException(id: Long) = - NotFoundException( - MIX_TYPE_EXCEPTION_ERROR_CODE, - MIX_TYPE_NOT_FOUND_EXCEPTION_TITLE, - "A mix type with the id $id could not be found", - id - ) + NotFoundException( + MIX_TYPE_EXCEPTION_ERROR_CODE, + MIX_TYPE_NOT_FOUND_EXCEPTION_TITLE, + "A mix type with the id $id could not be found", + id + ) + +fun mixTypeIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + MIX_TYPE_EXCEPTION_ERROR_CODE, + MIX_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, + "A mix type with the id $id already exists", + id + ) fun mixTypeNameNotFoundException(name: String) = - NotFoundException( - MIX_TYPE_EXCEPTION_ERROR_CODE, - MIX_TYPE_NOT_FOUND_EXCEPTION_TITLE, - "A mix type with the name $name could not be found", - name, - "name" - ) + NotFoundException( + MIX_TYPE_EXCEPTION_ERROR_CODE, + MIX_TYPE_NOT_FOUND_EXCEPTION_TITLE, + "A mix type with the name $name could not be found", + name, + "name" + ) fun mixTypeNameAlreadyExistsException(name: String) = - AlreadyExistsException( - MIX_TYPE_EXCEPTION_ERROR_CODE, - MIX_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, - "A mix type with the name $name already exists", - name, - "name" - ) + AlreadyExistsException( + MIX_TYPE_EXCEPTION_ERROR_CODE, + MIX_TYPE_ALREADY_EXISTS_EXCEPTION_TITLE, + "A mix type with the name $name already exists", + name, + "name" + ) fun cannotDeleteMixTypeException(mixType: MixType) = - CannotDeleteException( - MIX_TYPE_EXCEPTION_ERROR_CODE, - MIX_TYPE_CANNOT_DELETE_EXCEPTION_TITLE, - "Cannot delete the mix type ${mixType.name} because one or more mixes depends on it" - ) + CannotDeleteException( + MIX_TYPE_EXCEPTION_ERROR_CODE, + MIX_TYPE_CANNOT_DELETE_EXCEPTION_TITLE, + "Cannot delete the mix type ${mixType.name} because one or more mixes depends on it" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Recipe.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Recipe.kt index b047f8f..8d32a87 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Recipe.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/Recipe.kt @@ -1,6 +1,7 @@ package dev.fyloz.colorrecipesexplorer.model import com.fasterxml.jackson.annotation.JsonIgnore +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.exception.RestException import dev.fyloz.colorrecipesexplorer.model.validation.NullOrNotBlank @@ -27,39 +28,39 @@ private const val NOTE_GROUP_ID_NULL_MESSAGE = "Un identifiant de groupe est req @Entity @Table(name = "recipe") data class Recipe( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - /** The name of the recipe. It is not unique in the entire system, but is unique in the scope of a [Company]. */ - val name: String, + /** The name of the recipe. It is not unique in the entire system, but is unique in the scope of a [Company]. */ + val name: String, - val description: String, + val description: String, - /** The color produced by the recipe. The string should be formatted as a hexadecimal color without the sharp (#). */ - val color: String, + /** The color produced by the recipe. The string should be formatted as a hexadecimal color without the sharp (#). */ + val color: String, - /** The gloss of the color in percents. (0-100) */ - val gloss: Byte, + /** The gloss of the color in percents. (0-100) */ + val gloss: Byte, - val sample: Int?, + val sample: Int?, - @Column(name = "approbation_date") - val approbationDate: LocalDate?, + @Column(name = "approbation_date") + val approbationDate: LocalDate?, - /** A remark given by the creator of the recipe. */ - val remark: String, + /** A remark given by the creator of the recipe. */ + val remark: String, - @ManyToOne - @JoinColumn(name = "company_id") - val company: Company, + @ManyToOne + @JoinColumn(name = "company_id") + val company: Company, - @OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe") - val mixes: MutableList, + @OneToMany(cascade = [CascadeType.ALL], mappedBy = "recipe") + val mixes: MutableList, - @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true) - @JoinColumn(name = "recipe_id") - val groupsInformation: Set + @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true) + @JoinColumn(name = "recipe_id") + val groupsInformation: Set ) : Model { /** The mix types contained in this recipe. */ val mixTypes: Collection @@ -67,209 +68,218 @@ data class Recipe( get() = mixes.map { it.mixType } fun groupInformationForGroup(groupId: Long) = - groupsInformation.firstOrNull { it.group.id == groupId } + groupsInformation.firstOrNull { it.group.id == groupId } } open class RecipeSaveDto( - @field:NotBlank(message = RECIPE_NAME_NULL_MESSAGE) - val name: String, + @field:NotBlank(message = RECIPE_NAME_NULL_MESSAGE) + val name: String, - @field:NotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE) - val description: String, + @field:NotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE) + val description: String, - @field:NotBlank(message = RECIPE_COLOR_NULL_MESSAGE) - @field:Pattern(regexp = "^#([0-9a-f]{6})$") - val color: String, + @field:NotBlank(message = RECIPE_COLOR_NULL_MESSAGE) + @field:Pattern(regexp = "^#([0-9a-f]{6})$") + val color: String, - @field:NotNull(message = RECIPE_GLOSS_NULL_MESSAGE) - @field:Min(value = 0, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) - @field:Max(value = 100, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) - val gloss: Byte, + @field:NotNull(message = RECIPE_GLOSS_NULL_MESSAGE) + @field:Min(value = 0, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) + @field:Max(value = 100, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) + val gloss: Byte, - @field:Min(value = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE) - val sample: Int?, + @field:Min(value = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE) + val sample: Int?, - val approbationDate: LocalDate?, + val approbationDate: LocalDate?, - val remark: String?, + val remark: String?, - @field:Min(value = 0, message = RECIPE_COMPANY_NULL_MESSAGE) - val companyId: Long = -1L, + @field:Min(value = 0, message = RECIPE_COMPANY_NULL_MESSAGE) + val companyId: Long = -1L, ) : EntityDto { override fun toEntity(): Recipe = recipe( - name = name, - description = description, - sample = sample, - approbationDate = approbationDate, - remark = remark ?: "", - company = company(id = companyId) + name = name, + description = description, + sample = sample, + approbationDate = approbationDate, + remark = remark ?: "", + company = company(id = companyId) ) } open class RecipeUpdateDto( - @field:NotNull(message = RECIPE_ID_NULL_MESSAGE) - val id: Long, + @field:NotNull(message = RECIPE_ID_NULL_MESSAGE) + val id: Long, - @field:NullOrNotBlank(message = RECIPE_NAME_NULL_MESSAGE) - val name: String?, + @field:NullOrNotBlank(message = RECIPE_NAME_NULL_MESSAGE) + val name: String?, - @field:NullOrNotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE) - val description: String?, + @field:NullOrNotBlank(message = RECIPE_DESCRIPTION_NULL_MESSAGE) + val description: String?, - @field:NullOrNotBlank(message = RECIPE_COLOR_NULL_MESSAGE) - @field:Pattern(regexp = "^#([0-9a-f]{6})$") - val color: String?, + @field:NullOrNotBlank(message = RECIPE_COLOR_NULL_MESSAGE) + @field:Pattern(regexp = "^#([0-9a-f]{6})$") + val color: String?, - @field:Min(value = 0, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) - @field:Max(value = 100, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) - val gloss: Byte?, + @field:Min(value = 0, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) + @field:Max(value = 100, message = RECIPE_GLOSS_OUTSIDE_RANGE_MESSAGE) + val gloss: Byte?, - @field:NullOrSize(min = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE) - val sample: Int?, + @field:NullOrSize(min = 0, message = RECIPE_SAMPLE_TOO_SMALL_MESSAGE) + val sample: Int?, - val approbationDate: LocalDate?, + val approbationDate: LocalDate?, - val remark: String?, + val remark: String?, - val steps: Set? + val steps: Set? ) : EntityDto @Entity @Table(name = "recipe_group_information") data class RecipeGroupInformation( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + val id: Long?, - @ManyToOne - @JoinColumn(name = "group_id") - val group: EmployeeGroup, + @ManyToOne + @JoinColumn(name = "group_id") + val group: EmployeeGroup, - var note: String?, + var note: String?, - @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true) - @JoinColumn(name = "recipe_group_information_id") - var steps: MutableSet? + @OneToMany(cascade = [CascadeType.ALL], fetch = FetchType.EAGER, orphanRemoval = true) + @JoinColumn(name = "recipe_group_information_id") + var steps: MutableSet? ) data class RecipeStepsDto( - @field:NotNull(message = RECIPE_STEPS_DTO_GROUP_ID_NULL_MESSAGE) - val groupId: Long, + @field:NotNull(message = RECIPE_STEPS_DTO_GROUP_ID_NULL_MESSAGE) + val groupId: Long, - @field:NotNull(message = RECIPE_STEPS_DTO_MESSAGES_NULL_MESSAGE) - val steps: Set + @field:NotNull(message = RECIPE_STEPS_DTO_MESSAGES_NULL_MESSAGE) + val steps: Set ) data class RecipePublicDataDto( - @field:NotNull(message = RECIPE_ID_NULL_MESSAGE) - val recipeId: Long, + @field:NotNull(message = RECIPE_ID_NULL_MESSAGE) + val recipeId: Long, - val notes: Set?, + val notes: Set?, - val mixesLocation: Set? + val mixesLocation: Set? ) data class NoteDto( - @field:NotNull(message = NOTE_GROUP_ID_NULL_MESSAGE) - val groupId: Long, + @field:NotNull(message = NOTE_GROUP_ID_NULL_MESSAGE) + val groupId: Long, - val content: String? + val content: String? ) // ==== DSL ==== fun recipe( - id: Long? = null, - name: String = "name", - description: String = "description", - color: String = "ffffff", - gloss: Byte = 0, - sample: Int? = -1, - approbationDate: LocalDate? = LocalDate.MIN, - remark: String = "remark", - company: Company = company(), - mixes: MutableList = mutableListOf(), - groupsInformation: Set = setOf(), - op: Recipe.() -> Unit = {} + id: Long? = null, + name: String = "name", + description: String = "description", + color: String = "ffffff", + gloss: Byte = 0, + sample: Int? = -1, + approbationDate: LocalDate? = LocalDate.MIN, + remark: String = "remark", + company: Company = company(), + mixes: MutableList = mutableListOf(), + groupsInformation: Set = setOf(), + op: Recipe.() -> Unit = {} ) = Recipe( - id, - name, - description, - color, - gloss, - sample, - approbationDate, - remark, - company, - mixes, - groupsInformation + id, + name, + description, + color, + gloss, + sample, + approbationDate, + remark, + company, + mixes, + groupsInformation ).apply(op) fun recipeSaveDto( - name: String = "name", - description: String = "description", - color: String = "ffffff", - gloss: Byte = 0, - sample: Int? = -1, - approbationDate: LocalDate? = LocalDate.MIN, - remark: String = "remark", - companyId: Long = 0L, - op: RecipeSaveDto.() -> Unit = {} + name: String = "name", + description: String = "description", + color: String = "ffffff", + gloss: Byte = 0, + sample: Int? = -1, + approbationDate: LocalDate? = LocalDate.MIN, + remark: String = "remark", + companyId: Long = 0L, + op: RecipeSaveDto.() -> Unit = {} ) = RecipeSaveDto(name, description, color, gloss, sample, approbationDate, remark, companyId).apply(op) fun recipeUpdateDto( - id: Long = 0L, - name: String? = "name", - description: String? = "description", - color: String? = "ffffff", - gloss: Byte? = 0, - sample: Int? = -1, - approbationDate: LocalDate? = LocalDate.MIN, - remark: String? = "remark", - steps: Set? = setOf(), - op: RecipeUpdateDto.() -> Unit = {} + id: Long = 0L, + name: String? = "name", + description: String? = "description", + color: String? = "ffffff", + gloss: Byte? = 0, + sample: Int? = -1, + approbationDate: LocalDate? = LocalDate.MIN, + remark: String? = "remark", + steps: Set? = setOf(), + op: RecipeUpdateDto.() -> Unit = {} ) = RecipeUpdateDto(id, name, description, color, gloss, sample, approbationDate, remark, steps).apply(op) fun recipeGroupInformation( - id: Long? = null, - group: EmployeeGroup = employeeGroup(), - note: String? = null, - steps: MutableSet? = mutableSetOf(), - op: RecipeGroupInformation.() -> Unit = {} + id: Long? = null, + group: EmployeeGroup = employeeGroup(), + note: String? = null, + steps: MutableSet? = mutableSetOf(), + op: RecipeGroupInformation.() -> Unit = {} ) = RecipeGroupInformation(id, group, note, steps).apply(op) fun recipePublicDataDto( - recipeId: Long = 0L, - notes: Set? = null, - mixesLocation: Set? = null, - op: RecipePublicDataDto.() -> Unit = {} + recipeId: Long = 0L, + notes: Set? = null, + mixesLocation: Set? = null, + op: RecipePublicDataDto.() -> Unit = {} ) = RecipePublicDataDto(recipeId, notes, mixesLocation).apply(op) fun noteDto( - groupId: Long = 0L, - content: String? = "note", - op: NoteDto.() -> Unit = {} + groupId: Long = 0L, + content: String? = "note", + op: NoteDto.() -> Unit = {} ) = NoteDto(groupId, content).apply(op) // ==== Exceptions ==== private const val RECIPE_NOT_FOUND_EXCEPTION_TITLE = "Recipe not found" +private const val RECIPE_ALREADY_EXISTS_EXCEPTION_TITLE = "Recipe already exists" private const val RECIPE_EXCEPTION_ERROR_CODE = "recipe" class RecipeImageNotFoundException(id: Long, recipe: Recipe) : - RestException( - "notfound-recipeimage-id", - "Recipe image not found", - HttpStatus.NOT_FOUND, - "A recipe image with the id $id could no be found for the recipe ${recipe.name}", - mapOf( - "id" to id, - "recipe" to recipe.name - ) + RestException( + "notfound-recipeimage-id", + "Recipe image not found", + HttpStatus.NOT_FOUND, + "A recipe image with the id $id could no be found for the recipe ${recipe.name}", + mapOf( + "id" to id, + "recipe" to recipe.name ) + ) fun recipeIdNotFoundException(id: Long) = - NotFoundException( - RECIPE_EXCEPTION_ERROR_CODE, - RECIPE_NOT_FOUND_EXCEPTION_TITLE, - "A recipe with the id $id could not be found", - id - ) + NotFoundException( + RECIPE_EXCEPTION_ERROR_CODE, + RECIPE_NOT_FOUND_EXCEPTION_TITLE, + "A recipe with the id $id could not be found", + id + ) + +fun recipeIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + RECIPE_EXCEPTION_ERROR_CODE, + RECIPE_ALREADY_EXISTS_EXCEPTION_TITLE, + "A recipe with the id $id already exists", + id + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/RecipeStep.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/RecipeStep.kt index 830c348..1f5a3a7 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/RecipeStep.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/RecipeStep.kt @@ -1,36 +1,46 @@ package dev.fyloz.colorrecipesexplorer.model +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import javax.persistence.* @Entity @Table(name = "recipe_step") data class RecipeStep( - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - override val id: Long?, + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + override val id: Long?, - val position: Int, + val position: Int, - val message: String + val message: String ) : Model // ==== DSL ==== fun recipeStep( - id: Long? = null, - position: Int = 0, - message: String = "message", - op: RecipeStep.() -> Unit = {} + id: Long? = null, + position: Int = 0, + message: String = "message", + op: RecipeStep.() -> Unit = {} ) = RecipeStep(id, position, message).apply(op) // ==== Exceptions ==== private const val RECIPE_STEP_NOT_FOUND_EXCEPTION_TITLE = "Recipe step not found" +private const val RECIPE_STEP_ALREADY_EXISTS_EXCEPTION_TITLE = "Recipe step already exists" private const val RECIPE_STEP_EXCEPTION_ERROR_CODE = "recipestep" fun recipeStepIdNotFoundException(id: Long) = - NotFoundException( - RECIPE_STEP_EXCEPTION_ERROR_CODE, - RECIPE_STEP_NOT_FOUND_EXCEPTION_TITLE, - "A recipe step with the id $id could not be found", - id - ) + NotFoundException( + RECIPE_STEP_EXCEPTION_ERROR_CODE, + RECIPE_STEP_NOT_FOUND_EXCEPTION_TITLE, + "A recipe step with the id $id could not be found", + id + ) + +fun recipeStepIdAlreadyExistsException(id: Long) = + AlreadyExistsException( + RECIPE_STEP_EXCEPTION_ERROR_CODE, + RECIPE_STEP_ALREADY_EXISTS_EXCEPTION_TITLE, + "A recipe step with the id $id already exists", + id + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrNotBlank.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrNotBlank.kt index 6ad2763..9a381b9 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrNotBlank.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrNotBlank.kt @@ -14,9 +14,9 @@ private const val MESSAGE = "must be null or not blank" @MustBeDocumented @Constraint(validatedBy = [NullOrNotBlankValidator::class]) annotation class NullOrNotBlank( - val message: String = MESSAGE, - val groups: Array> = [], - @Suppress("unused") val payload: Array> = [] + val message: String = MESSAGE, + val groups: Array> = [], + @Suppress("unused") val payload: Array> = [] ) class NullOrNotBlankValidator : ConstraintValidator { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrSize.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrSize.kt index a546664..e6c4208 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrSize.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/model/validation/NullOrSize.kt @@ -14,11 +14,11 @@ private const val MESSAGE = "must be null or have a correct length" @MustBeDocumented @Constraint(validatedBy = [NullOrSizeValidator::class]) annotation class NullOrSize( - val min: Long = MIN_SIZE, - val max: Long = MAX_SIZE, - val message: String = MESSAGE, - val groups: Array> = [], - @Suppress("unused") val payload: Array> = [] + val min: Long = MIN_SIZE, + val max: Long = MAX_SIZE, + val message: String = MESSAGE, + val groups: Array> = [], + @Suppress("unused") val payload: Array> = [] ) class NullOrSizeValidator : ConstraintValidator { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/CompanyRepository.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/CompanyRepository.kt index 2d2ec80..b0b4142 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/CompanyRepository.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/CompanyRepository.kt @@ -7,7 +7,7 @@ import org.springframework.stereotype.Repository @Repository interface CompanyRepository : NamedJpaRepository { @Query( - """ + """ select case when(count(r.id) > 0) then false else true end from Company c left join Recipe r on c.id = r.company.id diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepository.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepository.kt index 63c633d..03ed9c3 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepository.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepository.kt @@ -17,7 +17,7 @@ interface MaterialRepository : NamedJpaRepository { fun updateInventoryQuantityById(id: Long, inventoryQuantity: Float) @Query( - """ + """ select case when(count(mm.id) + count(mt.id) > 0) then false else true end from Material m left join MixMaterial mm on m.id = mm.material.id diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialTypeRepository.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialTypeRepository.kt index e07c248..a664876 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialTypeRepository.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialTypeRepository.kt @@ -16,7 +16,7 @@ interface MaterialTypeRepository : NamedJpaRepository { fun findByPrefix(prefix: String): MaterialType? @Query( - """ + """ select case when(count(m.id) > 0) then false else true end from MaterialType t left join Material m on t.id = m.materialType.id diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepository.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepository.kt index b3a4f0a..51c39a9 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepository.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepository.kt @@ -16,7 +16,7 @@ interface MixRepository : JpaRepository { fun updateLocationById(id: Long, location: String?) @Query( - """ + """ select case when(count(mm.id) > 0) then false else true end from Mix m left join MixMaterial mm on m.mixType.material.id = mm.material.id diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixTypeRepository.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixTypeRepository.kt index 732e57c..7298eb6 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixTypeRepository.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixTypeRepository.kt @@ -19,7 +19,7 @@ interface MixTypeRepository : NamedJpaRepository { fun findByNameAndMaterialType(name: String, materialType: MaterialType): MixType? @Query( - """ + """ select case when(count(m.id) > 0) then false else true end from MixType t left join Mix m on t.id = m.mixType.id diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/AccountControllers.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/AccountControllers.kt index 8e89f85..0776aa5 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/AccountControllers.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/AccountControllers.kt @@ -23,52 +23,52 @@ class EmployeeController(private val employeeService: EmployeeService) { @GetMapping @PreAuthorizeViewUsers fun getAll() = - ok(employeeService.getAll()) + ok(employeeService.getAll()) @GetMapping("{id}") @PreAuthorizeViewUsers fun getById(@PathVariable id: Long) = - ok(employeeService.getById(id)) + ok(employeeService.getById(id)) @GetMapping("current") fun getCurrent(loggedInEmployee: Principal?) = - if (loggedInEmployee != null) - ok( - employeeService.getById( - loggedInEmployee.name.toLong(), - ignoreDefaultGroupUsers = false, - ignoreSystemUsers = false - ) + if (loggedInEmployee != null) + ok( + employeeService.getById( + loggedInEmployee.name.toLong(), + ignoreDefaultGroupUsers = false, + ignoreSystemUsers = false ) - else - forbidden() + ) + else + forbidden() @PostMapping @PreAuthorizeEditUsers fun save(@Valid @RequestBody employee: EmployeeSaveDto) = - created(EMPLOYEE_CONTROLLER_PATH) { - employeeService.save(employee) - } + created(EMPLOYEE_CONTROLLER_PATH) { + employeeService.save(employee) + } @PutMapping @PreAuthorizeEditUsers fun update(@Valid @RequestBody employee: EmployeeUpdateDto) = - noContent { - employeeService.update(employee) - } + noContent { + employeeService.update(employee) + } @PutMapping("{id}/password", consumes = [MediaType.TEXT_PLAIN_VALUE]) @PreAuthorizeEditUsers fun updatePassword(@PathVariable id: Long, @RequestBody password: String) = - noContent { - employeeService.updatePassword(id, password) - } + noContent { + employeeService.updatePassword(id, password) + } @PutMapping("{employeeId}/permissions/{permission}") @PreAuthorizeEditUsers fun addPermission( - @PathVariable employeeId: Long, - @PathVariable permission: EmployeePermission + @PathVariable employeeId: Long, + @PathVariable permission: EmployeePermission ) = noContent { employeeService.addPermission(employeeId, permission) } @@ -76,8 +76,8 @@ class EmployeeController(private val employeeService: EmployeeService) { @DeleteMapping("{employeeId}/permissions/{permission}") @PreAuthorizeEditUsers fun removePermission( - @PathVariable employeeId: Long, - @PathVariable permission: EmployeePermission + @PathVariable employeeId: Long, + @PathVariable permission: EmployeePermission ) = noContent { employeeService.removePermission(employeeId, permission) } @@ -85,7 +85,7 @@ class EmployeeController(private val employeeService: EmployeeService) { @DeleteMapping("{id}") @PreAuthorizeRemoveUsers fun deleteById(@PathVariable id: Long) = - employeeService.deleteById(id) + employeeService.deleteById(id) } @RestController @@ -94,50 +94,50 @@ class GroupsController(private val groupService: EmployeeGroupServiceImpl) { @GetMapping @PreAuthorize("hasAnyAuthority('VIEW_RECIPES', 'VIEW_USERS')") fun getAll() = - ok(groupService.getAll()) + ok(groupService.getAll()) @GetMapping("{id}") @PreAuthorizeViewUsers fun getById(@PathVariable id: Long) = - ok(groupService.getById(id)) + ok(groupService.getById(id)) @GetMapping("{id}/employees") @PreAuthorizeViewUsers fun getEmployeesForGroup(@PathVariable id: Long) = - ok(groupService.getEmployeesForGroup(id)) + ok(groupService.getEmployeesForGroup(id)) @PostMapping("default/{groupId}") @PreAuthorizeViewUsers fun setDefaultGroup(@PathVariable groupId: Long, response: HttpServletResponse) = - noContent { - groupService.setResponseDefaultGroup(groupId, response) - } + noContent { + groupService.setResponseDefaultGroup(groupId, response) + } @GetMapping("default") @PreAuthorizeViewUsers fun getRequestDefaultGroup(request: HttpServletRequest) = - ok(groupService.getRequestDefaultGroup(request)) + ok(groupService.getRequestDefaultGroup(request)) @PostMapping @PreAuthorizeEditUsers fun save(@Valid @RequestBody group: EmployeeGroupSaveDto) = - created(EMPLOYEE_GROUP_CONTROLLER_PATH) { - groupService.save(group) - } + created(EMPLOYEE_GROUP_CONTROLLER_PATH) { + groupService.save(group) + } @PutMapping @PreAuthorizeEditUsers fun update(@Valid @RequestBody group: EmployeeGroupUpdateDto) = - noContent { - groupService.update(group) - } + noContent { + groupService.update(group) + } @DeleteMapping("{id}") @PreAuthorizeRemoveUsers fun deleteById(@PathVariable id: Long) = - noContent { - groupService.deleteById(id) - } + noContent { + groupService.deleteById(id) + } } @RestController @@ -145,7 +145,7 @@ class GroupsController(private val groupService: EmployeeGroupServiceImpl) { class LogoutController(private val employeeService: EmployeeService) { @GetMapping("logout") fun logout(request: HttpServletRequest) = - ok { - employeeService.logout(request) - } + ok { + employeeService.logout(request) + } } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/CompanyController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/CompanyController.kt index bf690b4..ef59303 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/CompanyController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/CompanyController.kt @@ -17,30 +17,30 @@ private const val COMPANY_CONTROLLER_PATH = "api/company" class CompanyController(private val companyService: CompanyService) { @GetMapping fun getAll() = - ok(companyService.getAll()) + ok(companyService.getAll()) @GetMapping("{id}") fun getById(@PathVariable id: Long) = - ok(companyService.getById(id)) + ok(companyService.getById(id)) @PostMapping @PreAuthorize("hasAuthority('EDIT_COMPANIES')") fun save(@Valid @RequestBody company: CompanySaveDto) = - created(COMPANY_CONTROLLER_PATH) { - companyService.save(company) - } + created(COMPANY_CONTROLLER_PATH) { + companyService.save(company) + } @PutMapping @PreAuthorize("hasAuthority('EDIT_COMPANIES')") fun update(@Valid @RequestBody company: CompanyUpdateDto) = - noContent { - companyService.update(company) - } + noContent { + companyService.update(company) + } @DeleteMapping("{id}") @PreAuthorize("hasAuthority('REMOVE_COMPANIES')") fun deleteById(@PathVariable id: Long) = - noContent { - companyService.deleteById(id) - } + noContent { + companyService.deleteById(id) + } } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/InventoryController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/InventoryController.kt index 5971d86..832e14d 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/InventoryController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/InventoryController.kt @@ -15,7 +15,7 @@ private const val INVENTORY_CONTROLLER_PATH = "api/inventory" @RestController @RequestMapping(INVENTORY_CONTROLLER_PATH) class InventoryController( - private val inventoryService: InventoryService + private val inventoryService: InventoryService ) { @PutMapping("add") @PreAuthorize("hasAuthority('ADD_TO_INVENTORY')") @@ -26,10 +26,10 @@ class InventoryController( @PutMapping("deduct") @PreAuthorize("hasAuthority('DEDUCT_FROM_INVENTORY')") fun deduct(@RequestBody quantities: Collection) = - ok(inventoryService.deduct(quantities)) + ok(inventoryService.deduct(quantities)) @PutMapping("deduct/mix") @PreAuthorize("hasAuthority('DEDUCT_FROM_INVENTORY')") fun deduct(@RequestBody mixRatio: MixDeductDto) = - ok(inventoryService.deductMix(mixRatio)) + ok(inventoryService.deductMix(mixRatio)) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialController.kt index 39df895..a44d493 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialController.kt @@ -18,55 +18,55 @@ private const val MATERIAL_CONTROLLER_PATH = "api/material" class MaterialController(private val materialService: MaterialService) { @GetMapping fun getAll() = - ok(materialService.getAll()) + ok(materialService.getAll()) @GetMapping("notmixtype") fun getAllNotMixType() = - ok(materialService.getAllNotMixType()) + ok(materialService.getAllNotMixType()) @GetMapping("{id}") fun getById(@PathVariable id: Long) = - ok(materialService.getById(id)) + ok(materialService.getById(id)) @PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @PreAuthorize("hasAuthority('EDIT_MATERIALS')") fun save(@Valid material: MaterialSaveDto, simdutFile: MultipartFile?) = - created(MATERIAL_CONTROLLER_PATH) { - materialService.save( - materialSaveDto( - name = material.name, - inventoryQuantity = material.inventoryQuantity, - materialTypeId = material.materialTypeId, - simdutFile = simdutFile - ) + created(MATERIAL_CONTROLLER_PATH) { + materialService.save( + materialSaveDto( + name = material.name, + inventoryQuantity = material.inventoryQuantity, + materialTypeId = material.materialTypeId, + simdutFile = simdutFile ) - } + ) + } @PutMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @PreAuthorize("hasAuthority('EDIT_MATERIALS')") fun update(@Valid material: MaterialUpdateDto, simdutFile: MultipartFile?) = - noContent { - materialService.update( - materialUpdateDto( - id = material.id, - name = material.name, - inventoryQuantity = material.inventoryQuantity, - materialTypeId = material.materialTypeId, - simdutFile = simdutFile - ) + noContent { + materialService.update( + materialUpdateDto( + id = material.id, + name = material.name, + inventoryQuantity = material.inventoryQuantity, + materialTypeId = material.materialTypeId, + simdutFile = simdutFile ) - } + ) + } @DeleteMapping("{id}") @PreAuthorize("hasAuthority('REMOVE_MATERIALS')") fun deleteById(@PathVariable id: Long) = - noContent { - materialService.deleteById(id) - } + noContent { + materialService.deleteById(id) + } @GetMapping("{id}/simdut/exists") fun hasSimdut(@PathVariable id: Long) = - ok(materialService.hasSimdut(id)) + ok(materialService.hasSimdut(id)) @GetMapping("{id}/simdut", produces = [MediaType.APPLICATION_PDF_VALUE]) fun getSimdut(@PathVariable id: Long): ResponseEntity = with(materialService.getSimdut(id)) { @@ -79,14 +79,14 @@ class MaterialController(private val materialService: MaterialService) { @GetMapping("/simdut") fun getAllIdsWithSimdut() = - ok(materialService.getAllIdsWithSimdut()) + ok(materialService.getAllIdsWithSimdut()) @GetMapping("mix/create/{recipeId}") fun getAllForMixCreation(@PathVariable recipeId: Long) = - ok(materialService.getAllForMixCreation(recipeId)) + ok(materialService.getAllForMixCreation(recipeId)) @GetMapping("mix/update/{mixId}") fun getAllForMixUpdate(@PathVariable mixId: Long) = - ok(materialService.getAllForMixUpdate(mixId)) + ok(materialService.getAllForMixUpdate(mixId)) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialTypeController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialTypeController.kt index 6123066..3991873 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialTypeController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/MaterialTypeController.kt @@ -17,31 +17,31 @@ private const val MATERIAL_TYPE_CONTROLLER_PATH = "api/materialtype" class MaterialTypeController(private val materialTypeService: MaterialTypeService) { @GetMapping fun getAll() = - ok(materialTypeService.getAll()) + ok(materialTypeService.getAll()) @GetMapping("{id}") fun getById(@PathVariable id: Long) = - ok(materialTypeService.getById(id)) + ok(materialTypeService.getById(id)) @PostMapping @PreAuthorize("hasAuthority('EDIT_MATERIAL_TYPES')") fun save(@Valid @RequestBody materialType: MaterialTypeSaveDto) = - created(MATERIAL_TYPE_CONTROLLER_PATH) { - materialTypeService.save(materialType) - } + created(MATERIAL_TYPE_CONTROLLER_PATH) { + materialTypeService.save(materialType) + } @PutMapping @PreAuthorize("hasAuthority('EDIT_MATERIAL_TYPES')") fun update(@Valid @RequestBody materialType: MaterialTypeUpdateDto) = - noContent { - materialTypeService.update(materialType) - } + noContent { + materialTypeService.update(materialType) + } @DeleteMapping("{id}") @PreAuthorize("hasAuthority('REMOVE_MATERIAL_TYPES')") fun deleteById(@PathVariable id: Long) = - noContent { - materialTypeService.deleteById(id) - } + noContent { + materialTypeService.deleteById(id) + } } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RecipeController.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RecipeController.kt index 0d81d5d..a4f39fc 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RecipeController.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RecipeController.kt @@ -25,39 +25,39 @@ private const val MIX_CONTROLLER_PATH = "api/recipe/mix" class RecipeController(private val recipeService: RecipeService) { @GetMapping fun getAll() = - ok(recipeService.getAll()) + ok(recipeService.getAll()) @GetMapping("{id}") fun getById(@PathVariable id: Long) = - ok(recipeService.getById(id)) + ok(recipeService.getById(id)) @PostMapping @PreAuthorizeEditRecipes fun save(@Valid @RequestBody recipe: RecipeSaveDto) = - created(RECIPE_CONTROLLER_PATH) { - recipeService.save(recipe) - } + created(RECIPE_CONTROLLER_PATH) { + recipeService.save(recipe) + } @PutMapping @PreAuthorizeEditRecipes fun update(@Valid @RequestBody recipe: RecipeUpdateDto) = - noContent { - recipeService.update(recipe) - } + noContent { + recipeService.update(recipe) + } @PutMapping("public") @PreAuthorize("hasAuthority('EDIT_RECIPES_PUBLIC_DATA')") fun updatePublicData(@Valid @RequestBody publicDataDto: RecipePublicDataDto) = - noContent { - recipeService.updatePublicData(publicDataDto) - } + noContent { + recipeService.updatePublicData(publicDataDto) + } @DeleteMapping("{id}") @PreAuthorizeRemoveRecipes fun deleteById(@PathVariable id: Long) = - noContent { - recipeService.deleteById(id) - } + noContent { + recipeService.deleteById(id) + } } @RestController @@ -66,11 +66,11 @@ class RecipeController(private val recipeService: RecipeService) { class RecipeImageController(val recipeImageService: RecipeImageService) { @GetMapping("{recipeId}/image") fun getAllIdsForRecipe(@PathVariable recipeId: Long) = - ok(recipeImageService.getAllIdsForRecipe(recipeId)) + ok(recipeImageService.getAllIdsForRecipe(recipeId)) @GetMapping("{recipeId}/image/{id}", produces = [MediaType.IMAGE_JPEG_VALUE, MediaType.IMAGE_PNG_VALUE]) fun getById(@PathVariable recipeId: Long, @PathVariable id: Long) = - ok(recipeImageService.getByIdForRecipe(id, recipeId)) + ok(recipeImageService.getByIdForRecipe(id, recipeId)) @PostMapping("{recipeId}/image", consumes = [MediaType.MULTIPART_FORM_DATA_VALUE]) @PreAuthorizeEditRecipes @@ -82,9 +82,9 @@ class RecipeImageController(val recipeImageService: RecipeImageService) { @DeleteMapping("{recipeId}/image/{id}") @PreAuthorizeRemoveRecipes fun delete(@PathVariable recipeId: Long, @PathVariable id: Long) = - noContent { - recipeImageService.delete(id, recipeId) - } + noContent { + recipeImageService.delete(id, recipeId) + } } @RestController @@ -93,26 +93,26 @@ class RecipeImageController(val recipeImageService: RecipeImageService) { class MixController(private val mixService: MixService) { @GetMapping("{id}") fun getById(@PathVariable id: Long) = - ok(mixService.getById(id)) + ok(mixService.getById(id)) @PostMapping @PreAuthorizeEditRecipes fun save(@Valid @RequestBody mix: MixSaveDto) = - created(MIX_CONTROLLER_PATH) { - mixService.save(mix) - } + created(MIX_CONTROLLER_PATH) { + mixService.save(mix) + } @PutMapping @PreAuthorizeEditRecipes fun update(@Valid @RequestBody mix: MixUpdateDto) = - noContent { - mixService.update(mix) - } + noContent { + mixService.update(mix) + } @DeleteMapping("{id}") @PreAuthorizeRemoveRecipes fun deleteById(@PathVariable id: Long) = - noContent { - mixService.deleteById(id) - } + noContent { + mixService.deleteById(id) + } } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RestUtils.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RestUtils.kt index 0c0de8a..46004d1 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RestUtils.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/rest/RestUtils.kt @@ -9,11 +9,11 @@ import java.net.URI /** Creates a HTTP OK [ResponseEntity] from the given [body]. */ fun ok(body: T): ResponseEntity = - ResponseEntity.ok(body) + ResponseEntity.ok(body) /** Creates a HTTP OK [ResponseEntity] from the given [body] and [headers]. */ fun ok(body: T, headers: HttpHeaders): ResponseEntity = - ResponseEntity(body, headers, HttpStatus.OK) + ResponseEntity(body, headers, HttpStatus.OK) /** Executes the given [action] then returns an HTTP OK [ResponseEntity] form the given [body]. */ fun ok(action: () -> Unit): ResponseEntity { @@ -23,19 +23,19 @@ fun ok(action: () -> Unit): ResponseEntity { /** Creates a HTTP CREATED [ResponseEntity] from the given [body] with the location set to [controllerPath]/id. */ fun created(controllerPath: String, body: T): ResponseEntity = - ResponseEntity.created(URI.create("$controllerPath/${body.id}")).body(body) + ResponseEntity.created(URI.create("$controllerPath/${body.id}")).body(body) /** Creates a HTTP CREATED [ResponseEntity] with the result of the given [producer] as its body. */ fun created(controllerPath: String, producer: () -> T): ResponseEntity = - created(controllerPath, producer()) + created(controllerPath, producer()) /** Creates a HTTP NOT FOUND [ResponseEntity]. */ fun notFound(): ResponseEntity = - ResponseEntity.notFound().build() + ResponseEntity.notFound().build() /** Creates a HTTP NO CONTENT [ResponseEntity]. */ fun noContent(): ResponseEntity = - ResponseEntity.noContent().build() + ResponseEntity.noContent().build() /** Executes the given [action] then returns an HTTP NO CONTENT [ResponseEntity]. */ fun noContent(action: () -> Unit): ResponseEntity { @@ -45,12 +45,12 @@ fun noContent(action: () -> Unit): ResponseEntity { /** Creates a HTTP FORBIDDEN [ResponseEntity]. */ fun forbidden(): ResponseEntity = - ResponseEntity.status(HttpStatus.FORBIDDEN).build() + ResponseEntity.status(HttpStatus.FORBIDDEN).build() /** Creates an [HttpHeaders] instance from the given options. */ fun httpHeaders( - contentType: MediaType = MediaType.APPLICATION_JSON, - op: HttpHeaders.() -> Unit = {} + contentType: MediaType = MediaType.APPLICATION_JSON, + op: HttpHeaders.() -> Unit = {} ) = HttpHeaders().apply { this.contentType = contentType diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountService.kt index 7462285..183ccd9 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountService.kt @@ -56,7 +56,7 @@ interface EmployeeService : ExternalModelService { + ExternalNamedModelService { /** Gets all the employees of the group with the given [id]. */ fun getEmployeesForGroup(id: Long): Collection @@ -74,49 +74,50 @@ interface EmployeeUserDetailsService : UserDetailsService { @Service class EmployeeServiceImpl( - employeeRepository: EmployeeRepository, - @Lazy val groupService: EmployeeGroupService, - @Lazy val passwordEncoder: PasswordEncoder, + employeeRepository: EmployeeRepository, + @Lazy val groupService: EmployeeGroupService, + @Lazy val passwordEncoder: PasswordEncoder, ) : AbstractExternalModelService(employeeRepository), - EmployeeService { + EmployeeService { override fun idNotFoundException(id: Long) = employeeIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = employeeIdAlreadyExistsException(id) override fun existsByFirstNameAndLastName(firstName: String, lastName: String): Boolean = - repository.existsByFirstNameAndLastName(firstName, lastName) + repository.existsByFirstNameAndLastName(firstName, lastName) override fun getAll(): Collection = - super.getAll().filter { !it.isSystemUser && !it.isDefaultGroupUser } + super.getAll().filter { !it.isSystemUser && !it.isDefaultGroupUser } override fun getById(id: Long): Employee = - getById(id, ignoreDefaultGroupUsers = true, ignoreSystemUsers = true) + getById(id, ignoreDefaultGroupUsers = true, ignoreSystemUsers = true) override fun getById(id: Long, ignoreDefaultGroupUsers: Boolean, ignoreSystemUsers: Boolean): Employee = - super.getById(id).apply { - if (ignoreSystemUsers && isSystemUser || ignoreDefaultGroupUsers && isDefaultGroupUser) - throw idNotFoundException(id) - } + super.getById(id).apply { + if (ignoreSystemUsers && isSystemUser || ignoreDefaultGroupUsers && isDefaultGroupUser) + throw idNotFoundException(id) + } override fun getByGroup(group: EmployeeGroup): Collection = - repository.findAllByGroup(group).filter { - !it.isSystemUser && !it.isDefaultGroupUser - } + repository.findAllByGroup(group).filter { + !it.isSystemUser && !it.isDefaultGroupUser + } override fun getDefaultGroupEmployee(group: EmployeeGroup): Employee = - repository.findByIsDefaultGroupUserIsTrueAndGroupIs(group) + repository.findByIsDefaultGroupUserIsTrueAndGroupIs(group) override fun save(entity: EmployeeSaveDto): Employee = - save(with(entity) { - Employee( - id, - firstName, - lastName, - passwordEncoder.encode(password), - isDefaultGroupUser = false, - isSystemUser = false, - group = if (groupId != null) groupService.getById(groupId) else null, - permissions = permissions - ) - }) + save(with(entity) { + Employee( + id, + firstName, + lastName, + passwordEncoder.encode(password), + isDefaultGroupUser = false, + isSystemUser = false, + group = if (groupId != null) groupService.getById(groupId) else null, + permissions = permissions + ) + }) override fun save(entity: Employee): Employee { if (existsById(entity.id)) @@ -128,14 +129,14 @@ class EmployeeServiceImpl( override fun saveDefaultGroupEmployee(group: EmployeeGroup) { save( - Employee( - id = 1000000L + group.id!!, - firstName = group.name, - lastName = "EmployeeModel", - password = passwordEncoder.encode(group.name), - group = group, - isDefaultGroupUser = true - ) + Employee( + id = 1000000L + group.id!!, + firstName = group.name, + lastName = "EmployeeModel", + password = passwordEncoder.encode(group.name), + group = group, + isDefaultGroupUser = true + ) ) } @@ -143,9 +144,9 @@ class EmployeeServiceImpl( val employee = getById(employeeId, ignoreDefaultGroupUsers = true, ignoreSystemUsers = false) employee.lastLoginTime = time return update( - employee, - ignoreDefaultGroupUsers = true, - ignoreSystemUsers = false + employee, + ignoreDefaultGroupUsers = true, + ignoreSystemUsers = false ) } @@ -153,21 +154,21 @@ class EmployeeServiceImpl( val persistedEmployee by lazy { getById(entity.id) } return update(with(entity) { Employee( - id = id, - firstName = firstName or persistedEmployee.firstName, - lastName = lastName or persistedEmployee.lastName, - password = persistedEmployee.password, - isDefaultGroupUser = false, - isSystemUser = false, - group = if (entity.groupId != null) groupService.getById(entity.groupId) else persistedEmployee.group, - permissions = permissions?.toMutableSet() ?: persistedEmployee.permissions, - lastLoginTime = persistedEmployee.lastLoginTime + id = id, + firstName = firstName or persistedEmployee.firstName, + lastName = lastName or persistedEmployee.lastName, + password = persistedEmployee.password, + isDefaultGroupUser = false, + isSystemUser = false, + group = if (entity.groupId != null) groupService.getById(entity.groupId) else persistedEmployee.group, + permissions = permissions?.toMutableSet() ?: persistedEmployee.permissions, + lastLoginTime = persistedEmployee.lastLoginTime ) }) } override fun update(entity: Employee): Employee = - update(entity, ignoreDefaultGroupUsers = true, ignoreSystemUsers = true) + update(entity, ignoreDefaultGroupUsers = true, ignoreSystemUsers = true) override fun update(entity: Employee, ignoreDefaultGroupUsers: Boolean, ignoreSystemUsers: Boolean): Employee { with(repository.findByFirstNameAndLastName(entity.firstName, entity.lastName)) { @@ -182,24 +183,24 @@ class EmployeeServiceImpl( val persistedEmployee = getById(id, ignoreDefaultGroupUsers = true, ignoreSystemUsers = true) return super.update(with(persistedEmployee) { Employee( - id, - firstName, - lastName, - passwordEncoder.encode(password), - isDefaultGroupUser, - isSystemUser, - group, - permissions, - lastLoginTime + id, + firstName, + lastName, + passwordEncoder.encode(password), + isDefaultGroupUser, + isSystemUser, + group, + permissions, + lastLoginTime ) }) } override fun addPermission(employeeId: Long, permission: EmployeePermission): Employee = - super.update(getById(employeeId).apply { permissions += permission }) + super.update(getById(employeeId).apply { permissions += permission }) override fun removePermission(employeeId: Long, permission: EmployeePermission): Employee = - super.update(getById(employeeId).apply { permissions -= permission }) + super.update(getById(employeeId).apply { permissions -= permission }) override fun logout(request: HttpServletRequest) { val authorizationCookie = WebUtils.getCookie(request, "Authorization") @@ -216,19 +217,20 @@ const val defaultGroupCookieMaxAge = 10 * 365 * 24 * 60 * 60 // 10 ans @Service class EmployeeGroupServiceImpl( - val employeeService: EmployeeService, - employeeGroupRepository: EmployeeGroupRepository + private val employeeService: EmployeeService, + employeeGroupRepository: EmployeeGroupRepository ) : AbstractExternalNamedModelService( - employeeGroupRepository + employeeGroupRepository ), - EmployeeGroupService { + EmployeeGroupService { override fun idNotFoundException(id: Long) = employeeGroupIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = employeeGroupIdAlreadyExistsException(id) override fun nameNotFoundException(name: String) = employeeGroupNameNotFoundException(name) override fun nameAlreadyExistsException(name: String) = employeeGroupNameAlreadyExistsException(name) override fun existsByName(name: String): Boolean = repository.existsByName(name) override fun getEmployeesForGroup(id: Long): Collection = - employeeService.getByGroup(getById(id)) + employeeService.getByGroup(getById(id)) @Transactional override fun save(entity: EmployeeGroup): EmployeeGroup { @@ -241,9 +243,9 @@ class EmployeeGroupServiceImpl( val persistedGroup by lazy { getById(entity.id) } return update(with(entity) { EmployeeGroup( - entity.id, - if (name.isNotBlank()) entity.name else persistedGroup.name, - if (permissions.isNotEmpty()) entity.permissions else persistedGroup.permissions + entity.id, + if (name.isNotBlank()) entity.name else persistedGroup.name, + if (permissions.isNotEmpty()) entity.permissions else persistedGroup.permissions ) }) } @@ -256,11 +258,11 @@ class EmployeeGroupServiceImpl( override fun getRequestDefaultGroup(request: HttpServletRequest): EmployeeGroup { val defaultGroupCookie = WebUtils.getCookie(request, defaultGroupCookieName) - ?: throw NoDefaultGroupException() + ?: throw NoDefaultGroupException() val defaultGroupUser = employeeService.getById( - defaultGroupCookie.value.toLong(), - ignoreDefaultGroupUsers = false, - ignoreSystemUsers = true + defaultGroupCookie.value.toLong(), + ignoreDefaultGroupUsers = false, + ignoreSystemUsers = true ) return defaultGroupUser.group!! } @@ -269,17 +271,17 @@ class EmployeeGroupServiceImpl( val group = getById(groupId) val defaultGroupUser = employeeService.getDefaultGroupEmployee(group) response.addHeader( - "Set-Cookie", - "$defaultGroupCookieName=${defaultGroupUser.id}; Max-Age=${defaultGroupCookieMaxAge}; Path=/api; HttpOnly; Secure; SameSite=strict" + "Set-Cookie", + "$defaultGroupCookieName=${defaultGroupUser.id}; Max-Age=${defaultGroupCookieMaxAge}; Path=/api; HttpOnly; Secure; SameSite=strict" ) } } @Service class EmployeeUserDetailsServiceImpl( - val employeeService: EmployeeService + private val employeeService: EmployeeService ) : - EmployeeUserDetailsService { + EmployeeUserDetailsService { override fun loadUserByUsername(username: String): UserDetails { try { return loadUserByEmployeeId(username.toLong(), true) @@ -292,9 +294,9 @@ class EmployeeUserDetailsServiceImpl( override fun loadUserByEmployeeId(employeeId: Long, ignoreDefaultGroupUsers: Boolean): UserDetails { val employee = employeeService.getById( - employeeId, - ignoreDefaultGroupUsers = ignoreDefaultGroupUsers, - ignoreSystemUsers = false + employeeId, + ignoreDefaultGroupUsers = ignoreDefaultGroupUsers, + ignoreSystemUsers = false ) return User(employee.id.toString(), employee.password, employee.authorities) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyService.kt index 65f037f..5e2d495 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyService.kt @@ -12,12 +12,13 @@ interface CompanyService : ExternalNamedModelService(companyRepository), - CompanyService { + AbstractExternalNamedModelService(companyRepository), + CompanyService { override fun idNotFoundException(id: Long) = companyIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = companyIdAlreadyExistsException(id) override fun nameNotFoundException(name: String) = companyNameNotFoundException(name) override fun nameAlreadyExistsException(name: String) = companyNameAlreadyExistsException(name) @@ -29,8 +30,8 @@ class CompanyServiceImpl( return update(with(entity) { company( - id = id, - name = if (name != null && name.isNotBlank()) name else persistedCompany.name + id = id, + name = if (name != null && name.isNotBlank()) name else persistedCompany.name ) }) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryService.kt index 0dc05b3..965425a 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryService.kt @@ -26,20 +26,20 @@ interface InventoryService { @Service class InventoryServiceImpl( - private val materialService: MaterialService, - private val mixService: MixService + private val materialService: MaterialService, + private val mixService: MixService ) : InventoryService { @Transactional override fun add(materialQuantities: Collection) = - materialQuantities.map { - materialQuantityDto(materialId = it.material, quantity = add(it)) - } + materialQuantities.map { + materialQuantityDto(materialId = it.material, quantity = add(it)) + } override fun add(materialQuantity: MaterialQuantityDto) = - materialService.updateQuantity( - materialService.getById(materialQuantity.material), - materialQuantity.quantity - ) + materialService.updateQuantity( + materialService.getById(materialQuantity.material), + materialQuantity.quantity + ) @Transactional override fun deductMix(mixRatio: MixDeductDto): Collection { @@ -48,15 +48,15 @@ class InventoryServiceImpl( val adjustedFirstMaterialQuantity = firstMixMaterial.quantity * mixRatio.ratio fun adjustQuantity(mixMaterial: MixMaterial): Float = - if (!mixMaterial.material.materialType!!.usePercentages) - mixMaterial.quantity * mixRatio.ratio - else - (mixMaterial.quantity * adjustedFirstMaterialQuantity) / 100f + if (!mixMaterial.material.materialType!!.usePercentages) + mixMaterial.quantity * mixRatio.ratio + else + (mixMaterial.quantity * adjustedFirstMaterialQuantity) / 100f return deduct(mix.mixMaterials.map { materialQuantityDto( - materialId = it.material.id!!, - quantity = adjustQuantity(it) + materialId = it.material.id!!, + quantity = adjustQuantity(it) ) }) } @@ -65,11 +65,11 @@ class InventoryServiceImpl( override fun deduct(materialQuantities: Collection): Collection { val thrown = mutableListOf() val updatedQuantities = - materialQuantities.mapMayThrow( - { thrown.add(it) } - ) { - materialQuantityDto(materialId = it.material, quantity = deduct(it)) - } + materialQuantities.mapMayThrow( + { thrown.add(it) } + ) { + materialQuantityDto(materialId = it.material, quantity = deduct(it)) + } if (thrown.isNotEmpty()) { throw MultiplesNotEnoughInventoryException(thrown) @@ -78,35 +78,35 @@ class InventoryServiceImpl( } override fun deduct(materialQuantity: MaterialQuantityDto): Float = - with(materialService.getById(materialQuantity.material)) { - if (this.inventoryQuantity >= materialQuantity.quantity) { - materialService.updateQuantity(this, -materialQuantity.quantity) - } else { - throw NotEnoughInventoryException(materialQuantity.quantity, this) - } - } + with(materialService.getById(materialQuantity.material)) { + if (this.inventoryQuantity >= materialQuantity.quantity) { + materialService.updateQuantity(this, -materialQuantity.quantity) + } else { + throw NotEnoughInventoryException(materialQuantity.quantity, this) + } + } } class NotEnoughInventoryException(quantity: Float, material: Material) : - RestException( - "notenoughinventory", - "Not enough inventory", - HttpStatus.BAD_REQUEST, - "Cannot deduct ${quantity}mL of ${material.name} because there is only ${material.inventoryQuantity}mL in inventory", - mapOf( - "material" to material.name, - "requestQuantity" to quantity, - "availableQuantity" to material.inventoryQuantity - ) + RestException( + "notenoughinventory", + "Not enough inventory", + HttpStatus.BAD_REQUEST, + "Cannot deduct ${quantity}mL of ${material.name} because there is only ${material.inventoryQuantity}mL in inventory", + mapOf( + "material" to material.name, + "requestQuantity" to quantity, + "availableQuantity" to material.inventoryQuantity ) + ) class MultiplesNotEnoughInventoryException(exceptions: List) : - RestException( - "notenoughinventory-multiple", - "Not enough inventory", - HttpStatus.BAD_REQUEST, - "Cannot deduct requested quantities because there is no enough of them in inventory", - mapOf( - "lowQuantities" to exceptions.map { it.extensions } - ) + RestException( + "notenoughinventory-multiple", + "Not enough inventory", + HttpStatus.BAD_REQUEST, + "Cannot deduct requested quantities because there is no enough of them in inventory", + mapOf( + "lowQuantities" to exceptions.map { it.extensions } ) + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialService.kt index 384e04c..0b9831b 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialService.kt @@ -1,5 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.repository.MaterialRepository import dev.fyloz.colorrecipesexplorer.service.files.SimdutService @@ -8,7 +9,7 @@ import org.springframework.context.annotation.Lazy import org.springframework.stereotype.Service interface MaterialService : - ExternalNamedModelService { + ExternalNamedModelService { /** Checks if a material with the given [materialType] exists. */ fun existsByMaterialType(materialType: MaterialType): Boolean @@ -36,43 +37,44 @@ interface MaterialService : @Service class MaterialServiceImpl( - materialRepository: MaterialRepository, - val simdutService: SimdutService, - val recipeService: RecipeService, - val mixService: MixService, - @Lazy val materialTypeService: MaterialTypeService + materialRepository: MaterialRepository, + val simdutService: SimdutService, + val recipeService: RecipeService, + val mixService: MixService, + @Lazy val materialTypeService: MaterialTypeService ) : - AbstractExternalNamedModelService( - materialRepository - ), - MaterialService { + AbstractExternalNamedModelService( + materialRepository + ), + MaterialService { override fun idNotFoundException(id: Long) = materialIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = materialIdAlreadyExistsException(id) override fun nameNotFoundException(name: String) = materialNameNotFoundException(name) override fun nameAlreadyExistsException(name: String) = materialNameAlreadyExistsException(name) override fun existsByMaterialType(materialType: MaterialType): Boolean = - repository.existsByMaterialType(materialType) + repository.existsByMaterialType(materialType) override fun hasSimdut(id: Long): Boolean = simdutService.exists(getById(id)) override fun getSimdut(id: Long): ByteArray = simdutService.read(getById(id)) override fun getAllNotMixType(): Collection = getAll().filter { !it.isMixType } override fun getAllIdsWithSimdut(): Collection = - getAllNotMixType() - .filter { simdutService.exists(it) } - .map { it.id!! } + getAllNotMixType() + .filter { simdutService.exists(it) } + .map { it.id!! } override fun save(entity: MaterialSaveDto): Material = - save(with(entity) { - material( - name = entity.name, - inventoryQuantity = entity.inventoryQuantity, - materialType = materialTypeService.getById(materialTypeId), - isMixType = false - ) - }).apply { - if (entity.simdutFile != null && !entity.simdutFile.isEmpty) simdutService.write(this, entity.simdutFile) - } + save(with(entity) { + material( + name = entity.name, + inventoryQuantity = entity.inventoryQuantity, + materialType = materialTypeService.getById(materialTypeId), + isMixType = false + ) + }).apply { + if (entity.simdutFile != null && !entity.simdutFile.isEmpty) simdutService.write(this, entity.simdutFile) + } override fun update(entity: MaterialUpdateDto): Material { val persistedMaterial by lazy { @@ -81,11 +83,11 @@ class MaterialServiceImpl( return update(with(entity) { material( - id = id, - name = if (name != null && name.isNotBlank()) name else persistedMaterial.name, - inventoryQuantity = if (inventoryQuantity != null && inventoryQuantity != Float.MIN_VALUE) inventoryQuantity else persistedMaterial.inventoryQuantity, - isMixType = persistedMaterial.isMixType, - materialType = if (materialTypeId != null) materialTypeService.getById(materialTypeId) else persistedMaterial.materialType + id = id, + name = if (name != null && name.isNotBlank()) name else persistedMaterial.name, + inventoryQuantity = if (inventoryQuantity != null && inventoryQuantity != Float.MIN_VALUE) inventoryQuantity else persistedMaterial.inventoryQuantity, + isMixType = persistedMaterial.isMixType, + materialType = if (materialTypeId != null) materialTypeService.getById(materialTypeId) else persistedMaterial.materialType ) }).apply { if (entity.simdutFile != null && !entity.simdutFile.isEmpty) simdutService.update(entity.simdutFile, this) @@ -101,15 +103,15 @@ class MaterialServiceImpl( override fun getAllForMixCreation(recipeId: Long): Collection { val recipesMixTypes = recipeService.getById(recipeId).mixTypes return getAll() - .filter { !it.isMixType || recipesMixTypes.any { mixType -> mixType.material.id == it.id } } + .filter { !it.isMixType || recipesMixTypes.any { mixType -> mixType.material.id == it.id } } } override fun getAllForMixUpdate(mixId: Long): Collection { val mix = mixService.getById(mixId) val recipesMixTypes = mix.recipe.mixTypes return getAll() - .filter { !it.isMixType || recipesMixTypes.any { mixType -> mixType.material.id == it.id } } - .filter { it.id != mix.mixType.material.id } + .filter { !it.isMixType || recipesMixTypes.any { mixType -> mixType.material.id == it.id } } + .filter { it.id != mix.mixType.material.id } } private fun assertPersistedMaterial(material: Material) { diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeService.kt index 192c9e1..3a9f108 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeService.kt @@ -1,13 +1,14 @@ package dev.fyloz.colorrecipesexplorer.service import dev.fyloz.colorrecipesexplorer.config.properties.MaterialTypeProperties +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.model.validation.isNotNullAndNotBlank import dev.fyloz.colorrecipesexplorer.repository.MaterialTypeRepository import org.springframework.stereotype.Service interface MaterialTypeService : - ExternalNamedModelService { + ExternalNamedModelService { /** Checks if a material type with the given [prefix] exists. */ fun existsByPrefix(prefix: String): Boolean @@ -26,16 +27,17 @@ interface MaterialTypeService : @Service class MaterialTypeServiceImpl(repository: MaterialTypeRepository, private val materialService: MaterialService) : - AbstractExternalNamedModelService( - repository - ), MaterialTypeService { + AbstractExternalNamedModelService( + repository + ), MaterialTypeService { override fun idNotFoundException(id: Long) = materialTypeIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = materialIdAlreadyExistsException(id) override fun nameNotFoundException(name: String) = materialTypeNameNotFoundException(name) override fun nameAlreadyExistsException(name: String) = materialTypeNameAlreadyExistsException(name) override fun existsByPrefix(prefix: String): Boolean = repository.existsByPrefix(prefix) override fun isUsedByMaterial(materialType: MaterialType): Boolean = - materialService.existsByMaterialType(materialType) + materialService.existsByMaterialType(materialType) override fun getAllSystemTypes(): Collection = repository.findAllBySystemTypeIs(true) override fun getAllNonSystemType(): Collection = repository.findAllBySystemTypeIs(false) @@ -51,10 +53,10 @@ class MaterialTypeServiceImpl(repository: MaterialTypeRepository, private val ma return update(with(entity) { MaterialType( - id = id, - name = if (isNotNullAndNotBlank(name)) name else persistedMaterialType.name, - prefix = if (isNotNullAndNotBlank(prefix)) prefix else persistedMaterialType.prefix, - systemType = false + id = id, + name = if (isNotNullAndNotBlank(name)) name else persistedMaterialType.name, + prefix = if (isNotNullAndNotBlank(prefix)) prefix else persistedMaterialType.prefix, + systemType = false ) }) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialService.kt index 2431802..3bcab80 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialService.kt @@ -21,24 +21,25 @@ interface MixMaterialService : ModelService @Service class MixMaterialServiceImpl( - mixMaterialRepository: MixMaterialRepository, - @Lazy val materialService: MaterialService + mixMaterialRepository: MixMaterialRepository, + @Lazy val materialService: MaterialService ) : AbstractModelService(mixMaterialRepository), MixMaterialService { override fun idNotFoundException(id: Long) = mixMaterialIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = mixMaterialIdAlreadyExistsException(id) override fun existsByMaterial(material: Material): Boolean = repository.existsByMaterial(material) override fun create(mixMaterials: Set): Set = - mixMaterials.map(::create).toSet() + mixMaterials.map(::create).toSet() override fun create(mixMaterial: MixMaterialDto): MixMaterial = - mixMaterial( - material = materialService.getById(mixMaterial.materialId), - quantity = mixMaterial.quantity, - position = mixMaterial.position - ) + mixMaterial( + material = materialService.getById(mixMaterial.materialId), + quantity = mixMaterial.quantity, + position = mixMaterial.position + ) override fun updateQuantity(mixMaterial: MixMaterial, quantity: Float) = - update(mixMaterial.apply { - this.quantity = quantity - }) + update(mixMaterial.apply { + this.quantity = quantity + }) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixService.kt index b1cafd6..65edbe3 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixService.kt @@ -1,5 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.repository.MixRepository import org.springframework.context.annotation.Lazy @@ -22,14 +23,15 @@ interface MixService : ExternalModelService(mixRepository), - MixService { + MixService { override fun idNotFoundException(id: Long) = mixIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = mixIdAlreadyExistsException(id) override fun getAllByMixType(mixType: MixType): Collection = repository.findAllByMixType(mixType) override fun mixTypeIsShared(mixType: MixType): Boolean = getAllByMixType(mixType).count() > 1 diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixTypeService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixTypeService.kt index 5b6e682..3cc83ab 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixTypeService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/MixTypeService.kt @@ -27,30 +27,31 @@ interface MixTypeService : NamedModelService { @Service class MixTypeServiceImpl( - mixTypeRepository: MixTypeRepository, - @Lazy val materialService: MaterialService, - @Lazy val mixService: MixService + mixTypeRepository: MixTypeRepository, + @Lazy val materialService: MaterialService, + @Lazy val mixService: MixService ) : - AbstractNamedModelService(mixTypeRepository), MixTypeService { + AbstractNamedModelService(mixTypeRepository), MixTypeService { override fun idNotFoundException(id: Long) = mixTypeIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = mixTypeIdAlreadyExistsException(id) override fun nameNotFoundException(name: String) = mixTypeNameNotFoundException(name) override fun nameAlreadyExistsException(name: String) = mixTypeNameAlreadyExistsException(name) override fun existsByNameAndMaterialType(name: String, materialType: MaterialType): Boolean = - repository.existsByNameAndMaterialType(name, materialType) + repository.existsByNameAndMaterialType(name, materialType) override fun getByMaterial(material: Material): MixType = - repository.findByMaterial(material) ?: throw nameNotFoundException(material.name) + repository.findByMaterial(material) ?: throw nameNotFoundException(material.name) override fun getByNameAndMaterialType(name: String, materialType: MaterialType): MixType = - repository.findByNameAndMaterialType(name, materialType) - ?: throw MixTypeNameAndMaterialTypeNotFoundException(name, materialType) + repository.findByNameAndMaterialType(name, materialType) + ?: throw MixTypeNameAndMaterialTypeNotFoundException(name, materialType) override fun getOrCreateForNameAndMaterialType(name: String, materialType: MaterialType): MixType = - if (existsByNameAndMaterialType(name, materialType)) - getByNameAndMaterialType(name, materialType) - else - saveForNameAndMaterialType(name, materialType) + if (existsByNameAndMaterialType(name, materialType)) + getByNameAndMaterialType(name, materialType) + else + saveForNameAndMaterialType(name, materialType) override fun save(entity: MixType): MixType { if (materialService.existsByName(entity.name)) @@ -59,24 +60,24 @@ class MixTypeServiceImpl( } override fun saveForNameAndMaterialType(name: String, materialType: MaterialType): MixType = - save( - mixType( - name = name, - material = material( - name = name, - inventoryQuantity = Float.MIN_VALUE, - isMixType = true, - materialType = materialType - ) - ) + save( + mixType( + name = name, + material = material( + name = name, + inventoryQuantity = Float.MIN_VALUE, + isMixType = true, + materialType = materialType + ) ) + ) override fun updateForNameAndMaterialType(mixType: MixType, name: String, materialType: MaterialType): MixType = - update(mixType.apply { - this.name = name - material.name = name - material.materialType = materialType - }) + update(mixType.apply { + this.name = name + material.name = name + material.materialType = materialType + }) override fun delete(entity: MixType) { if (!repository.canBeDeleted(entity.id!!)) throw cannotDeleteMixTypeException(entity) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt index b8db07c..39585f2 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeService.kt @@ -1,5 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.model.validation.or import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository @@ -30,14 +31,15 @@ interface RecipeService : ExternalModelService(recipeRepository), - RecipeService { + AbstractExternalModelService(recipeRepository), + RecipeService { override fun idNotFoundException(id: Long) = recipeIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = recipeIdAlreadyExistsException(id) override fun existsByCompany(company: Company): Boolean = repository.existsByCompany(company) override fun getAllByCompany(company: Company): Collection = repository.findAllByCompany(company) @@ -46,14 +48,14 @@ class RecipeServiceImpl( // TODO checks if name is unique in the scope of the [company] return save(with(entity) { recipe( - name = name, - description = description, - color = color, - gloss = gloss, - sample = sample, - approbationDate = approbationDate, - remark = remark ?: "", - company = companyService.getById(companyId) + name = name, + description = description, + color = color, + gloss = gloss, + sample = sample, + approbationDate = approbationDate, + remark = remark ?: "", + company = companyService.getById(companyId) ) }) } @@ -64,17 +66,17 @@ class RecipeServiceImpl( return update(with(entity) { recipe( - id = id, - name = name or persistedRecipe.name, - description = description or persistedRecipe.description, - color = color or persistedRecipe.color, - gloss = gloss ?: persistedRecipe.gloss, - sample = sample ?: persistedRecipe.sample, - approbationDate = approbationDate ?: persistedRecipe.approbationDate, - remark = remark or persistedRecipe.remark, - company = persistedRecipe.company, - mixes = persistedRecipe.mixes, - groupsInformation = updateGroupsInformationSteps(persistedRecipe, entity.steps) + id = id, + name = name or persistedRecipe.name, + description = description or persistedRecipe.description, + color = color or persistedRecipe.color, + gloss = gloss ?: persistedRecipe.gloss, + sample = sample ?: persistedRecipe.sample, + approbationDate = approbationDate ?: persistedRecipe.approbationDate, + remark = remark or persistedRecipe.remark, + company = persistedRecipe.company, + mixes = persistedRecipe.mixes, + groupsInformation = updateGroupsInformationSteps(persistedRecipe, entity.steps) ) }) } @@ -86,17 +88,17 @@ class RecipeServiceImpl( steps.forEach { with(recipe.groupInformationForGroup(it.groupId)) { updatedGroupsInformation.add( - this?.apply { - if (this.steps != null) { - this.steps!!.clear() - this.steps!!.addAll(it.steps) - } else { - this.steps = it.steps.toMutableSet() - } - } ?: recipeGroupInformation( - group = groupService.getById(it.groupId), - steps = it.steps.toMutableSet() - ) + this?.apply { + if (this.steps != null) { + this.steps!!.clear() + this.steps!!.addAll(it.steps) + } else { + this.steps = it.steps.toMutableSet() + } + } ?: recipeGroupInformation( + group = groupService.getById(it.groupId), + steps = it.steps.toMutableSet() + ) ) } } @@ -109,7 +111,7 @@ class RecipeServiceImpl( val recipe = getById(publicDataDto.recipeId) fun noteForGroup(group: EmployeeGroup) = - publicDataDto.notes.firstOrNull { it.groupId == group.id }?.content + publicDataDto.notes.firstOrNull { it.groupId == group.id }?.content // Notes recipe.groupsInformation.map { @@ -128,10 +130,10 @@ class RecipeServiceImpl( } override fun addMix(recipe: Recipe, mix: Mix) = - update(recipe.apply { mixes.add(mix) }) + update(recipe.apply { mixes.add(mix) }) override fun removeMix(mix: Mix): Recipe = - update(mix.recipe.apply { mixes.remove(mix) }) + update(mix.recipe.apply { mixes.remove(mix) }) } const val RECIPE_IMAGES_DIRECTORY = "images/recipe" @@ -152,11 +154,11 @@ interface RecipeImageService { @Service class RecipeImageServiceImpl(val recipeService: RecipeService, val fileService: FileService) : RecipeImageService { override fun getByIdForRecipe(id: Long, recipeId: Long): ByteArray = - try { - fileService.readAsBytes(getPath(id, recipeId)) - } catch (ex: NoSuchFileException) { - throw RecipeImageNotFoundException(id, recipeService.getById(recipeId)) - } + try { + fileService.readAsBytes(getPath(id, recipeId)) + } catch (ex: NoSuchFileException) { + throw RecipeImageNotFoundException(id, recipeService.getById(recipeId)) + } override fun getAllIdsForRecipe(recipeId: Long): Collection { val recipe = recipeService.getById(recipeId) @@ -165,19 +167,19 @@ class RecipeImageServiceImpl(val recipeService: RecipeService, val fileService: return listOf() } return recipeDirectory.listFiles()!! // Should never be null because we check if recipeDirectory is a directory and exists before - .filterNotNull() - .map { it.name.toLong() } + .filterNotNull() + .map { it.name.toLong() } } override fun save(image: MultipartFile, recipeId: Long): Long { /** Gets the next id available for a new image for the recipe with the given [recipeId]. */ fun getNextAvailableId(): Long = - with(getAllIdsForRecipe(recipeId)) { - if (isEmpty()) - 0 - else - maxOrNull()!! + 1L // maxOrNull() cannot return null because existingIds cannot be empty at this point - } + with(getAllIdsForRecipe(recipeId)) { + if (isEmpty()) + 0 + else + maxOrNull()!! + 1L // maxOrNull() cannot return null because existingIds cannot be empty at this point + } val nextAvailableId = getNextAvailableId() fileService.write(image, getPath(nextAvailableId, recipeId)) @@ -185,7 +187,7 @@ class RecipeImageServiceImpl(val recipeService: RecipeService, val fileService: } override fun delete(id: Long, recipeId: Long) = - fileService.delete(getPath(id, recipeId)) + fileService.delete(getPath(id, recipeId)) /** Gets the images directory of the recipe with the given [recipeId]. */ fun getRecipeDirectory(recipeId: Long) = File(fileService.getPath("$RECIPE_IMAGES_DIRECTORY/$recipeId")) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepService.kt index 42d941a..d4d6adb 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepService.kt @@ -1,6 +1,7 @@ package dev.fyloz.colorrecipesexplorer.service import dev.fyloz.colorrecipesexplorer.model.RecipeStep +import dev.fyloz.colorrecipesexplorer.model.recipeStepIdAlreadyExistsException import dev.fyloz.colorrecipesexplorer.model.recipeStepIdNotFoundException import dev.fyloz.colorrecipesexplorer.repository.RecipeStepRepository import org.springframework.stereotype.Service @@ -9,7 +10,8 @@ interface RecipeStepService : ModelService @Service class RecipeStepServiceImpl(recipeStepRepository: RecipeStepRepository) : - AbstractModelService(recipeStepRepository), - RecipeStepService { + AbstractModelService(recipeStepRepository), + RecipeStepService { override fun idNotFoundException(id: Long) = recipeStepIdNotFoundException(id) + override fun idAlreadyExistsException(id: Long) = recipeStepIdAlreadyExistsException(id) } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/Service.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/Service.kt index 0414c96..918247c 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/Service.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/Service.kt @@ -65,15 +65,16 @@ abstract class AbstractService>(override val reposito } abstract class AbstractModelService>(repository: R) : - AbstractService(repository), ModelService { + AbstractService(repository), ModelService { protected abstract fun idNotFoundException(id: Long): NotFoundException + protected abstract fun idAlreadyExistsException(id: Long): AlreadyExistsException override fun existsById(id: Long): Boolean = repository.existsById(id) override fun getById(id: Long): E = repository.findByIdOrNull(id) ?: throw idNotFoundException(id) override fun save(entity: E): E { if (entity.id != null && existsById(entity.id!!)) - throw idNotFoundException(entity.id!!) + throw idAlreadyExistsException(entity.id!!) return super.save(entity) } @@ -85,7 +86,7 @@ abstract class AbstractModelService>(repos } override fun deleteById(id: Long) = - delete(getById(id)) // Use delete(entity) to prevent code duplication and to ease testing + delete(getById(id)) // Use delete(entity) to prevent code duplication and to ease testing protected fun assertId(id: Long?) { Assert.notNull(id, "${javaClass.simpleName}.update() was called with a null identifier") @@ -93,7 +94,7 @@ abstract class AbstractModelService>(repos } abstract class AbstractNamedModelService>(repository: R) : - AbstractModelService(repository), NamedModelService { + AbstractModelService(repository), NamedModelService { protected abstract fun nameNotFoundException(name: String): NotFoundException protected abstract fun nameAlreadyExistsException(name: String): AlreadyExistsException @@ -139,23 +140,23 @@ interface ExternalService, U : EntityDto, R : JpaReposito /** An [ExternalService] for entities implementing the [Model] interface. */ interface ExternalModelService, U : EntityDto, R : JpaRepository> : - ModelService, ExternalService + ModelService, ExternalService /** An [ExternalService] for entities implementing the [NamedModel] interface. */ interface ExternalNamedModelService, U : EntityDto, R : JpaRepository> : - NamedModelService, ExternalModelService + NamedModelService, ExternalModelService /** An [AbstractService] with the functionalities of a [ExternalService]. */ @Suppress("unused") abstract class AbstractExternalService, U : EntityDto, R : JpaRepository>(repository: R) : - AbstractService(repository), ExternalService + AbstractService(repository), ExternalService /** An [AbstractModelService] with the functionalities of a [ExternalService]. */ abstract class AbstractExternalModelService, U : EntityDto, R : JpaRepository>( - repository: R + repository: R ) : AbstractModelService(repository), ExternalModelService /** An [AbstractNamedModelService] with the functionalities of a [ExternalService]. */ abstract class AbstractExternalNamedModelService, U : EntityDto, R : NamedJpaRepository>( - repository: R + repository: R ) : AbstractNamedModelService(repository), ExternalNamedModelService diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt index f2d3c38..c6c11fd 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/FileService.kt @@ -10,13 +10,12 @@ import java.io.IOException import java.io.InputStream import java.nio.charset.StandardCharsets import java.nio.file.Files -import java.nio.file.Paths @Service class FileService( - private val resourcesLoader: ResourceLoader, - private val creProperties: CreProperties, - private val logger: Logger + private val resourcesLoader: ResourceLoader, + private val creProperties: CreProperties, + private val logger: Logger ) { /** Reads the resource at the given [path] as a [String]. */ fun readResource(path: String): String = try { @@ -35,18 +34,18 @@ class FileService( /** Reads the file at the given [path] as a [ByteArray]. */ fun readAsBytes(path: String) = - withFileAt(path) { this.readBytes() } + withFileAt(path) { this.readBytes() } /** Writes the given [multipartFile] to the file at the given [path]. */ fun write(multipartFile: MultipartFile, path: String): Boolean = - if (multipartFile.size <= 0) true - else try { - multipartFile.transferTo(create(path).toPath()) - true - } catch (ex: IOException) { - logger.error("Unable to write multipart file", ex) - false - } + if (multipartFile.size <= 0) true + else try { + multipartFile.transferTo(create(path).toPath()) + true + } catch (ex: IOException) { + logger.error("Unable to write multipart file", ex) + false + } /** Creates a new file at the given [path]. If the file already exists, nothing will be done. */ fun create(path: String) = withFileAt(path) { @@ -77,8 +76,8 @@ class FileService( /** Runs the given [block] in the context of a file with the given [path]. */ fun withFileAt(path: String, block: File.() -> T) = - File(path).block() + File(path).block() fun getPath(fileName: String): String = - "${creProperties.workingDirectory}/$fileName" + "${creProperties.workingDirectory}/$fileName" } diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutService.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutService.kt index c483d12..e13c501 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutService.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutService.kt @@ -12,12 +12,12 @@ const val SIMDUT_DIRECTORY = "simdut" @Service class SimdutService( - private val fileService: FileService, - private val logger: Logger + private val fileService: FileService, + private val logger: Logger ) { /** Checks if the given [material] has a SIMDUT file. */ fun exists(material: Material) = - fileService.exists(getPath(material)) + fileService.exists(getPath(material)) /** Reads the SIMDUT file of the given [material]. */ fun read(material: Material): ByteArray { @@ -46,21 +46,21 @@ class SimdutService( /** Deletes the SIMDUT file of the given [material]. */ fun delete(material: Material) = - fileService.delete(getPath(material)) + fileService.delete(getPath(material)) /** Gets the path of the SIMDUT file of the given [material]. */ fun getPath(material: Material) = - fileService.getPath("$SIMDUT_DIRECTORY/${getSimdutFileName(material)}") + fileService.getPath("$SIMDUT_DIRECTORY/${getSimdutFileName(material)}") /** Gets the name of the SIMDUT file of the given [material]. */ fun getSimdutFileName(material: Material) = - material.id.toString() + material.id.toString() } class SimdutWriteException(material: Material) : - RestException( - "simdut-write", - "Could not write SIMDUT file", - HttpStatus.INTERNAL_SERVER_ERROR, - "Could not write the SIMDUT file for the material ${material.name} to the disk" - ) + RestException( + "simdut-write", + "Could not write SIMDUT file", + HttpStatus.INTERNAL_SERVER_ERROR, + "Could not write the SIMDUT file for the material ${material.name} to the disk" + ) diff --git a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/utils/Collections.kt b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/utils/Collections.kt index b28e138..1eab8ff 100644 --- a/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/utils/Collections.kt +++ b/src/main/kotlin/dev/fyloz/colorrecipesexplorer/service/utils/Collections.kt @@ -2,8 +2,8 @@ package dev.fyloz.colorrecipesexplorer.service.utils /** Returns a list containing the result of the given [transform] applied to each item of the [Iterable]. If the given [transform] throws, the [Throwable] will be passed to the given [throwableConsumer]. */ inline fun Iterable.mapMayThrow( - throwableConsumer: (E) -> Unit = {}, - transform: (T) -> R + throwableConsumer: (E) -> Unit = {}, + transform: (T) -> R ): List = this.mapNotNull { try { transform(it) diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 44a584f..492010d 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -7,7 +7,6 @@ cre.security.jwt-duration=18000000 # Root user cre.security.root.id=9999 cre.security.root.password=password - # Default material types entities.material-types.systemTypes[0].name=Aucun entities.material-types.systemTypes[0].prefix= @@ -16,11 +15,9 @@ entities.material-types.systemTypes[1].name=Base entities.material-types.systemTypes[1].prefix=BAS entities.material-types.systemTypes[1].usepercentages=false entities.material-types.baseName=Base - # Database manager databaseupdater.username=root databaseupdater.password=pass - # DEBUG spring.jpa.show-sql=true # Do not modify diff --git a/src/main/resources/junit-platform.properties b/src/main/resources/junit-platform.properties index d265fd8..2af5bf8 100644 --- a/src/main/resources/junit-platform.properties +++ b/src/main/resources/junit-platform.properties @@ -1 +1 @@ -junit.jupiter.testinstance.lifecycle.default = per_class +junit.jupiter.testinstance.lifecycle.default=per_class diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepositoryTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepositoryTest.kt index fa622f0..7394f85 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepositoryTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MaterialRepositoryTest.kt @@ -10,8 +10,8 @@ import kotlin.test.assertEquals @DataJpaTest(excludeAutoConfiguration = [LiquibaseAutoConfiguration::class]) class MaterialRepositoryTest @Autowired constructor( - private val materialRepository: MaterialRepository, - private val entityManager: TestEntityManager + private val materialRepository: MaterialRepository, + private val entityManager: TestEntityManager ) { // updateInventoryQuantityById() diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepositoryTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepositoryTest.kt index e87c425..2362e33 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepositoryTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/repository/MixRepositoryTest.kt @@ -10,8 +10,8 @@ import kotlin.test.assertEquals @DataJpaTest(excludeAutoConfiguration = [LiquibaseAutoConfiguration::class]) class MixRepositoryTest @Autowired constructor( - private val mixRepository: MixRepository, - private val entityManager: TestEntityManager + private val mixRepository: MixRepository, + private val entityManager: TestEntityManager ) { // updateLocationById() diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AbstractServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AbstractServiceTest.kt index 3f960a4..f81f41b 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AbstractServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AbstractServiceTest.kt @@ -1,8 +1,9 @@ package dev.fyloz.colorrecipesexplorer.service import com.nhaarman.mockitokotlin2.* -import dev.fyloz.colorrecipesexplorer.exception.EntityAlreadyExistsException +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException +import dev.fyloz.colorrecipesexplorer.exception.RestException import dev.fyloz.colorrecipesexplorer.model.EntityDto import dev.fyloz.colorrecipesexplorer.model.Model import dev.fyloz.colorrecipesexplorer.model.NamedModel @@ -26,8 +27,8 @@ abstract class AbstractServiceTest, R : JpaRepository protected val entityList: List get() = listOf( - entity, - anotherEntity + entity, + anotherEntity ) @AfterEach @@ -90,7 +91,7 @@ abstract class AbstractServiceTest, R : JpaRepository } abstract class AbstractModelServiceTest, R : JpaRepository> : - AbstractServiceTest1() { + AbstractServiceTest1() { // existsById() @@ -124,23 +125,21 @@ abstract class AbstractModelServiceTest, R : J } @Test - open fun `getById() throws EntityNotFoundException when no entity with the given id exists in the repository`() { + open fun `getById() throws NotFoundException when no entity with the given id exists in the repository`() { whenever(repository.findById(entity.id!!)).doReturn(Optional.empty()) - val exception = assertThrows { service.getById(entity.id!!) } - assertTrue(exception.value is Long) - assertEquals(entity.id, exception.value as Long) + assertThrows { service.getById(entity.id!!) } + .assertErrorCode() } // save() @Test - open fun `save() throws EntityAlreadyExistsException when an entity with the given id exists in the repository`() { - doReturn(true).whenever(repository).existsById(entity.id!!) + open fun `save() throws AlreadyExistsException when an entity with the given id exists in the repository`() { + doReturn(true).whenever(service).existsById(entity.id!!) - val exception = assertThrows { service.save(entity) } - assertTrue(exception.id is Long) - assertEquals(entity.id, exception.id as Long) + assertThrows { service.save(entity) } + .assertErrorCode() } // update() @@ -158,12 +157,11 @@ abstract class AbstractModelServiceTest, R : J } @Test - open fun `update() throws EntityNotFoundException when no entity with the given id exists in the repository`() { + open fun `update() throws NotFoundException when no entity with the given id exists in the repository`() { doReturn(false).whenever(service).existsById(entity.id!!) - val exception = assertThrows { service.update(entity) } - assertTrue(exception.value is Long) - assertEquals(entity.id, exception.value as Long) + assertThrows { service.update(entity) } + .assertErrorCode() } // deleteById() @@ -179,7 +177,7 @@ abstract class AbstractModelServiceTest, R : J } abstract class AbstractNamedModelServiceTest, R : NamedJpaRepository> : - AbstractModelServiceTest() { + AbstractModelServiceTest() { protected abstract val entityWithEntityName: E // existsByName() @@ -214,21 +212,21 @@ abstract class AbstractNamedModelServiceTest { service.getByName(entity.name) } - assertEquals(entity.name, exception.value) + assertThrows { service.getByName(entity.name) } + .assertErrorCode("name") } // save() @Test - open fun `save() throws EntityAlreadyExistsException when an entity with the given name exists`() { + open fun `save() throws AlreadyExistsException when an entity with the given name exists`() { doReturn(true).whenever(service).existsByName(entity.name) - val exception = assertThrows { service.save(entity) } - assertEquals(entity.name, exception.id) + assertThrows { service.save(entity) } + .assertErrorCode("name") } // update() @@ -247,23 +245,21 @@ abstract class AbstractNamedModelServiceTest { service.update(entity) } - assertTrue(exception.value is Long) - assertEquals(entity.id, exception.value as Long) - + assertThrows { service.update(entity) } + .assertErrorCode("name") } @Test - open fun `update() throws EntityAlreadyExistsException when an entity with the updated name exists`() { + open fun `update() throws AlreadyExistsException when an entity with the updated name exists`() { whenever(repository.findByName(entity.name)).doReturn(entityWithEntityName) doReturn(entity).whenever(service).getById(entity.id!!) - val exception = assertThrows { service.update(entity) } - assertEquals(entity.name, exception.id) + assertThrows { service.update(entity) } + .assertErrorCode("name") } // deleteByName() @@ -284,7 +280,7 @@ interface ExternalModelServiceTest { // ==== IMPLEMENTATIONS FOR EXTERNAL SERVICES ==== // Lots of code duplication but I don't have a better solution for now abstract class AbstractExternalModelServiceTest, U : EntityDto, S : ExternalModelService, R : JpaRepository> : - AbstractModelServiceTest(), ExternalModelServiceTest { + AbstractModelServiceTest(), ExternalModelServiceTest { protected abstract val entitySaveDto: N protected abstract val entityUpdateDto: U @@ -296,7 +292,7 @@ abstract class AbstractExternalModelServiceTest, U : } abstract class AbstractExternalNamedModelServiceTest, U : EntityDto, S : ExternalNamedModelService, R : NamedJpaRepository> : - AbstractNamedModelServiceTest(), ExternalModelServiceTest { + AbstractNamedModelServiceTest(), ExternalModelServiceTest { protected abstract val entitySaveDto: N protected abstract val entityUpdateDto: U @@ -307,12 +303,25 @@ abstract class AbstractExternalNamedModelServiceTest> withBaseSaveDtoTest( - entity: E, - entitySaveDto: N, - service: ExternalService, - saveMockMatcher: () -> E = { entity }, - op: () -> Unit = {} + entity: E, + entitySaveDto: N, + service: ExternalService, + saveMockMatcher: () -> E = { entity }, + op: () -> Unit = {} ) { doReturn(entity).whenever(service).save(saveMockMatcher()) doReturn(entity).whenever(entitySaveDto).toEntity() @@ -326,11 +335,11 @@ fun > withBaseSaveDtoTest( } fun > withBaseUpdateDtoTest( - entity: E, - entityUpdateDto: U, - service: ExternalModelService, - updateMockMatcher: () -> E, - op: E.() -> Unit = {} + entity: E, + entityUpdateDto: U, + service: ExternalModelService, + updateMockMatcher: () -> E, + op: E.() -> Unit = {} ) { doAnswer { it.arguments[0] }.whenever(service).update(updateMockMatcher()) doReturn(entity).whenever(entityUpdateDto).toEntity() diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountsServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountsServiceTest.kt index ac536f8..a844d91 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountsServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/AccountsServiceTest.kt @@ -2,13 +2,15 @@ package dev.fyloz.colorrecipesexplorer.service import com.nhaarman.mockitokotlin2.* import dev.fyloz.colorrecipesexplorer.config.defaultGroupCookieName -import dev.fyloz.colorrecipesexplorer.exception.EntityAlreadyExistsException +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.repository.EmployeeGroupRepository import dev.fyloz.colorrecipesexplorer.repository.EmployeeRepository -import org.junit.jupiter.api.* +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows import org.springframework.mock.web.MockHttpServletResponse import org.springframework.security.core.userdetails.User import org.springframework.security.core.userdetails.UsernameNotFoundException @@ -16,10 +18,13 @@ import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder import java.util.* import javax.servlet.http.Cookie import javax.servlet.http.HttpServletRequest -import kotlin.test.* +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotNull +import kotlin.test.assertTrue class EmployeeServiceTest : - AbstractExternalModelServiceTest() { + AbstractExternalModelServiceTest() { private val passwordEncoder = BCryptPasswordEncoder() override val entity: Employee = employee(passwordEncoder, id = 0L) @@ -31,22 +36,23 @@ class EmployeeServiceTest : override val entityUpdateDto: EmployeeUpdateDto = spy(employeeUpdateDto(id = 0L)) override val repository: EmployeeRepository = mock() - override val service: EmployeeService = spy(EmployeeServiceImpl(repository, passwordEncoder)) + private val employeeGroupService: EmployeeGroupService = mock() + override val service: EmployeeService = spy(EmployeeServiceImpl(repository, employeeGroupService, passwordEncoder)) private val entitySaveDtoEmployee = Employee( - entitySaveDto.id, - entitySaveDto.firstName, - entitySaveDto.lastName, - passwordEncoder.encode(entitySaveDto.password), - isDefaultGroupUser = false, - isSystemUser = false, - group = null, - permissions = entitySaveDto.permissions + entitySaveDto.id, + entitySaveDto.firstName, + entitySaveDto.lastName, + passwordEncoder.encode(entitySaveDto.password), + isDefaultGroupUser = false, + isSystemUser = false, + group = null, + permissions = entitySaveDto.permissions ) @AfterEach override fun afterEach() { - reset(entitySaveDto, entityUpdateDto) + reset(employeeGroupService) super.afterEach() } @@ -73,33 +79,29 @@ class EmployeeServiceTest : // getById() @Test - fun `getById() throws EntityNotFoundException when the corresponding employee is a default group user`() { + fun `getById() throws NotFoundException when the corresponding employee is a default group user`() { whenever(repository.findById(entityDefaultGroupUser.id)).doReturn(Optional.of(entityDefaultGroupUser)) - val exception = assertThrows { + assertThrows { service.getById( - entityDefaultGroupUser.id, - ignoreDefaultGroupUsers = true, - ignoreSystemUsers = false + entityDefaultGroupUser.id, + ignoreDefaultGroupUsers = true, + ignoreSystemUsers = false ) - } - assertTrue(exception.value is Long) - assertEquals(entityDefaultGroupUser.id, exception.value as Long) + }.assertErrorCode() } @Test - fun `getById() throws EntityNotFoundException when the corresponding employee is a system user`() { + fun `getById() throws NotFoundException when the corresponding employee is a system user`() { whenever(repository.findById(entitySystemUser.id)).doReturn(Optional.of(entitySystemUser)) - val exception = assertThrows { + assertThrows { service.getById( - entitySystemUser.id, - ignoreDefaultGroupUsers = false, - ignoreSystemUsers = true + entitySystemUser.id, + ignoreDefaultGroupUsers = false, + ignoreSystemUsers = true ) - } - assertTrue(exception.value is Long) - assertEquals(entitySystemUser.id, exception.value as Long) + }.assertErrorCode() } // getByGroup() @@ -147,18 +149,20 @@ class EmployeeServiceTest : } @Test - fun `save() throws EntityAlreadyExistsException when firstName and lastName exists`() { + fun `save() throws AlreadyExistsException when firstName and lastName exists`() { doReturn(true).whenever(repository).existsByFirstNameAndLastName(entity.firstName, entity.lastName) - val exception = assertThrows { service.save(entity) } - assertEquals("${entity.firstName} ${entity.lastName}", exception.id) + assertThrows { service.save(entity) } + .assertErrorCode("fullName") } @Test override fun `save(dto) calls and returns save() with the created entity`() { - withBaseSaveDtoTest(entity, entitySaveDto, service, {argThat { - this.id == entity.id && this.firstName == entity.firstName && this.lastName == entity.lastName - }}) + withBaseSaveDtoTest(entity, entitySaveDto, service, { + argThat { + this.id == entity.id && this.firstName == entity.firstName && this.lastName == entity.lastName + } + }) } @Test @@ -175,29 +179,27 @@ class EmployeeServiceTest : @Test override fun `update(dto) calls and returns update() with the created entity`() = - withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) + withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) @Test - fun `update() throws EntityAlreadyExistsException when a different employee with the given first name and last name exists`() { + fun `update() throws AlreadyExistsException when a different employee with the given first name and last name exists`() { whenever(repository.findByFirstNameAndLastName(entity.firstName, entity.lastName)).doReturn( - entityDefaultGroupUser + entityDefaultGroupUser ) doReturn(entity).whenever(service).getById(eq(entity.id), any(), any()) - val exception = assertThrows { + assertThrows { service.update( - entity, - true, - ignoreSystemUsers = true + entity, + true, + ignoreSystemUsers = true ) - } - assertTrue(exception.id is String) - assertEquals("${entity.firstName} ${entity.lastName}", exception.id as String) + }.assertErrorCode("fullName") } } class EmployeeGroupServiceTest : - AbstractExternalNamedModelServiceTest() { + AbstractExternalNamedModelServiceTest() { private val employeeService: EmployeeService = mock() override val repository: EmployeeGroupRepository = mock() override val service: EmployeeGroupServiceImpl = spy(EmployeeGroupServiceImpl(employeeService, repository)) @@ -257,13 +259,12 @@ class EmployeeGroupServiceTest : } @Test - fun `getRequestDefaultGroup() throws EntityNotFoundException when the HTTP request does not contains a cookie for the default group`() { + fun `getRequestDefaultGroup() throws NoDefaultGroupException when the HTTP request does not contains a cookie for the default group`() { val request: HttpServletRequest = mock() whenever(request.cookies).doReturn(arrayOf()) - val exception = assertThrows { service.getRequestDefaultGroup(request) } - assertEquals("defaultGroup", exception.value) + assertThrows { service.getRequestDefaultGroup(request) } } // setResponseDefaultGroup() @@ -297,7 +298,7 @@ class EmployeeGroupServiceTest : @Test override fun `update(dto) calls and returns update() with the created entity`() = - withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) + withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) } class EmployeeUserDetailsServiceTest { @@ -317,7 +318,7 @@ class EmployeeUserDetailsServiceTest { fun `loadUserByUsername() calls loadUserByEmployeeId() with the given username as an id`() { whenever(employeeService.getById(eq(employee.id), any(), any())).doReturn(employee) doReturn(User(employee.id.toString(), employee.password, listOf())).whenever(service) - .loadUserByEmployeeId(employee.id) + .loadUserByEmployeeId(employee.id) service.loadUserByUsername(employee.id.toString()) @@ -327,9 +328,7 @@ class EmployeeUserDetailsServiceTest { @Test fun `loadUserByUsername() throws UsernameNotFoundException when no employee with the given id exists`() { whenever(employeeService.getById(eq(employee.id), any(), any())).doThrow( - NotFoundException( - employee.id - ) + employeeIdNotFoundException(employee.id) ) assertThrows { service.loadUserByUsername(employee.id.toString()) } diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyServiceTest.kt index 265151f..a2ebbc7 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/CompanyServiceTest.kt @@ -9,7 +9,7 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue class CompanyServiceTest : - AbstractExternalNamedModelServiceTest() { + AbstractExternalNamedModelServiceTest() { private val recipeService: RecipeService = mock() override val repository: CompanyRepository = mock() override val service: CompanyService = spy(CompanyServiceImpl(repository, recipeService)) @@ -57,7 +57,7 @@ class CompanyServiceTest : @Test override fun `update(dto) calls and returns update() with the created entity`() = - withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) + withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) // delete() diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryServiceTest.kt index 694eb90..aae3b92 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/InventoryServiceTest.kt @@ -1,7 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service import com.nhaarman.mockitokotlin2.* -import dev.fyloz.colorrecipesexplorer.exception.LowQuantitiesException import dev.fyloz.colorrecipesexplorer.model.* import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Test @@ -24,15 +23,15 @@ class InventoryServiceTest { @Test fun `add(materialQuantities) calls add() for each MaterialQuantityDto`() { val materialQuantities = listOf( - materialQuantityDto(materialId = 1, quantity = 1234f), - materialQuantityDto(materialId = 2, quantity = 2345f), - materialQuantityDto(materialId = 3, quantity = 3456f), - materialQuantityDto(materialId = 4, quantity = 4567f) + materialQuantityDto(materialId = 1, quantity = 1234f), + materialQuantityDto(materialId = 2, quantity = 2345f), + materialQuantityDto(materialId = 3, quantity = 3456f), + materialQuantityDto(materialId = 4, quantity = 4567f) ) val storedQuantity = 2000f doAnswer { storedQuantity + (it.arguments[0] as MaterialQuantityDto).quantity }.whenever(service) - .add(any()) + .add(any()) val found = service.add(materialQuantities) @@ -51,8 +50,8 @@ class InventoryServiceTest { val found = service.add(this) verify(materialService).updateQuantity( - argThat { this.id == this@withGivenQuantities.material }, - eq(this.quantity) + argThat { this.id == this@withGivenQuantities.material }, + eq(this.quantity) ) assertEquals(updatedQuantity, found) } @@ -66,15 +65,15 @@ class InventoryServiceTest { val materialPercents = material(id = 1L, materialType = materialType(usePercentages = true)) val mixRatio = mixRatio(ratio = 1.5f) val mix = mix( - id = mixRatio.id, - mixMaterials = mutableSetOf( - mixMaterial(id = 0L, material = material, quantity = 1000f, position = 0), - mixMaterial(id = 1L, material = materialPercents, quantity = 50f, position = 1) - ) + id = mixRatio.id, + mixMaterials = mutableSetOf( + mixMaterial(id = 0L, material = material, quantity = 1000f, position = 0), + mixMaterial(id = 1L, material = materialPercents, quantity = 50f, position = 1) + ) ) val expectedQuantities = mapOf( - 0L to 1500f, - 1L to 750f + 0L to 1500f, + 1L to 750f ) whenever(mixService.getById(mix.id!!)).doReturn(mix) @@ -98,15 +97,15 @@ class InventoryServiceTest { @Test fun `deduct(materialQuantities) calls deduct() for each MaterialQuantityDto`() { val materialQuantities = listOf( - materialQuantityDto(materialId = 1, quantity = 1234f), - materialQuantityDto(materialId = 2, quantity = 2345f), - materialQuantityDto(materialId = 3, quantity = 3456f), - materialQuantityDto(materialId = 4, quantity = 4567f) + materialQuantityDto(materialId = 1, quantity = 1234f), + materialQuantityDto(materialId = 2, quantity = 2345f), + materialQuantityDto(materialId = 3, quantity = 3456f), + materialQuantityDto(materialId = 4, quantity = 4567f) ) val storedQuantity = 5000f doAnswer { storedQuantity - (it.arguments[0] as MaterialQuantityDto).quantity }.whenever(service) - .deduct(any()) + .deduct(any()) val found = service.deduct(materialQuantities) @@ -117,22 +116,20 @@ class InventoryServiceTest { } @Test - fun `deduct(materialQuantities) throws LowQuantitiesException when there is not enough inventory of a given material`() { + fun `deduct(materialQuantities) throws MultiplesNotEnoughInventoryException when there is not enough inventory of a given material`() { val materialQuantities = listOf( - materialQuantityDto(materialId = 1, quantity = 1234f), - materialQuantityDto(materialId = 2, quantity = 2345f), - materialQuantityDto(materialId = 3, quantity = 3456f), - materialQuantityDto(materialId = 4, quantity = 4567f) + materialQuantityDto(materialId = 1, quantity = 1234f), + materialQuantityDto(materialId = 2, quantity = 2345f), + materialQuantityDto(materialId = 3, quantity = 3456f), + materialQuantityDto(materialId = 4, quantity = 4567f) ) val inventoryQuantity = 3000f - val lowQuantities = materialQuantities.filter { it.quantity > inventoryQuantity } materialQuantities.forEach { withGivenQuantities(inventoryQuantity, it) } - val exception = assertThrows { service.deduct(materialQuantities) } - assertTrue { exception.materialQuantities.containsAll(lowQuantities) } + assertThrows { service.deduct(materialQuantities) } } @Test @@ -144,26 +141,25 @@ class InventoryServiceTest { val found = service.deduct(this) verify(materialService).updateQuantity( - argThat { this.id == this@withGivenQuantities.material }, - eq(-this.quantity) + argThat { this.id == this@withGivenQuantities.material }, + eq(-this.quantity) ) assertEquals(updatedQuantity, found) } } @Test - fun `deduct(materialQuantity) throws LowQuantityException when there is not enough inventory of the given material`() { + fun `deduct(materialQuantity) throws NotEnoughInventoryException when there is not enough inventory of the given material`() { withGivenQuantities(0f, 1000f) { - val exception = assertThrows { service.deduct(this) } - assertEquals(this, exception.materialQuantity) + assertThrows { service.deduct(this) } } } private fun withGivenQuantities( - stored: Float, - quantity: Float, - materialId: Long = 0L, - test: MaterialQuantityDto.(Float) -> Unit = {} + stored: Float, + quantity: Float, + materialId: Long = 0L, + test: MaterialQuantityDto.(Float) -> Unit = {} ) { val materialQuantity = materialQuantityDto(materialId = materialId, quantity = quantity) @@ -171,9 +167,9 @@ class InventoryServiceTest { } private fun withGivenQuantities( - stored: Float, - materialQuantity: MaterialQuantityDto, - test: MaterialQuantityDto.(Float) -> Unit = {} + stored: Float, + materialQuantity: MaterialQuantityDto, + test: MaterialQuantityDto.(Float) -> Unit = {} ) { val material = material(id = materialQuantity.material, inventoryQuantity = stored) diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialServiceTest.kt index 43a1b76..6da874e 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialServiceTest.kt @@ -1,7 +1,7 @@ package dev.fyloz.colorrecipesexplorer.service import com.nhaarman.mockitokotlin2.* -import dev.fyloz.colorrecipesexplorer.exception.EntityAlreadyExistsException +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.repository.MaterialRepository import dev.fyloz.colorrecipesexplorer.service.files.SimdutService @@ -14,14 +14,14 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue class MaterialServiceTest : - AbstractExternalNamedModelServiceTest() { + AbstractExternalNamedModelServiceTest() { override val repository: MaterialRepository = mock() private val simdutService: SimdutService = mock() private val recipeService: RecipeService = mock() private val mixService: MixService = mock() private val materialTypeService: MaterialTypeService = mock() override val service: MaterialService = - spy(MaterialServiceImpl(repository, simdutService, recipeService, mixService, materialTypeService)) + spy(MaterialServiceImpl(repository, simdutService, recipeService, mixService, materialTypeService)) override val entity: Material = material(id = 0L, name = "material") override val anotherEntity: Material = material(id = 1L, name = "another material") @@ -99,19 +99,19 @@ class MaterialServiceTest : @Test fun `getAllIdsWithSimdut() returns a list containing the identifier of every material with a SIMDUT file`() { val materials = listOf( - material(id = 0L), - material(id = 1L), - material(id = 2L), - material(id = 3L) + material(id = 0L), + material(id = 1L), + material(id = 2L), + material(id = 3L) ) val hasSimdut = mapOf( - *materials - .map { it.id!! to it.evenId } - .toTypedArray() + *materials + .map { it.id!! to it.evenId } + .toTypedArray() ) val expectedIds = hasSimdut - .filter { it.value } - .map { it.key } + .filter { it.value } + .map { it.key } whenever(simdutService.exists(any())).doAnswer { hasSimdut[(it.arguments[0] as Material).id] } doReturn(materials).whenever(service).getAllNotMixType() @@ -124,11 +124,11 @@ class MaterialServiceTest : // save() @Test - fun `save() throws EntityAlreadyExistsException when a material with the given name exists in the repository`() { + fun `save() throws AlreadyExistsException when a material with the given name exists in the repository`() { doReturn(true).whenever(service).existsByName(entity.name) - val exception = assertThrows { service.save(entity) } - assertEquals(entity.name, exception.id) + assertThrows { service.save(entity) } + .assertErrorCode("name") } @Test @@ -152,15 +152,15 @@ class MaterialServiceTest : // update() @Test - fun `update() throws EntityAlreadyExistsException when another material with the updated name exists in the repository`() { + fun `update() throws AlreadyExistsException when another material with the updated name exists in the repository`() { val material = material(id = 0L, name = "name") val anotherMaterial = material(id = 1L, name = "name") whenever(repository.findByName(material.name)).doReturn(anotherMaterial) doReturn(entity).whenever(service).getById(material.id!!) - val exception = assertThrows { service.update(material) } - assertEquals(material.name, exception.id) + assertThrows { service.update(material) } + .assertErrorCode("name") } // updateQuantity() @@ -186,7 +186,7 @@ class MaterialServiceTest : val anotherMixTypeMaterial = material(id = 2L, isMixType = true) val materials = listOf(normalMaterial, mixTypeMaterial, anotherMixTypeMaterial) val recipe = - recipe(id = 0L, mixes = mutableListOf(mix(mixType = mixType(id = 0L, material = mixTypeMaterial)))) + recipe(id = 0L, mixes = mutableListOf(mix(mixType = mixType(id = 0L, material = mixTypeMaterial)))) whenever(recipeService.getById(recipe.id!!)).doReturn(recipe) doReturn(materials).whenever(service).getAll() @@ -244,6 +244,6 @@ class MaterialServiceTest : } /** Utility property to check if the identifier of the given [Material] is even. */ - val Material.evenId: Boolean + private val Material.evenId: Boolean get() = this.id!! % 2 == 0L } diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeServiceTest.kt index 608e180..6846394 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MaterialTypeServiceTest.kt @@ -1,7 +1,7 @@ package dev.fyloz.colorrecipesexplorer.service import com.nhaarman.mockitokotlin2.* -import dev.fyloz.colorrecipesexplorer.exception.EntityAlreadyExistsException +import dev.fyloz.colorrecipesexplorer.exception.AlreadyExistsException import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.repository.MaterialTypeRepository @@ -13,7 +13,7 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue class MaterialTypeServiceTest : - AbstractExternalNamedModelServiceTest() { + AbstractExternalNamedModelServiceTest() { override val repository: MaterialTypeRepository = mock() private val materialService: MaterialService = mock() override val service: MaterialTypeService = spy(MaterialTypeServiceImpl(repository, materialService)) @@ -24,7 +24,7 @@ class MaterialTypeServiceTest : private val anotherSystemType = materialType(id = 4L, name = "another systype", prefix = "ASY", systemType = true) override val entitySaveDto: MaterialTypeSaveDto = spy(materialTypeSaveDto(name = "material type", prefix = "MAT")) override val entityUpdateDto: MaterialTypeUpdateDto = - spy(materialTypeUpdateDto(id = 0L, name = "material type", prefix = "MAT")) + spy(materialTypeUpdateDto(id = 0L, name = "material type", prefix = "MAT")) @AfterEach override fun afterEach() { @@ -106,18 +106,18 @@ class MaterialTypeServiceTest : // saveMaterialType() @Test - fun `saveMaterialType() throws EntityAlreadyExistsException when a material type with the given prefix already exists`() { + fun `saveMaterialType() throws AlreadyExistsException when a material type with the given prefix already exists`() { doReturn(true).whenever(service).existsByPrefix(entity.prefix) - val exception = assertThrows { service.save(entity) } - assertEquals(entity.prefix, exception.id) + assertThrows { service.save(entity) } + .assertErrorCode("prefix") } // update() @Test override fun `update(dto) calls and returns update() with the created entity`() = - withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) + withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) override fun `update() saves in the repository and returns the updated value`() { whenever(repository.save(entity)).doReturn(entity) @@ -132,35 +132,34 @@ class MaterialTypeServiceTest : assertEquals(entity, found) } - override fun `update() throws EntityNotFoundException when no entity with the given id exists in the repository`() { + override fun `update() throws NotFoundException when no entity with the given id exists in the repository`() { whenever(repository.findByName(entity.name)).doReturn(null) whenever(repository.findByPrefix(entity.prefix)).doReturn(null) doReturn(false).whenever(service).existsById(entity.id!!) doReturn(null).whenever(service).getById(entity.id!!) - val exception = assertThrows { service.update(entity) } - assertTrue(exception.value is Long) - assertEquals(entity.id, exception.value as Long) + assertThrows { service.update(entity) } + .assertErrorCode() } - override fun `update() throws EntityAlreadyExistsException when an entity with the updated name exists`() { + override fun `update() throws AlreadyExistsException when an entity with the updated name exists`() { whenever(repository.findByName(entity.name)).doReturn(entityWithEntityName) whenever(repository.findByPrefix(entity.prefix)).doReturn(null) doReturn(true).whenever(service).existsById(entity.id!!) doReturn(entity).whenever(service).getById(entity.id!!) - val exception = assertThrows { service.update(entity) } - assertEquals(entity.name, exception.id) + assertThrows { service.update(entity) } + .assertErrorCode("name") } @Test - fun `update() throws EntityAlreadyExistsException when an entity with the updated prefix exists`() { + fun `update() throws AlreadyExistsException when an entity with the updated prefix exists`() { val anotherMaterialType = materialType(prefix = entity.prefix) whenever(repository.findByPrefix(entity.prefix)).doReturn(anotherMaterialType) doReturn(entity).whenever(service).getById(entity.id!!) - val exception = assertThrows { service.update(entity) } - assertEquals(entity.prefix, exception.id) + assertThrows { service.update(entity) } + .assertErrorCode("prefix") } // delete() @@ -173,8 +172,4 @@ class MaterialTypeServiceTest : verify(repository).delete(entity) } - - override fun `deleteById() deletes the entity with the given id in the repository`() { - super.`deleteById() deletes the entity with the given id in the repository`() - } } diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialServiceTest.kt index 464aff2..35259e4 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/MixMaterialServiceTest.kt @@ -43,18 +43,18 @@ class MixMaterialServiceTest : AbstractModelServiceTest()) @@ -81,8 +81,8 @@ class MixMaterialServiceTest : AbstractModelServiceTest()) @@ -85,9 +85,9 @@ class MixServiceTest : AbstractExternalModelServiceTest Unit + scope: MixUpdateDtoTestScope = MixUpdateDtoTestScope(), + sharedMixType: Boolean = false, + op: MixUpdateDtoTestScope.() -> Unit ) { with(scope) { doReturn(true).whenever(service).existsById(mix.id!!) @@ -127,7 +127,7 @@ class MixServiceTest : AbstractExternalModelServiceTest>())).doAnswer { (it.arguments[0] as Set).map { dto -> mixMaterial( - material = material(id = dto.materialId), - quantity = dto.quantity, - position = dto.position + material = material(id = dto.materialId), + quantity = dto.quantity, + position = dto.position ) }.toSet() } @@ -189,10 +189,10 @@ class MixServiceTest : AbstractExternalModelServiceTest { service.getByMaterial(material) } - assertEquals(material.name, exception.value) + assertThrows { service.getByMaterial(material) } + .assertErrorCode("name") } // getByNameAndMaterialType() @@ -100,11 +100,11 @@ class MixTypeServiceTest : AbstractNamedModelServiceTest { service.save(entity) } - assertEquals(entity.name, exception.id) + assertThrows { service.save(entity) } + .assertErrorCode("name") } // saveForNameAndMaterialType() diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt index 3851792..3bb751e 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeServiceTest.kt @@ -1,7 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service import com.nhaarman.mockitokotlin2.* -import dev.fyloz.colorrecipesexplorer.exception.NotFoundException import dev.fyloz.colorrecipesexplorer.model.* import dev.fyloz.colorrecipesexplorer.repository.RecipeRepository import dev.fyloz.colorrecipesexplorer.service.files.FileService @@ -16,7 +15,7 @@ import kotlin.test.assertFalse import kotlin.test.assertTrue class RecipeServiceTest : - AbstractExternalModelServiceTest() { + AbstractExternalModelServiceTest() { override val repository: RecipeRepository = mock() private val companyService: CompanyService = mock() private val mixService: MixService = mock() @@ -79,22 +78,22 @@ class RecipeServiceTest : @Test override fun `update(dto) calls and returns update() with the created entity`() = - withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) + withBaseUpdateDtoTest(entity, entityUpdateDto, service, { any() }) // updatePublicData() @Test fun `updatePublicData() updates the notes of a recipe groups information according to the RecipePublicDataDto`() { val recipe = recipe( - id = 0L, groupsInformation = setOf( - recipeGroupInformation(id = 0L, group = employeeGroup(id = 1L), note = "Old note"), - recipeGroupInformation(id = 1L, group = employeeGroup(id = 2L), note = "Another note"), - recipeGroupInformation(id = 2L, group = employeeGroup(id = 3L), note = "Up to date note") - ) + id = 0L, groupsInformation = setOf( + recipeGroupInformation(id = 0L, group = employeeGroup(id = 1L), note = "Old note"), + recipeGroupInformation(id = 1L, group = employeeGroup(id = 2L), note = "Another note"), + recipeGroupInformation(id = 2L, group = employeeGroup(id = 3L), note = "Up to date note") + ) ) val notes = setOf( - noteDto(groupId = 1, content = "Note 1"), - noteDto(groupId = 2, content = null) + noteDto(groupId = 1, content = "Note 1"), + noteDto(groupId = 2, content = null) ) val publicData = recipePublicDataDto(recipeId = recipe.id!!, notes = notes) @@ -114,10 +113,12 @@ class RecipeServiceTest : @Test fun `updatePublicData() update the location of a recipe mixes in the mix service according to the RecipePublicDataDto`() { - val publicData = recipePublicDataDto(mixesLocation = setOf( + val publicData = recipePublicDataDto( + mixesLocation = setOf( mixLocationDto(mixId = 0L, location = "Loc 1"), mixLocationDto(mixId = 1L, location = "Loc 2") - )) + ) + ) service.updatePublicData(publicData) @@ -193,13 +194,11 @@ class RecipeImageServiceTest { } @Test - fun `getByIdForRecipe() throws EntityNotFoundException when no image with the given recipe and image id exists`() { + fun `getByIdForRecipe() throws RecipeImageNotFoundException when no image with the given recipe and image id exists`() { doReturn(imagePath).whenever(service).getPath(imageId, recipeId) whenever(fileService.readAsBytes(imagePath)).doAnswer { throw NoSuchFileException(imagePath) } - val exception = - assertThrows { service.getByIdForRecipe(imageId, recipeId) } - assertEquals("$recipeId/$imageId", exception.value) + assertThrows { service.getByIdForRecipe(imageId, recipeId) } } diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepServiceTest.kt index d7180aa..714b4a7 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/RecipeStepServiceTest.kt @@ -7,7 +7,7 @@ import dev.fyloz.colorrecipesexplorer.model.recipeStep import dev.fyloz.colorrecipesexplorer.repository.RecipeStepRepository class RecipeStepServiceTest : - AbstractModelServiceTest() { + AbstractModelServiceTest() { override val repository: RecipeStepRepository = mock() override val service: RecipeStepService = spy(RecipeStepServiceImpl(repository)) diff --git a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutServiceTest.kt b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutServiceTest.kt index 9cfc0f0..c80391b 100644 --- a/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutServiceTest.kt +++ b/src/test/kotlin/dev/fyloz/colorrecipesexplorer/service/files/SimdutServiceTest.kt @@ -1,7 +1,6 @@ package dev.fyloz.colorrecipesexplorer.service.files import com.nhaarman.mockitokotlin2.* -import dev.fyloz.colorrecipesexplorer.exception.SimdutWriteException import dev.fyloz.colorrecipesexplorer.model.Material import dev.fyloz.colorrecipesexplorer.model.material import org.junit.jupiter.api.AfterEach @@ -26,7 +25,7 @@ class SimdutServiceTest { @JvmName("withNullableMaterialPath") private inline fun withMaterialPath(material: Material? = null, exists: Boolean = true, test: (String) -> Unit) = - withMaterialPath(material ?: this.material, exists, test) + withMaterialPath(material ?: this.material, exists, test) private inline fun withMaterialPath(material: Material, exists: Boolean = true, test: (String) -> Unit) { val path = "data/simdut/${material.id}" @@ -109,8 +108,7 @@ class SimdutServiceTest { whenever(fileService.write(simdutMultipart, path)).doReturn(false) - val exception = assertThrows { service.write(material, simdutMultipart) } - assertEquals(material, exception.material) + assertThrows { service.write(material, simdutMultipart) } } }