Enhanced owner validation and property checks in services:
- **Backend**: - Check ownership before execution in DestinationService and PremisesService - Added Valid period check in pre flight check - Fixed allowed headers in cors config - added user groups to migration
This commit is contained in:
parent
302967e645
commit
a7ea4d97d2
30 changed files with 425 additions and 315 deletions
|
|
@ -14,17 +14,24 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="bulk-operation-caption">dataset</div>
|
<div class="bulk-operation-caption">dataset</div>
|
||||||
<div class="bulk-operation-data">
|
<div class="bulk-operation-data">
|
||||||
<radio-option name="export-dataset" value="NODE" v-model="exportDataset">nodes</radio-option>
|
<radio-option v-if="canModify('nodes')" name="export-dataset" value="NODE" v-model="exportDataset">nodes
|
||||||
<radio-option name="export-dataset" value="COUNTRY_MATRIX" v-model="exportDataset">kilometer rates
|
|
||||||
</radio-option>
|
</radio-option>
|
||||||
<radio-option name="export-dataset" value="CONTAINER_RATE" v-model="exportDataset">container rates
|
<radio-option v-if="canModify('rates')" name="export-dataset" value="COUNTRY_MATRIX"
|
||||||
|
v-model="exportDataset">kilometer rates
|
||||||
|
</radio-option>
|
||||||
|
<radio-option v-if="canModify('rates')" name="export-dataset" value="CONTAINER_RATE"
|
||||||
|
v-model="exportDataset">container rates
|
||||||
|
</radio-option>
|
||||||
|
<radio-option v-if="canModify('materials')" name="export-dataset" value="MATERIAL" v-model="exportDataset">
|
||||||
|
materials
|
||||||
|
</radio-option>
|
||||||
|
<radio-option v-if="canModify('packaging')" name="export-dataset" value="PACKAGING" v-model="exportDataset">
|
||||||
|
packaging
|
||||||
</radio-option>
|
</radio-option>
|
||||||
<radio-option name="export-dataset" value="MATERIAL" v-model="exportDataset">materials</radio-option>
|
|
||||||
<radio-option name="export-dataset" value="PACKAGING" v-model="exportDataset">packaging</radio-option>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bulk-operation-caption">validity period</div>
|
<div v-if="canModify('rates')" class="bulk-operation-caption">validity period</div>
|
||||||
<div class="bulk-operation-data">
|
<div v-if="canModify('rates')" class="bulk-operation-data">
|
||||||
<div class="period-select-container">
|
<div class="period-select-container">
|
||||||
<dropdown :options="periods"
|
<dropdown :options="periods"
|
||||||
emptyText="No property set available"
|
emptyText="No property set available"
|
||||||
|
|
@ -48,13 +55,20 @@
|
||||||
<div class="bulk-operation-header">Import</div>
|
<div class="bulk-operation-header">Import</div>
|
||||||
<div class="bulk-operation-caption">dataset</div>
|
<div class="bulk-operation-caption">dataset</div>
|
||||||
<div class="bulk-operation-data">
|
<div class="bulk-operation-data">
|
||||||
<radio-option name="import-dataset" value="NODE" v-model="importDataset">nodes</radio-option>
|
<radio-option v-if="canModify('nodes')" name="import-dataset" value="NODE" v-model="importDataset">nodes
|
||||||
<radio-option name="import-dataset" value="COUNTRY_MATRIX" v-model="importDataset">kilometer rates
|
|
||||||
</radio-option>
|
</radio-option>
|
||||||
<radio-option name="import-dataset" value="CONTAINER_RATE" v-model="importDataset">container rates
|
<radio-option v-if="canModify('rates')" name="import-dataset" value="COUNTRY_MATRIX"
|
||||||
|
v-model="importDataset">kilometer rates
|
||||||
|
</radio-option>
|
||||||
|
<radio-option v-if="canModify('rates')" name="import-dataset" value="CONTAINER_RATE"
|
||||||
|
v-model="importDataset">container rates
|
||||||
|
</radio-option>
|
||||||
|
<radio-option v-if="canModify('materials')" name="import-dataset" value="MATERIAL" v-model="importDataset">
|
||||||
|
materials
|
||||||
|
</radio-option>
|
||||||
|
<radio-option v-if="canModify('packaging')" name="import-dataset" value="PACKAGING" v-model="importDataset">
|
||||||
|
packaging
|
||||||
</radio-option>
|
</radio-option>
|
||||||
<radio-option name="import-dataset" value="MATERIAL" v-model="importDataset">materials</radio-option>
|
|
||||||
<radio-option name="import-dataset" value="PACKAGING" v-model="importDataset">packaging</radio-option>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bulk-operation-caption">file</div>
|
<div class="bulk-operation-caption">file</div>
|
||||||
|
|
@ -79,8 +93,11 @@
|
||||||
<div class="bulk-operation-box-status-container">
|
<div class="bulk-operation-box-status-container">
|
||||||
<div class="bulk-operation-status">
|
<div class="bulk-operation-status">
|
||||||
<div class="bulk-operation-header">History</div>
|
<div class="bulk-operation-header">History</div>
|
||||||
<div v-if="this.bulkOperationStore.getBulkOperations.length === 0" class="empty-container">No recent bulk operations</div>
|
<div v-if="this.bulkOperationStore.getBulkOperations.length === 0" class="empty-container">No recent bulk
|
||||||
<bulk-operation v-else v-for="bulk in this.bulkOperationStore.getBulkOperations" :key="bulk.id" :operation="bulk" @download="fetchFile"></bulk-operation>
|
operations
|
||||||
|
</div>
|
||||||
|
<bulk-operation v-else v-for="bulk in this.bulkOperationStore.getBulkOperations" :key="bulk.id"
|
||||||
|
:operation="bulk" @download="fetchFile"></bulk-operation>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -101,6 +118,7 @@ import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
||||||
import {useBulkOperationStore} from "@/store/bulkOperation.js";
|
import {useBulkOperationStore} from "@/store/bulkOperation.js";
|
||||||
import BulkOperation from "@/components/layout/bulkoperation/BulkOperation.vue";
|
import BulkOperation from "@/components/layout/bulkoperation/BulkOperation.vue";
|
||||||
import logger from "@/logger.js";
|
import logger from "@/logger.js";
|
||||||
|
import {useActiveUserStore} from "@/store/activeuser.js";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "BulkOperations",
|
name: "BulkOperations",
|
||||||
|
|
@ -125,13 +143,13 @@ export default {
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
async isSelected(newVal) {
|
async isSelected(newVal) {
|
||||||
if(newVal === true)
|
if (newVal === true && this.activeUserStore.allowRates)
|
||||||
await this.validityPeriodStore.loadPeriods();
|
await this.validityPeriodStore.loadPeriods();
|
||||||
await this.bulkOperationStore.manageStatus();
|
await this.bulkOperationStore.manageStatus();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
...mapStores(useValidityPeriodStore, useBulkOperationStore),
|
...mapStores(useValidityPeriodStore, useBulkOperationStore, useActiveUserStore),
|
||||||
showValidityPeriod() {
|
showValidityPeriod() {
|
||||||
return this.exportType === "download" && (this.exportDataset === "COUNTRY_MATRIX" || this.exportDataset === "CONTAINER_RATE");
|
return this.exportType === "download" && (this.exportDataset === "COUNTRY_MATRIX" || this.exportDataset === "CONTAINER_RATE");
|
||||||
},
|
},
|
||||||
|
|
@ -167,8 +185,20 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
canModify(role) {
|
||||||
|
switch (role) {
|
||||||
|
case "nodes":
|
||||||
|
return this.activeUserStore.isSuper;
|
||||||
|
case "rates":
|
||||||
|
return this.activeUserStore.isSuper || this.activeUserStore.isFreight;
|
||||||
|
case "materials":
|
||||||
|
return this.activeUserStore.isSuper || this.activeUserStore.isMaterial;
|
||||||
|
case "packaging":
|
||||||
|
return this.activeUserStore.isSuper || this.activeUserStore.isPackaging;
|
||||||
|
}
|
||||||
|
},
|
||||||
buildDate(date) {
|
buildDate(date) {
|
||||||
if(date === null) return "not set";
|
if (date === null) return "not set";
|
||||||
|
|
||||||
return `${date[0]}-${date[1].toString().padStart(2, '0')}-${date[2].toString().padStart(2, '0')} ${date[3]?.toString().padStart(2, '0') ?? '00'}:${date[4]?.toString().padStart(2, '0') ?? '00'}:${date[5]?.toString().padStart(2, '0') ?? '00'}`
|
return `${date[0]}-${date[1].toString().padStart(2, '0')}-${date[2].toString().padStart(2, '0')} ${date[3]?.toString().padStart(2, '0') ?? '00'}:${date[4]?.toString().padStart(2, '0') ?? '00'}:${date[5]?.toString().padStart(2, '0') ?? '00'}`
|
||||||
},
|
},
|
||||||
|
|
@ -195,7 +225,7 @@ export default {
|
||||||
this.fileBlob = await this.readFileAsBlob(file);
|
this.fileBlob = await this.readFileAsBlob(file);
|
||||||
|
|
||||||
// File-Objekt mit dem Blob erstellen, das den originalen Namen und Typ behält
|
// File-Objekt mit dem Blob erstellen, das den originalen Namen und Typ behält
|
||||||
this.selectedFile = new File([this.fileBlob], file.name, { type: file.type });
|
this.selectedFile = new File([this.fileBlob], file.name, {type: file.type});
|
||||||
this.selectedFileName = file.name;
|
this.selectedFileName = file.name;
|
||||||
|
|
||||||
logger.info(`File loaded into memory: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`);
|
logger.info(`File loaded into memory: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`);
|
||||||
|
|
@ -220,7 +250,7 @@ export default {
|
||||||
|
|
||||||
reader.onload = (e) => {
|
reader.onload = (e) => {
|
||||||
// ArrayBuffer in Blob konvertieren
|
// ArrayBuffer in Blob konvertieren
|
||||||
const blob = new Blob([e.target.result], { type: file.type });
|
const blob = new Blob([e.target.result], {type: file.type});
|
||||||
resolve(blob);
|
resolve(blob);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,19 +77,22 @@ export default {
|
||||||
tabsConfig() {
|
tabsConfig() {
|
||||||
const tabs = [];
|
const tabs = [];
|
||||||
|
|
||||||
if(this.activeUserStore.isSuper) {
|
if (this.activeUserStore.isSuper) {
|
||||||
tabs.push(this.propertiesTab);
|
tabs.push(this.propertiesTab);
|
||||||
tabs.push(this.systemLogTab);
|
tabs.push(this.systemLogTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.activeUserStore.isService) {
|
if (this.activeUserStore.isService) {
|
||||||
tabs.push(this.appsTab);
|
tabs.push(this.appsTab);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.activeUserStore.isSuper || this.activeUserStore.isMaterial) {
|
||||||
tabs.push(this.materialsTab);
|
tabs.push(this.materialsTab);
|
||||||
|
}
|
||||||
|
|
||||||
tabs.push(this.nodesTab);
|
tabs.push(this.nodesTab);
|
||||||
|
|
||||||
if(this.activeUserStore.allowRates)
|
if (this.activeUserStore.allowRates)
|
||||||
tabs.push(this.ratesTab);
|
tabs.push(this.ratesTab);
|
||||||
|
|
||||||
tabs.push(this.bulkOperationsTab);
|
tabs.push(this.bulkOperationsTab);
|
||||||
|
|
|
||||||
|
|
@ -18,12 +18,12 @@ export const useActiveUserStore = defineStore('activeUser', {
|
||||||
allowConfiguration(state) {
|
allowConfiguration(state) {
|
||||||
if (state.user === null)
|
if (state.user === null)
|
||||||
return false;
|
return false;
|
||||||
return state.user.groups?.includes("super") || state.user.groups?.includes("freight") || state.user.groups?.includes("packaging") || state.user.groups?.includes("service");
|
return state.user.groups?.includes("super") || state.user.groups?.includes("freight") || state.user.groups?.includes("packaging") || state.user.groups?.includes("service") || state.user.groups?.includes("material");
|
||||||
},
|
},
|
||||||
allowReporting(state) {
|
allowReporting(state) {
|
||||||
if (state.user === null)
|
if (state.user === null)
|
||||||
return false;
|
return false;
|
||||||
return state.user.groups?.includes("super") || state.user.groups?.includes("freight") || state.user.groups?.includes("packaging") || state.user.groups?.includes("basic") || state.user.groups?.includes("calculation");
|
return state.user.groups?.includes("super") || state.user.groups?.includes("freight") || state.user.groups?.includes("packaging") || state.user.groups?.includes("material") || state.user.groups?.includes("basic") || state.user.groups?.includes("calculation");
|
||||||
},
|
},
|
||||||
isSuper(state) {
|
isSuper(state) {
|
||||||
if (state.user === null)
|
if (state.user === null)
|
||||||
|
|
@ -45,6 +45,11 @@ export const useActiveUserStore = defineStore('activeUser', {
|
||||||
return false;
|
return false;
|
||||||
return state.user.groups?.includes("freight");
|
return state.user.groups?.includes("freight");
|
||||||
},
|
},
|
||||||
|
isMaterial(state) {
|
||||||
|
if (state.user === null)
|
||||||
|
return false;
|
||||||
|
return state.user.groups?.includes("material");
|
||||||
|
},
|
||||||
allowRates(state) {
|
allowRates(state) {
|
||||||
if (state.user === null)
|
if (state.user === null)
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import {defineStore} from 'pinia'
|
||||||
import {config} from '@/config'
|
import {config} from '@/config'
|
||||||
import {useErrorStore} from "@/store/error.js";
|
import {useErrorStore} from "@/store/error.js";
|
||||||
import performRequest from "@/backend.js";
|
import performRequest from "@/backend.js";
|
||||||
|
import logger from "@/logger.js";
|
||||||
|
|
||||||
export const useMaterialStore = defineStore('material', {
|
export const useMaterialStore = defineStore('material', {
|
||||||
state() {
|
state() {
|
||||||
|
|
|
||||||
|
|
@ -14,63 +14,63 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@Configuration
|
//@Configuration
|
||||||
@EnableWebMvc
|
//@EnableWebMvc
|
||||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
//@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||||
public class CorsConfig implements WebMvcConfigurer {
|
public class CorsConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
private final Environment environment;
|
// private final Environment environment;
|
||||||
|
//
|
||||||
@Value("${lcc.allowed_cors}")
|
// @Value("${lcc.allowed_cors}")
|
||||||
private String allowedCors;
|
// private String allowedCors;
|
||||||
|
//
|
||||||
public CorsConfig(Environment environment) {
|
// public CorsConfig(Environment environment) {
|
||||||
this.environment = environment;
|
// this.environment = environment;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
@Override
|
// @Override
|
||||||
public void addCorsMappings(@NotNull CorsRegistry registry) {
|
// public void addCorsMappings(@NotNull CorsRegistry registry) {
|
||||||
String[] activeProfiles = environment.getActiveProfiles();
|
// String[] activeProfiles = environment.getActiveProfiles();
|
||||||
|
//
|
||||||
System.out.println("Active profiles: " + Arrays.toString(activeProfiles));
|
// System.out.println("Active profiles: " + Arrays.toString(activeProfiles));
|
||||||
System.out.println("Allowed CORS: " + allowedCors);
|
// System.out.println("Allowed CORS: " + allowedCors);
|
||||||
|
//
|
||||||
if (Arrays.asList(activeProfiles).contains("dev")) {
|
// if (Arrays.asList(activeProfiles).contains("dev")) {
|
||||||
|
//
|
||||||
System.out.println("Applying DEV CORS configuration");
|
// System.out.println("Applying DEV CORS configuration");
|
||||||
|
//
|
||||||
// Development CORS configuration
|
// // Development CORS configuration
|
||||||
registry.addMapping("/api/**")
|
// registry.addMapping("/api/**")
|
||||||
.allowedOriginPatterns("http://localhost:*")
|
// .allowedOriginPatterns("http://localhost:*")
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
.allowedHeaders("*")
|
// .allowedHeaders("*")
|
||||||
.exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
// .exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
||||||
.allowCredentials(true);
|
// .allowCredentials(true);
|
||||||
|
//
|
||||||
// OAuth endpoints
|
// // OAuth endpoints
|
||||||
registry.addMapping("/oauth/**")
|
// registry.addMapping("/oauth/**")
|
||||||
.allowedOriginPatterns("http://localhost:*")
|
// .allowedOriginPatterns("http://localhost:*")
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
.allowedHeaders("*")
|
// .allowedHeaders("*")
|
||||||
.allowCredentials(true);
|
// .allowCredentials(true);
|
||||||
} else {
|
// } else {
|
||||||
|
//
|
||||||
System.out.println("Applying PROD CORS configuration");
|
// System.out.println("Applying PROD CORS configuration");
|
||||||
|
//
|
||||||
// Production CORS configuration
|
// // Production CORS configuration
|
||||||
registry.addMapping("/api/**")
|
// registry.addMapping("/api/**")
|
||||||
.allowedOrigins(allowedCors)
|
// .allowedOrigins(allowedCors)
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
.allowedHeaders("*")
|
// .allowedHeaders("*")
|
||||||
.exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
// .exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
||||||
.allowCredentials(true);
|
// .allowCredentials(true);
|
||||||
|
//
|
||||||
// OAuth endpoints
|
// // OAuth endpoints
|
||||||
registry.addMapping("/oauth/**")
|
// registry.addMapping("/oauth/**")
|
||||||
.allowedOriginPatterns("*")
|
// .allowedOriginPatterns("*")
|
||||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||||
.allowedHeaders("*")
|
// .allowedHeaders("*")
|
||||||
.allowCredentials(true);
|
// .allowCredentials(true);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
|
|
@ -104,10 +104,13 @@ public class SecurityConfig {
|
||||||
CorsConfiguration configuration = new CorsConfiguration();
|
CorsConfiguration configuration = new CorsConfiguration();
|
||||||
configuration.setAllowedOriginPatterns(List.of("http://localhost:*"));
|
configuration.setAllowedOriginPatterns(List.of("http://localhost:*"));
|
||||||
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||||
configuration.setAllowedHeaders(Arrays.asList("*"));
|
configuration.setAllowedHeaders(List.of("*"));
|
||||||
configuration.setAllowCredentials(true);
|
configuration.setAllowCredentials(true);
|
||||||
configuration.setMaxAge(3600L);
|
configuration.setMaxAge(3600L);
|
||||||
|
|
||||||
|
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
|
||||||
|
|
||||||
|
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
source.registerCorsConfiguration("/**", configuration);
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
return source;
|
return source;
|
||||||
|
|
@ -131,6 +134,9 @@ public class SecurityConfig {
|
||||||
configuration.setAllowCredentials(true);
|
configuration.setAllowCredentials(true);
|
||||||
configuration.setMaxAge(3600L);
|
configuration.setMaxAge(3600L);
|
||||||
|
|
||||||
|
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
|
||||||
|
|
||||||
|
|
||||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||||
source.registerCorsConfiguration("/**", configuration);
|
source.registerCorsConfiguration("/**", configuration);
|
||||||
return source;
|
return source;
|
||||||
|
|
|
||||||
|
|
@ -37,20 +37,20 @@ public class BulkOperationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping({"/status/", "/status"})
|
@GetMapping({"/status/", "/status"})
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<List<BulkOperationDTO>> getBulkStatus() {
|
public ResponseEntity<List<BulkOperationDTO>> getBulkStatus() {
|
||||||
return ResponseEntity.ok(bulkOperationService.getStatus());
|
return ResponseEntity.ok(bulkOperationService.getStatus());
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping({"/upload/{type}", "/upload/{type}/"})
|
@PostMapping({"/upload/{type}", "/upload/{type}/"})
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<Void> uploadFile(@PathVariable BulkFileType type, @BodyParam("file") MultipartFile file) {
|
public ResponseEntity<Void> uploadFile(@PathVariable BulkFileType type, @BodyParam("file") MultipartFile file) {
|
||||||
bulkOperationService.processFileImport(type, file);
|
bulkOperationService.processFileImport(type, file);
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping({"/templates/{type}", "/templates/{type}/"})
|
@GetMapping({"/templates/{type}", "/templates/{type}/"})
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<InputStreamResource> generateTemplate(@PathVariable BulkFileType type) {
|
public ResponseEntity<InputStreamResource> generateTemplate(@PathVariable BulkFileType type) {
|
||||||
HttpHeaders headers = new HttpHeaders();
|
HttpHeaders headers = new HttpHeaders();
|
||||||
headers.add("Content-Disposition", "attachment; filename=lcc_template_" + type.name().toLowerCase() + ".xlsx");
|
headers.add("Content-Disposition", "attachment; filename=lcc_template_" + type.name().toLowerCase() + ".xlsx");
|
||||||
|
|
@ -64,7 +64,7 @@ public class BulkOperationController {
|
||||||
|
|
||||||
|
|
||||||
@GetMapping({"/download/{type}", "/download/{type}/"})
|
@GetMapping({"/download/{type}", "/download/{type}/"})
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type) {
|
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type) {
|
||||||
bulkOperationService.processFileExport(type);
|
bulkOperationService.processFileExport(type);
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
|
|
@ -72,7 +72,7 @@ public class BulkOperationController {
|
||||||
|
|
||||||
|
|
||||||
@GetMapping({"/download/{type}/{validity_period_id}", "/download/{type}/{validity_period_id}/"})
|
@GetMapping({"/download/{type}/{validity_period_id}", "/download/{type}/{validity_period_id}/"})
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type, @PathVariable("validity_period_id") Integer validityPeriodId) {
|
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type, @PathVariable("validity_period_id") Integer validityPeriodId) {
|
||||||
bulkOperationService.processFileExport(type, validityPeriodId);
|
bulkOperationService.processFileExport(type, validityPeriodId);
|
||||||
return ResponseEntity.ok().build();
|
return ResponseEntity.ok().build();
|
||||||
|
|
@ -80,7 +80,7 @@ public class BulkOperationController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping({"/file/{processId}", "/file/{processId}/"})
|
@GetMapping({"/file/{processId}", "/file/{processId}/"})
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<InputStreamResource> download(@PathVariable("processId") Integer id) {
|
public ResponseEntity<InputStreamResource> download(@PathVariable("processId") Integer id) {
|
||||||
var op = bulkOperationService.getBulkOperation(id);
|
var op = bulkOperationService.getBulkOperation(id);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ public class MaterialController {
|
||||||
* X-Total-Count (total elements), X-Page-Count (total pages), and X-Current-Page (current page).
|
* X-Total-Count (total elements), X-Page-Count (total pages), and X-Current-Page (current page).
|
||||||
*/
|
*/
|
||||||
@GetMapping("/")
|
@GetMapping("/")
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<List<MaterialDTO>> listMaterials(
|
public ResponseEntity<List<MaterialDTO>> listMaterials(
|
||||||
@RequestParam(defaultValue = "true") String excludeDeprecated,
|
@RequestParam(defaultValue = "true") String excludeDeprecated,
|
||||||
@RequestParam(defaultValue = "20") @Min(1) int limit,
|
@RequestParam(defaultValue = "20") @Min(1) int limit,
|
||||||
|
|
@ -61,7 +61,7 @@ public class MaterialController {
|
||||||
* @throws RuntimeException if the material with the given ID is not found.
|
* @throws RuntimeException if the material with the given ID is not found.
|
||||||
*/
|
*/
|
||||||
@GetMapping("/{id}")
|
@GetMapping("/{id}")
|
||||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING')")
|
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||||
public ResponseEntity<MaterialDetailDTO> getMaterialDetails(@PathVariable Integer id) {
|
public ResponseEntity<MaterialDetailDTO> getMaterialDetails(@PathVariable Integer id) {
|
||||||
return ResponseEntity.ok(materialService.getMaterial(id));
|
return ResponseEntity.ok(materialService.getMaterial(id));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,15 @@
|
||||||
package de.avatic.lcc.dto.generic;
|
package de.avatic.lcc.dto.generic;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
|
||||||
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a geographical location with latitude and longitude.
|
* Represents a geographical location with latitude and longitude.
|
||||||
* This immutable DTO (Data Transfer Object) is used to transfer location data across system layers.
|
* This immutable DTO (Data Transfer Object) is used to transfer location data across system layers.
|
||||||
*/
|
*
|
||||||
public class LocationDTO {
|
* @param latitude The latitude of the location.
|
||||||
|
|
||||||
/**
|
|
||||||
* The latitude of the location.
|
|
||||||
* Positive values indicate north and negative values indicate south.
|
* Positive values indicate north and negative values indicate south.
|
||||||
*/
|
* @param longitude The longitude of the location.
|
||||||
private final double latitude;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The longitude of the location.
|
|
||||||
* Positive values indicate east and negative values indicate west.
|
* Positive values indicate east and negative values indicate west.
|
||||||
*/
|
*/
|
||||||
private final double longitude;
|
public record LocationDTO(double latitude, double longitude) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new {@code LocationDTO} with the specified latitude and longitude.
|
* Constructs a new {@code LocationDTO} with the specified latitude and longitude.
|
||||||
|
|
@ -28,9 +17,7 @@ public class LocationDTO {
|
||||||
* @param latitude the latitude of the location, where north is positive and south is negative
|
* @param latitude the latitude of the location, where north is positive and south is negative
|
||||||
* @param longitude the longitude of the location, where east is positive and west is negative
|
* @param longitude the longitude of the location, where east is positive and west is negative
|
||||||
*/
|
*/
|
||||||
public LocationDTO(double latitude, double longitude) {
|
public LocationDTO {
|
||||||
this.latitude = latitude;
|
|
||||||
this.longitude = longitude;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -46,7 +33,8 @@ public class LocationDTO {
|
||||||
*
|
*
|
||||||
* @return the latitude, where positive values indicate north and negative values indicate south
|
* @return the latitude, where positive values indicate north and negative values indicate south
|
||||||
*/
|
*/
|
||||||
public double getLatitude() {
|
@Override
|
||||||
|
public double latitude() {
|
||||||
return latitude;
|
return latitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -55,7 +43,8 @@ public class LocationDTO {
|
||||||
*
|
*
|
||||||
* @return the longitude, where positive values indicate east and negative values indicate west
|
* @return the longitude, where positive values indicate east and negative values indicate west
|
||||||
*/
|
*/
|
||||||
public double getLongitude() {
|
@Override
|
||||||
|
public double longitude() {
|
||||||
return longitude;
|
return longitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -68,11 +57,6 @@ public class LocationDTO {
|
||||||
Double.compare(that.longitude, longitude) == 0;
|
Double.compare(that.longitude, longitude) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(latitude, longitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "LocationDTO{" +
|
return "LocationDTO{" +
|
||||||
|
|
|
||||||
|
|
@ -160,18 +160,12 @@ public class BulkOperationRepository {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class BulkOperationRowMapper implements RowMapper<BulkOperation> {
|
private record BulkOperationRowMapper(boolean skipFile) implements RowMapper<BulkOperation> {
|
||||||
|
|
||||||
private final boolean skipFile;
|
|
||||||
|
|
||||||
BulkOperationRowMapper() {
|
BulkOperationRowMapper() {
|
||||||
this(false);
|
this(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
BulkOperationRowMapper(boolean skipFile) {
|
|
||||||
this.skipFile = skipFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BulkOperation mapRow(ResultSet rs, int rowNum) throws SQLException {
|
public BulkOperation mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||||
BulkOperation operation = new BulkOperation();
|
BulkOperation operation = new BulkOperation();
|
||||||
|
|
|
||||||
|
|
@ -30,15 +30,18 @@ import java.util.Map;
|
||||||
@Repository
|
@Repository
|
||||||
public class DumpRepository {
|
public class DumpRepository {
|
||||||
|
|
||||||
@Autowired
|
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
|
||||||
|
|
||||||
@Autowired
|
private final JdbcTemplate jdbcTemplate;
|
||||||
private JdbcTemplate jdbcTemplate;
|
private final PremiseRepository premiseRepository;
|
||||||
@Autowired
|
private final PremiseTransformer premiseTransformer;
|
||||||
private PremiseRepository premiseRepository;
|
|
||||||
@Autowired
|
public DumpRepository(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbcTemplate, PremiseRepository premiseRepository, PremiseTransformer premiseTransformer) {
|
||||||
private PremiseTransformer premiseTransformer;
|
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
|
||||||
|
this.jdbcTemplate = jdbcTemplate;
|
||||||
|
this.premiseRepository = premiseRepository;
|
||||||
|
this.premiseTransformer = premiseTransformer;
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public CalculationJobDumpDTO getDump(Integer id) {
|
public CalculationJobDumpDTO getDump(Integer id) {
|
||||||
|
|
|
||||||
|
|
@ -122,7 +122,7 @@ public class SysErrorRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Count total elements
|
// Count total elements
|
||||||
String countSql = "SELECT COUNT(*) FROM sys_error e" + whereClause.toString();
|
String countSql = "SELECT COUNT(*) FROM sys_error e" + whereClause;
|
||||||
Integer totalElements = namedParameterJdbcTemplate.queryForObject(countSql, parameters, Integer.class);
|
Integer totalElements = namedParameterJdbcTemplate.queryForObject(countSql, parameters, Integer.class);
|
||||||
|
|
||||||
// Build main query with pagination
|
// Build main query with pagination
|
||||||
|
|
@ -130,7 +130,7 @@ public class SysErrorRepository {
|
||||||
SELECT e.id, e.user_id, e.title, e.code, e.message, e.pinia,
|
SELECT e.id, e.user_id, e.title, e.code, e.message, e.pinia,
|
||||||
e.calculation_job_id, e.bulk_operation_id, e.type, e.created_at
|
e.calculation_job_id, e.bulk_operation_id, e.type, e.created_at
|
||||||
FROM sys_error e
|
FROM sys_error e
|
||||||
""" + whereClause.toString() + """
|
""" + whereClause + """
|
||||||
ORDER BY e.created_at DESC
|
ORDER BY e.created_at DESC
|
||||||
LIMIT :limit OFFSET :offset
|
LIMIT :limit OFFSET :offset
|
||||||
""";
|
""";
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import java.util.function.Function;
|
||||||
*/
|
*/
|
||||||
public class SearchQueryResult<T> {
|
public class SearchQueryResult<T> {
|
||||||
|
|
||||||
private List<T> result;
|
private final List<T> result;
|
||||||
|
|
||||||
private final Integer page, totalPages, totalElements, elementsPerPage;
|
private final Integer page, totalPages, totalElements, elementsPerPage;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -135,6 +135,28 @@ public class DestinationRepository {
|
||||||
return Optional.of(userId.getFirst());
|
return Optional.of(userId.getFirst());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public Map<Integer, Integer> getOwnerIdsByIds(List<Integer> ids) {
|
||||||
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
String placeholders = String.join(",", Collections.nCopies(ids.size(), "?"));
|
||||||
|
String query = String.format("""
|
||||||
|
SELECT pd.id AS pd_id, p.user_id AS user_id
|
||||||
|
FROM premise_destination pd
|
||||||
|
JOIN premise p ON pd.premise_id = p.id
|
||||||
|
WHERE pd.id IN (%s)""", placeholders);
|
||||||
|
|
||||||
|
return jdbcTemplate.query(query, rs -> {
|
||||||
|
Map<Integer, Integer> result = new HashMap<>();
|
||||||
|
while (rs.next()) {
|
||||||
|
result.put(rs.getInt("pd_id"), rs.getInt("user_id"));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}, ids.toArray());
|
||||||
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public List<Destination> getByPremiseIdsAndNodeId(List<Integer> premiseId, Integer nodeId, Integer userId) {
|
public List<Destination> getByPremiseIdsAndNodeId(List<Integer> premiseId, Integer nodeId, Integer userId) {
|
||||||
String placeholder = String.join(",", Collections.nCopies(premiseId.size(), "?"));
|
String placeholder = String.join(",", Collections.nCopies(premiseId.size(), "?"));
|
||||||
|
|
@ -226,6 +248,29 @@ public class DestinationRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
|
public void checkOwner(List<Integer> ids, Integer userId) {
|
||||||
|
if (ids == null || ids.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, Integer> ownerMap = getOwnerIdsByIds(ids);
|
||||||
|
List<String> violations = new ArrayList<>();
|
||||||
|
|
||||||
|
for (Integer id : ids) {
|
||||||
|
Integer ownerId = ownerMap.get(id);
|
||||||
|
|
||||||
|
if (ownerId == null || !ownerId.equals(userId)) {
|
||||||
|
violations.add("id " + id + " (owner: " + ownerId + " user: " + userId + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!violations.isEmpty()) {
|
||||||
|
throw new ForbiddenException("Access violation. Accessing destinations: " +
|
||||||
|
String.join(", ", violations));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class DestinationMapper implements RowMapper<Destination> {
|
private static class DestinationMapper implements RowMapper<Destination> {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -288,13 +288,7 @@ public class ContainerRateRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static class ContainerRateMapper implements RowMapper<ContainerRate> {
|
private record ContainerRateMapper(boolean fetchCountryIds) implements RowMapper<ContainerRate> {
|
||||||
|
|
||||||
private final boolean fetchCountryIds;
|
|
||||||
|
|
||||||
public ContainerRateMapper(boolean fetchCountryIds) {
|
|
||||||
this.fetchCountryIds = fetchCountryIds;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ContainerRateMapper() {
|
public ContainerRateMapper() {
|
||||||
this(false);
|
this(false);
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ import de.avatic.lcc.repositories.users.UserNodeRepository;
|
||||||
import de.avatic.lcc.service.calculation.RoutingService;
|
import de.avatic.lcc.service.calculation.RoutingService;
|
||||||
import de.avatic.lcc.service.transformer.premise.DestinationTransformer;
|
import de.avatic.lcc.service.transformer.premise.DestinationTransformer;
|
||||||
import de.avatic.lcc.service.users.AuthorizationService;
|
import de.avatic.lcc.service.users.AuthorizationService;
|
||||||
import de.avatic.lcc.util.exception.base.ForbiddenException;
|
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
|
@ -34,15 +33,12 @@ public class DestinationService {
|
||||||
private final RouteSectionRepository routeSectionRepository;
|
private final RouteSectionRepository routeSectionRepository;
|
||||||
private final RouteNodeRepository routeNodeRepository;
|
private final RouteNodeRepository routeNodeRepository;
|
||||||
private final RoutingService routingService;
|
private final RoutingService routingService;
|
||||||
;
|
|
||||||
private final NodeRepository nodeRepository;
|
private final NodeRepository nodeRepository;
|
||||||
private final PremiseRepository premiseRepository;
|
private final PremiseRepository premiseRepository;
|
||||||
private final UserNodeRepository userNodeRepository;
|
private final UserNodeRepository userNodeRepository;
|
||||||
private final PropertyRepository propertyRepository;
|
|
||||||
private final PropertyService propertyService;
|
|
||||||
private final AuthorizationService authorizationService;
|
private final AuthorizationService authorizationService;
|
||||||
|
|
||||||
public DestinationService(DestinationRepository destinationRepository, DestinationTransformer destinationTransformer, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, RoutingService routingService, NodeRepository nodeRepository, PremiseRepository premiseRepository, UserNodeRepository userNodeRepository, PropertyRepository propertyRepository, PropertyService propertyService, AuthorizationService authorizationService) {
|
public DestinationService(DestinationRepository destinationRepository, DestinationTransformer destinationTransformer, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, RoutingService routingService, NodeRepository nodeRepository, PremiseRepository premiseRepository, UserNodeRepository userNodeRepository, AuthorizationService authorizationService) {
|
||||||
this.destinationRepository = destinationRepository;
|
this.destinationRepository = destinationRepository;
|
||||||
this.destinationTransformer = destinationTransformer;
|
this.destinationTransformer = destinationTransformer;
|
||||||
this.routeRepository = routeRepository;
|
this.routeRepository = routeRepository;
|
||||||
|
|
@ -52,16 +48,16 @@ public class DestinationService {
|
||||||
this.nodeRepository = nodeRepository;
|
this.nodeRepository = nodeRepository;
|
||||||
this.premiseRepository = premiseRepository;
|
this.premiseRepository = premiseRepository;
|
||||||
this.userNodeRepository = userNodeRepository;
|
this.userNodeRepository = userNodeRepository;
|
||||||
this.propertyRepository = propertyRepository;
|
|
||||||
this.propertyService = propertyService;
|
|
||||||
this.authorizationService = authorizationService;
|
this.authorizationService = authorizationService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public Map<Integer, List<DestinationDTO>> setDestination(DestinationSetDTO dto) {
|
public Map<Integer, List<DestinationDTO>> setDestination(DestinationSetDTO dto) {
|
||||||
//TODO fix user authorization
|
var admin = authorizationService.isSuper();
|
||||||
var userId = 1;
|
Integer userId = authorizationService.getUserId();
|
||||||
//dto.getPremiseId().forEach(id -> destinationRepository.checkOwner(id, userId));
|
|
||||||
|
if (!admin)
|
||||||
|
destinationRepository.checkOwner(dto.getPremiseId(), userId);
|
||||||
|
|
||||||
deleteAllDestinationsByPremiseId(dto.getPremiseId(), false);
|
deleteAllDestinationsByPremiseId(dto.getPremiseId(), false);
|
||||||
|
|
||||||
|
|
@ -80,7 +76,6 @@ public class DestinationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private List<Destination> createDestination(List<Premise> premisesToProcess, Integer destinationNodeId, Integer annualAmount, Number repackingCost, Number disposalCost, Number handlingCost, Map<RouteIds, List<RouteInformation>> routes) {
|
private List<Destination> createDestination(List<Premise> premisesToProcess, Integer destinationNodeId, Integer annualAmount, Number repackingCost, Number disposalCost, Number handlingCost, Map<RouteIds, List<RouteInformation>> routes) {
|
||||||
|
|
||||||
Node destinationNode = nodeRepository.getById(destinationNodeId).orElseThrow();
|
Node destinationNode = nodeRepository.getById(destinationNodeId).orElseThrow();
|
||||||
|
|
@ -141,17 +136,22 @@ public class DestinationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public DestinationDTO getDestination(Integer id) {
|
public DestinationDTO getDestination(Integer id) {
|
||||||
//todo check authorization
|
var admin = authorizationService.isSuper();
|
||||||
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
|
destinationRepository.checkOwner(id, userId);
|
||||||
|
|
||||||
return destinationTransformer.toDestinationDTO(destinationRepository.getById(id).orElseThrow());
|
return destinationTransformer.toDestinationDTO(destinationRepository.getById(id).orElseThrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void updateDestination(Integer id, DestinationUpdateDTO destinationUpdateDTO) {
|
public void updateDestination(Integer id, DestinationUpdateDTO destinationUpdateDTO) {
|
||||||
//todo check authorization
|
var admin = authorizationService.isSuper();
|
||||||
Integer userId = authorizationService.getUserId();
|
Integer userId = authorizationService.getUserId();
|
||||||
destinationRepository.checkOwner(id, userId);
|
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
|
destinationRepository.checkOwner(id, userId);
|
||||||
|
|
||||||
var selectedRouteId = destinationUpdateDTO.getRouteSelectedId();
|
var selectedRouteId = destinationUpdateDTO.getRouteSelectedId();
|
||||||
|
|
||||||
|
|
@ -159,7 +159,6 @@ public class DestinationService {
|
||||||
routeRepository.updateSelectedByDestinationId(id, selectedRouteId);
|
routeRepository.updateSelectedByDestinationId(id, selectedRouteId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
destinationRepository.update(id,
|
destinationRepository.update(id,
|
||||||
destinationUpdateDTO.getAnnualAmount(),
|
destinationUpdateDTO.getAnnualAmount(),
|
||||||
destinationUpdateDTO.getRepackingCost() == null ? null : BigDecimal.valueOf(destinationUpdateDTO.getRepackingCost().doubleValue()),
|
destinationUpdateDTO.getRepackingCost() == null ? null : BigDecimal.valueOf(destinationUpdateDTO.getRepackingCost().doubleValue()),
|
||||||
|
|
@ -177,21 +176,21 @@ public class DestinationService {
|
||||||
Map<Integer, Node> nodes = new HashMap<>();
|
Map<Integer, Node> nodes = new HashMap<>();
|
||||||
Map<Integer, Node> userNodes = new HashMap<>();
|
Map<Integer, Node> userNodes = new HashMap<>();
|
||||||
|
|
||||||
for(var premise : premisses) {
|
for (var premise : premisses) {
|
||||||
for(var destinationId : destinationIds) {
|
for (var destinationId : destinationIds) {
|
||||||
boolean isUserSupplierNode = (premise.getSupplierNodeId() == null);
|
boolean isUserSupplierNode = (premise.getSupplierNodeId() == null);
|
||||||
var ids = new RouteIds(isUserSupplierNode ? premise.getUserSupplierNodeId() : premise.getSupplierNodeId(), destinationId, isUserSupplierNode);
|
var ids = new RouteIds(isUserSupplierNode ? premise.getUserSupplierNodeId() : premise.getSupplierNodeId(), destinationId, isUserSupplierNode);
|
||||||
if(routes.containsKey(ids)) continue;
|
if (routes.containsKey(ids)) continue;
|
||||||
|
|
||||||
if(!nodes.containsKey(destinationId)) {
|
if (!nodes.containsKey(destinationId)) {
|
||||||
nodes.put(destinationId, nodeRepository.getById(destinationId).orElseThrow());
|
nodes.put(destinationId, nodeRepository.getById(destinationId).orElseThrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isUserSupplierNode && !nodes.containsKey(premise.getSupplierNodeId())) {
|
if (!isUserSupplierNode && !nodes.containsKey(premise.getSupplierNodeId())) {
|
||||||
nodes.put(premise.getSupplierNodeId(), nodeRepository.getById(premise.getSupplierNodeId()).orElseThrow());
|
nodes.put(premise.getSupplierNodeId(), nodeRepository.getById(premise.getSupplierNodeId()).orElseThrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isUserSupplierNode && !userNodes.containsKey(premise.getUserSupplierNodeId())) {
|
if (isUserSupplierNode && !userNodes.containsKey(premise.getUserSupplierNodeId())) {
|
||||||
userNodes.put(premise.getUserSupplierNodeId(), userNodeRepository.getById(premise.getUserSupplierNodeId()).orElseThrow());
|
userNodes.put(premise.getUserSupplierNodeId(), userNodeRepository.getById(premise.getUserSupplierNodeId()).orElseThrow());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -205,7 +204,6 @@ public class DestinationService {
|
||||||
@Transactional
|
@Transactional
|
||||||
public void saveRoute(List<RouteInformation> routeObjs, Integer destinationId) {
|
public void saveRoute(List<RouteInformation> routeObjs, Integer destinationId) {
|
||||||
|
|
||||||
|
|
||||||
for (var routeObj : routeObjs) {
|
for (var routeObj : routeObjs) {
|
||||||
boolean first = true;
|
boolean first = true;
|
||||||
Integer fromNodeId = null;
|
Integer fromNodeId = null;
|
||||||
|
|
@ -238,44 +236,12 @@ public class DestinationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private record RouteIds(Integer fromNodeId, Integer toNodeId, boolean isUserSupplierNode) {}
|
|
||||||
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void findRouteAndSave(Integer destinationId, Node destination, Node supplier, boolean isUserSupplierNode) {
|
public void findRouteAndSave(Integer destinationId, Node destination, Node supplier, boolean isUserSupplierNode) {
|
||||||
|
|
||||||
var routeObjs = routingService.findRoutes(destination, supplier, isUserSupplierNode);
|
var routeObjs = routingService.findRoutes(destination, supplier, isUserSupplierNode);
|
||||||
|
|
||||||
for (var routeObj : routeObjs) {
|
saveRoute(routeObjs, destinationId);
|
||||||
boolean first = true;
|
|
||||||
Integer fromNodeId = null;
|
|
||||||
|
|
||||||
var premiseRoute = routeObj.getRoute();
|
|
||||||
premiseRoute.setDestinationId(destinationId);
|
|
||||||
int routeId = routeRepository.insert(premiseRoute);
|
|
||||||
|
|
||||||
|
|
||||||
for (RouteSectionInformation section : routeObj.getSections()) {
|
|
||||||
|
|
||||||
if (first) {
|
|
||||||
fromNodeId = routeNodeRepository.insert(section.getFromNode());
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
var toNode = section.getToNode();
|
|
||||||
Integer toNodeId = routeNodeRepository.insert(toNode);
|
|
||||||
|
|
||||||
var premiseRouteSection = section.getSection();
|
|
||||||
|
|
||||||
premiseRouteSection.setRouteId(routeId);
|
|
||||||
premiseRouteSection.setFromRouteNodeId(fromNodeId);
|
|
||||||
premiseRouteSection.setToRouteNodeId(toNodeId);
|
|
||||||
|
|
||||||
routeSectionRepository.insert(premiseRouteSection);
|
|
||||||
|
|
||||||
fromNodeId = toNodeId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
@ -289,14 +255,14 @@ public class DestinationService {
|
||||||
destinations.forEach(destination -> deleteDestinationById(destination.getId(), deleteRoutesOnly));
|
destinations.forEach(destination -> deleteDestinationById(destination.getId(), deleteRoutesOnly));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void deleteDestinationById(Integer id, boolean deleteRoutesOnly) {
|
public void deleteDestinationById(Integer id, boolean deleteRoutesOnly) {
|
||||||
//todo check authorization
|
var admin = authorizationService.isSuper();
|
||||||
Integer userId = authorizationService.getUserId();
|
Integer userId = authorizationService.getUserId();
|
||||||
Optional<Integer> ownerId = destinationRepository.getOwnerIdById(id);
|
|
||||||
|
|
||||||
if (ownerId.isPresent() && ownerId.get().equals(userId)) {
|
if (!admin)
|
||||||
|
destinationRepository.checkOwner(id, userId);
|
||||||
|
|
||||||
List<Route> routes = routeRepository.getByDestinationId(id);
|
List<Route> routes = routeRepository.getByDestinationId(id);
|
||||||
|
|
||||||
for (var route : routes) {
|
for (var route : routes) {
|
||||||
|
|
@ -310,11 +276,6 @@ public class DestinationService {
|
||||||
if (!deleteRoutesOnly)
|
if (!deleteRoutesOnly)
|
||||||
destinationRepository.deleteById(id);
|
destinationRepository.deleteById(id);
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ForbiddenException("Not authorized to delete destination with id " + id);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
@ -349,5 +310,8 @@ public class DestinationService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private record RouteIds(Integer fromNodeId, Integer toNodeId, boolean isUserSupplierNode) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,10 @@ public class PremisesService {
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public List<PremiseDetailDTO> getPremises(List<Integer> premiseIds) {
|
public List<PremiseDetailDTO> getPremises(List<Integer> premiseIds) {
|
||||||
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(premiseIds, userId);
|
premiseRepository.checkOwner(premiseIds, userId);
|
||||||
|
|
||||||
return premiseRepository.getPremisesById(premiseIds).stream().filter(p -> p.getState().equals(PremiseState.DRAFT)).map(premiseTransformer::toPremiseDetailDTO).toList();
|
return premiseRepository.getPremisesById(premiseIds).stream().filter(p -> p.getState().equals(PremiseState.DRAFT)).map(premiseTransformer::toPremiseDetailDTO).toList();
|
||||||
|
|
@ -98,12 +101,14 @@ public class PremisesService {
|
||||||
|
|
||||||
|
|
||||||
public void startCalculation(List<Integer> premises) {
|
public void startCalculation(List<Integer> premises) {
|
||||||
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(premises, userId);
|
premiseRepository.checkOwner(premises, userId);
|
||||||
|
|
||||||
var validSetId = propertySetRepository.getValidSetId();
|
var validSetId = propertySetRepository.getValidSetId();
|
||||||
var validPeriodId = validityPeriodRepository.getValidPeriodId().orElseThrow(() -> new InternalErrorException("no valid period found that is VALID"));
|
var validPeriodId = validityPeriodRepository.getValidPeriodId().orElseThrow(() -> new InternalErrorException("no set of transport rates found that is VALID"));
|
||||||
|
|
||||||
premises.forEach(premiseId -> preCalculationCheckService.doPrecheck(premiseId, validSetId, validPeriodId));
|
premises.forEach(premiseId -> preCalculationCheckService.doPrecheck(premiseId, validSetId, validPeriodId));
|
||||||
|
|
||||||
|
|
@ -183,11 +188,12 @@ public class PremisesService {
|
||||||
return calculationStatusService.getCalculationStatus(processId);
|
return calculationStatusService.getCalculationStatus(processId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
|
||||||
public void updatePackaging(PackagingUpdateDTO packagingDTO) {
|
|
||||||
|
|
||||||
//TODO check values. and return errors if needed
|
public void updatePackaging(PackagingUpdateDTO packagingDTO) {
|
||||||
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(packagingDTO.getPremiseIds(), userId);
|
premiseRepository.checkOwner(packagingDTO.getPremiseIds(), userId);
|
||||||
|
|
||||||
var dimensions = packagingDTO.getDimensions() == null ? null : dimensionTransformer.toDimensionEntity(packagingDTO.getDimensions());
|
var dimensions = packagingDTO.getDimensions() == null ? null : dimensionTransformer.toDimensionEntity(packagingDTO.getDimensions());
|
||||||
|
|
@ -197,8 +203,10 @@ public class PremisesService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updateMaterial(MaterialUpdateDTO materialUpdateDTO) {
|
public void updateMaterial(MaterialUpdateDTO materialUpdateDTO) {
|
||||||
//TODO check values. and return errors if needed
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(materialUpdateDTO.getPremiseIds(), userId);
|
premiseRepository.checkOwner(materialUpdateDTO.getPremiseIds(), userId);
|
||||||
|
|
||||||
var tariffRate = materialUpdateDTO.getTariffRate() == null ? null : BigDecimal.valueOf(materialUpdateDTO.getTariffRate().doubleValue());
|
var tariffRate = materialUpdateDTO.getTariffRate() == null ? null : BigDecimal.valueOf(materialUpdateDTO.getTariffRate().doubleValue());
|
||||||
|
|
@ -207,8 +215,10 @@ public class PremisesService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void updatePrice(PriceUpdateDTO priceUpdateDTO) {
|
public void updatePrice(PriceUpdateDTO priceUpdateDTO) {
|
||||||
//TODO check values. and return errors if needed
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(priceUpdateDTO.getPremiseIds(), userId);
|
premiseRepository.checkOwner(priceUpdateDTO.getPremiseIds(), userId);
|
||||||
|
|
||||||
var price = priceUpdateDTO.getPrice() == null ? null : BigDecimal.valueOf(priceUpdateDTO.getPrice().doubleValue());
|
var price = priceUpdateDTO.getPrice() == null ? null : BigDecimal.valueOf(priceUpdateDTO.getPrice().doubleValue());
|
||||||
|
|
@ -219,9 +229,13 @@ public class PremisesService {
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void delete(List<Integer> premiseIds) {
|
public void delete(List<Integer> premiseIds) {
|
||||||
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(premiseIds, userId);
|
premiseRepository.checkOwner(premiseIds, userId);
|
||||||
|
|
||||||
|
|
||||||
// only delete drafts.
|
// only delete drafts.
|
||||||
var toBeDeleted = premiseRepository.getPremisesById(premiseIds).stream().filter(p -> p.getState().equals(PremiseState.DRAFT)).map(Premise::getId).toList();
|
var toBeDeleted = premiseRepository.getPremisesById(premiseIds).stream().filter(p -> p.getState().equals(PremiseState.DRAFT)).map(Premise::getId).toList();
|
||||||
|
|
||||||
|
|
@ -232,10 +246,15 @@ public class PremisesService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public void archive(List<Integer> premiseIds) {
|
public void archive(List<Integer> premiseIds) {
|
||||||
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(premiseIds, userId);
|
premiseRepository.checkOwner(premiseIds, userId);
|
||||||
|
|
||||||
|
|
||||||
// only archive completed.
|
// only archive completed.
|
||||||
var premisses = premiseRepository.getPremisesById(premiseIds);
|
var premisses = premiseRepository.getPremisesById(premiseIds);
|
||||||
premiseRepository.setStatus(premisses.stream().filter(p -> p.getState().equals(PremiseState.COMPLETED)).map(Premise::getId).toList(), PremiseState.ARCHIVED);
|
premiseRepository.setStatus(premisses.stream().filter(p -> p.getState().equals(PremiseState.COMPLETED)).map(Premise::getId).toList(), PremiseState.ARCHIVED);
|
||||||
|
|
@ -262,9 +281,14 @@ public class PremisesService {
|
||||||
return resolveDTO;
|
return resolveDTO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Transactional
|
||||||
public List<Integer> duplicate(List<Integer> premissIds) {
|
public List<Integer> duplicate(List<Integer> premissIds) {
|
||||||
|
var admin = authorizationService.isSuper();
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
if (!admin)
|
||||||
premiseRepository.checkOwner(premissIds, userId);
|
premiseRepository.checkOwner(premissIds, userId);
|
||||||
|
|
||||||
var newIds = new ArrayList<Integer>();
|
var newIds = new ArrayList<Integer>();
|
||||||
|
|
||||||
premissIds.forEach(id -> {
|
premissIds.forEach(id -> {
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ public class PropertyValidationService {
|
||||||
public void evaluate(String value) {
|
public void evaluate(String value) {
|
||||||
if (operator == CompareOperator.ENUM) {
|
if (operator == CompareOperator.ENUM) {
|
||||||
if (!((List<String>) this.value).contains(value)) {
|
if (!((List<String>) this.value).contains(value)) {
|
||||||
throw new PropertyValidationException(propertyId, operator.getIdentifier(), ((List<String>) this.value).toString(), value);
|
throw new PropertyValidationException(propertyId, operator.getIdentifier(), this.value.toString(), value);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -53,8 +53,8 @@ public class UserNodeService {
|
||||||
|
|
||||||
node.setName(dto.getName());
|
node.setName(dto.getName());
|
||||||
node.setAddress(dto.getAddress());
|
node.setAddress(dto.getAddress());
|
||||||
node.setGeoLng(BigDecimal.valueOf(dto.getLocation().getLongitude()));
|
node.setGeoLng(BigDecimal.valueOf(dto.getLocation().longitude()));
|
||||||
node.setGeoLat(BigDecimal.valueOf(dto.getLocation().getLatitude()));
|
node.setGeoLat(BigDecimal.valueOf(dto.getLocation().latitude()));
|
||||||
node.setDestination(false);
|
node.setDestination(false);
|
||||||
node.setSource(true);
|
node.setSource(true);
|
||||||
node.setIntermediate(false);
|
node.setIntermediate(false);
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,9 @@ package de.avatic.lcc.service.bulk;
|
||||||
|
|
||||||
import de.avatic.lcc.model.bulk.BulkFileTypes;
|
import de.avatic.lcc.model.bulk.BulkFileTypes;
|
||||||
import de.avatic.lcc.model.bulk.BulkOperation;
|
import de.avatic.lcc.model.bulk.BulkOperation;
|
||||||
import de.avatic.lcc.repositories.NodeRepository;
|
|
||||||
import de.avatic.lcc.service.api.BatchGeoApiService;
|
import de.avatic.lcc.service.api.BatchGeoApiService;
|
||||||
import de.avatic.lcc.service.bulk.bulkImport.*;
|
import de.avatic.lcc.service.bulk.bulkImport.*;
|
||||||
import de.avatic.lcc.service.excelMapper.*;
|
import de.avatic.lcc.service.excelMapper.*;
|
||||||
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
|
|
||||||
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
|
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
|
||||||
import org.apache.poi.ss.usermodel.Sheet;
|
import org.apache.poi.ss.usermodel.Sheet;
|
||||||
import org.apache.poi.ss.usermodel.Workbook;
|
import org.apache.poi.ss.usermodel.Workbook;
|
||||||
|
|
@ -26,8 +24,7 @@ public class BulkImportService {
|
||||||
private final MaterialExcelMapper materialExcelMapper;
|
private final MaterialExcelMapper materialExcelMapper;
|
||||||
private final PackagingExcelMapper packagingExcelMapper;
|
private final PackagingExcelMapper packagingExcelMapper;
|
||||||
private final NodeExcelMapper nodeExcelMapper;
|
private final NodeExcelMapper nodeExcelMapper;
|
||||||
private final NodeRepository nodeRepository;
|
|
||||||
private final NodeTransformer nodeTransformer;
|
|
||||||
private final NodeBulkImportService nodeBulkImportService;
|
private final NodeBulkImportService nodeBulkImportService;
|
||||||
private final PackagingBulkImportService packagingBulkImportService;
|
private final PackagingBulkImportService packagingBulkImportService;
|
||||||
private final MaterialBulkImportService materialBulkImportService;
|
private final MaterialBulkImportService materialBulkImportService;
|
||||||
|
|
@ -35,14 +32,12 @@ public class BulkImportService {
|
||||||
private final ContainerRateImportService containerRateImportService;
|
private final ContainerRateImportService containerRateImportService;
|
||||||
private final BatchGeoApiService batchGeoApiService;
|
private final BatchGeoApiService batchGeoApiService;
|
||||||
|
|
||||||
public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeRepository nodeRepository, NodeTransformer nodeTransformer, NodeBulkImportService nodeBulkImportService, PackagingBulkImportService packagingBulkImportService, MaterialBulkImportService materialBulkImportService, MatrixRateImportService matrixRateImportService, ContainerRateImportService containerRateImportService, BatchGeoApiService batchGeoApiService) {
|
public BulkImportService(MatrixRateExcelMapper matrixRateExcelMapper, ContainerRateExcelMapper containerRateExcelMapper, MaterialExcelMapper materialExcelMapper, PackagingExcelMapper packagingExcelMapper, NodeExcelMapper nodeExcelMapper, NodeBulkImportService nodeBulkImportService, PackagingBulkImportService packagingBulkImportService, MaterialBulkImportService materialBulkImportService, MatrixRateImportService matrixRateImportService, ContainerRateImportService containerRateImportService, BatchGeoApiService batchGeoApiService) {
|
||||||
this.matrixRateExcelMapper = matrixRateExcelMapper;
|
this.matrixRateExcelMapper = matrixRateExcelMapper;
|
||||||
this.containerRateExcelMapper = containerRateExcelMapper;
|
this.containerRateExcelMapper = containerRateExcelMapper;
|
||||||
this.materialExcelMapper = materialExcelMapper;
|
this.materialExcelMapper = materialExcelMapper;
|
||||||
this.packagingExcelMapper = packagingExcelMapper;
|
this.packagingExcelMapper = packagingExcelMapper;
|
||||||
this.nodeExcelMapper = nodeExcelMapper;
|
this.nodeExcelMapper = nodeExcelMapper;
|
||||||
this.nodeRepository = nodeRepository;
|
|
||||||
this.nodeTransformer = nodeTransformer;
|
|
||||||
this.nodeBulkImportService = nodeBulkImportService;
|
this.nodeBulkImportService = nodeBulkImportService;
|
||||||
this.packagingBulkImportService = packagingBulkImportService;
|
this.packagingBulkImportService = packagingBulkImportService;
|
||||||
this.materialBulkImportService = materialBulkImportService;
|
this.materialBulkImportService = materialBulkImportService;
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,9 @@ import de.avatic.lcc.repositories.rates.ValidityPeriodRepository;
|
||||||
import de.avatic.lcc.service.transformer.bulk.BulkOperationTransformer;
|
import de.avatic.lcc.service.transformer.bulk.BulkOperationTransformer;
|
||||||
import de.avatic.lcc.service.users.AuthorizationService;
|
import de.avatic.lcc.service.users.AuthorizationService;
|
||||||
import de.avatic.lcc.util.exception.badrequest.FileFormatNotSupportedException;
|
import de.avatic.lcc.util.exception.badrequest.FileFormatNotSupportedException;
|
||||||
|
import de.avatic.lcc.util.exception.base.ForbiddenException;
|
||||||
import de.avatic.lcc.util.exception.base.InternalErrorException;
|
import de.avatic.lcc.util.exception.base.InternalErrorException;
|
||||||
|
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
|
@ -39,6 +41,8 @@ public class BulkOperationService {
|
||||||
public void processFileImport(BulkFileType fileType, MultipartFile file) {
|
public void processFileImport(BulkFileType fileType, MultipartFile file) {
|
||||||
|
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
checkAuthorized(fileType);
|
||||||
|
|
||||||
|
|
||||||
String contentType = file.getContentType();
|
String contentType = file.getContentType();
|
||||||
if (!"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType) &&
|
if (!"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType) &&
|
||||||
|
|
@ -62,10 +66,23 @@ public class BulkOperationService {
|
||||||
|
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new RuntimeException(e); //TODO throw a nice exception
|
throw new ExcelValidationError("Unable to read uploaded file.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void checkAuthorized(BulkFileType fileType) {
|
||||||
|
|
||||||
|
if( switch (fileType) {
|
||||||
|
case CONTAINER_RATE, COUNTRY_MATRIX -> authorizationService.hasAnyRole("SUPER", "FREIGHT");
|
||||||
|
case MATERIAL -> authorizationService.hasAnyRole("SUPER", "MATERIAL");
|
||||||
|
case PACKAGING -> authorizationService.hasAnyRole("SUPER", "PACKAGING");
|
||||||
|
case NODE -> authorizationService.hasAnyRole("SUPER");
|
||||||
|
}) {
|
||||||
|
throw new ForbiddenException("You are not authorized to perform this operation");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void processFileExport(BulkFileType type, Integer validityPeriodId) {
|
public void processFileExport(BulkFileType type, Integer validityPeriodId) {
|
||||||
var userId = authorizationService.getUserId();
|
var userId = authorizationService.getUserId();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ public class TemplateExportService {
|
||||||
|
|
||||||
public InputStreamSource generateTemplate(BulkFileType bulkFileType) {
|
public InputStreamSource generateTemplate(BulkFileType bulkFileType) {
|
||||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||||
Workbook workbook = new XSSFWorkbook();) {
|
Workbook workbook = new XSSFWorkbook()) {
|
||||||
|
|
||||||
Sheet sheet = workbook.createSheet(BulkFileTypes.valueOf(bulkFileType.name()).getSheetName());
|
Sheet sheet = workbook.createSheet(BulkFileTypes.valueOf(bulkFileType.name()).getSheetName());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -229,7 +229,7 @@ public class ContainerCalculationService {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static enum SolutionType {
|
private enum SolutionType {
|
||||||
HORIZONTAL, VERTICAL
|
HORIZONTAL, VERTICAL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -289,15 +289,7 @@ public class ContainerCalculationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Renderer(text = "getFullDebugInfo()")
|
@Renderer(text = "getFullDebugInfo()")
|
||||||
private static class Block {
|
private record Block(PackagingDimension dimension, BlockType type) {
|
||||||
|
|
||||||
private final PackagingDimension dimension;
|
|
||||||
private final BlockType type;
|
|
||||||
|
|
||||||
public Block(PackagingDimension dimension, BlockType type) {
|
|
||||||
this.dimension = dimension;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int calculateBlockCount(int containerColumnLength) {
|
public int calculateBlockCount(int containerColumnLength) {
|
||||||
return containerColumnLength / type.getBlockColumnLength(dimension);
|
return containerColumnLength / type.getBlockColumnLength(dimension);
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ import de.avatic.lcc.model.db.rates.ValidityPeriodState;
|
||||||
import de.avatic.lcc.model.db.utils.WeightUnit;
|
import de.avatic.lcc.model.db.utils.WeightUnit;
|
||||||
import de.avatic.lcc.repositories.NodeRepository;
|
import de.avatic.lcc.repositories.NodeRepository;
|
||||||
import de.avatic.lcc.repositories.premise.*;
|
import de.avatic.lcc.repositories.premise.*;
|
||||||
|
import de.avatic.lcc.repositories.properties.PropertyRepository;
|
||||||
import de.avatic.lcc.repositories.properties.PropertySetRepository;
|
import de.avatic.lcc.repositories.properties.PropertySetRepository;
|
||||||
import de.avatic.lcc.repositories.rates.ContainerRateRepository;
|
import de.avatic.lcc.repositories.rates.ContainerRateRepository;
|
||||||
import de.avatic.lcc.repositories.rates.MatrixRateRepository;
|
import de.avatic.lcc.repositories.rates.MatrixRateRepository;
|
||||||
|
|
@ -25,9 +26,12 @@ import de.avatic.lcc.util.exception.internalerror.PremiseValidationError;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.temporal.TemporalUnit;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class PreCalculationCheckService {
|
public class PreCalculationCheckService {
|
||||||
|
|
@ -48,8 +52,9 @@ public class PreCalculationCheckService {
|
||||||
private final ContainerRateRepository containerRateRepository;
|
private final ContainerRateRepository containerRateRepository;
|
||||||
private final ValidityPeriodRepository validityPeriodRepository;
|
private final ValidityPeriodRepository validityPeriodRepository;
|
||||||
private final PropertySetRepository propertySetRepository;
|
private final PropertySetRepository propertySetRepository;
|
||||||
|
private final PropertyRepository propertyRepository;
|
||||||
|
|
||||||
public PreCalculationCheckService(PremiseRepository premiseRepository, CustomApiService customApiService, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository, DimensionTransformer dimensionTransformer, PropertyService propertyService, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, MatrixRateRepository matrixRateRepository, ContainerRateRepository containerRateRepository, ValidityPeriodRepository validityPeriodRepository, PropertySetRepository propertySetRepository) {
|
public PreCalculationCheckService(PremiseRepository premiseRepository, CustomApiService customApiService, DestinationRepository destinationRepository, RouteRepository routeRepository, NodeRepository nodeRepository, DimensionTransformer dimensionTransformer, PropertyService propertyService, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, MatrixRateRepository matrixRateRepository, ContainerRateRepository containerRateRepository, ValidityPeriodRepository validityPeriodRepository, PropertySetRepository propertySetRepository, PropertyRepository propertyRepository) {
|
||||||
this.premiseRepository = premiseRepository;
|
this.premiseRepository = premiseRepository;
|
||||||
this.customApiService = customApiService;
|
this.customApiService = customApiService;
|
||||||
this.destinationRepository = destinationRepository;
|
this.destinationRepository = destinationRepository;
|
||||||
|
|
@ -64,6 +69,7 @@ public class PreCalculationCheckService {
|
||||||
this.containerRateRepository = containerRateRepository;
|
this.containerRateRepository = containerRateRepository;
|
||||||
this.validityPeriodRepository = validityPeriodRepository;
|
this.validityPeriodRepository = validityPeriodRepository;
|
||||||
this.propertySetRepository = propertySetRepository;
|
this.propertySetRepository = propertySetRepository;
|
||||||
|
this.propertyRepository = propertyRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void doPrecheck(Integer premiseId, Integer setId, Integer periodId) {
|
public void doPrecheck(Integer premiseId, Integer setId, Integer periodId) {
|
||||||
|
|
@ -125,17 +131,30 @@ public class PreCalculationCheckService {
|
||||||
private void periodCheck(ValidityPeriod period, PropertySet set) {
|
private void periodCheck(ValidityPeriod period, PropertySet set) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if(set == null)
|
if(set == null)
|
||||||
throw new PremiseValidationError("There are no system properties for the given date.");
|
throw new PremiseValidationError("There are no system properties for the given date. Please contact your administrator.");
|
||||||
|
|
||||||
if(period == null)
|
if(period == null)
|
||||||
throw new PremiseValidationError("There are no rates for the given date.");
|
throw new PremiseValidationError("There are no rates for the given date. Please contact your administrator.");
|
||||||
|
|
||||||
if(ValidityPeriodState.VALID != period.getState() && ValidityPeriodState.EXPIRED != period.getState())
|
if(ValidityPeriodState.VALID != period.getState() && ValidityPeriodState.EXPIRED != period.getState())
|
||||||
throw new PremiseValidationError("There are no valid rates for the given date.");
|
throw new PremiseValidationError("There are no valid rates for the given date. Please contact your administrator.");
|
||||||
|
|
||||||
if(ValidityPeriodState.VALID != set.getState() && ValidityPeriodState.EXPIRED != period.getState())
|
if(ValidityPeriodState.VALID != set.getState() && ValidityPeriodState.EXPIRED != period.getState())
|
||||||
throw new PremiseValidationError("There are no valid system properties for the given date.");
|
throw new PremiseValidationError("There are no valid system properties for the given date. Please contact your administrator.");
|
||||||
|
|
||||||
|
//TODO: sicherstellen, dass die valid days für den zeitpunkt galten zu dem die valid period galt (wenn rückwirkend gerechnet wird)
|
||||||
|
var validDays = propertyRepository.getPropertyByMappingId(SystemPropertyMappingId.VALID_DAYS, set.getId());
|
||||||
|
var renewals = period.getRenewals();
|
||||||
|
|
||||||
|
if(validDays.isEmpty())
|
||||||
|
throw new PremiseValidationError("There are no valid days property. Please contact your administrator");
|
||||||
|
|
||||||
|
var validDaysInt = Integer.parseInt(validDays.get().getCurrentValue());
|
||||||
|
|
||||||
|
if(!period.getStartDate().plusDays((long) validDaysInt * renewals).isAfter(LocalDateTime.now()))
|
||||||
|
throw new PremiseValidationError("There are no valid rates for the given date. Please contact your administrator.");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -130,8 +130,6 @@ public class ReportTransformer {
|
||||||
return new TimePeriod(startDate, endDate);
|
return new TimePeriod(startDate, endDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
;
|
|
||||||
|
|
||||||
private WeightedTotalCosts getWeightedTotalCosts(Map<Integer, List<CalculationJobRouteSection>> sectionsMap) {
|
private WeightedTotalCosts getWeightedTotalCosts(Map<Integer, List<CalculationJobRouteSection>> sectionsMap) {
|
||||||
|
|
||||||
BigDecimal totalPreRunCost = BigDecimal.ZERO;
|
BigDecimal totalPreRunCost = BigDecimal.ZERO;
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@ import org.springframework.security.core.Authentication;
|
||||||
import org.springframework.security.core.context.SecurityContextHolder;
|
import org.springframework.security.core.context.SecurityContextHolder;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
public class AuthorizationService {
|
public class AuthorizationService {
|
||||||
|
|
||||||
|
|
@ -35,9 +37,22 @@ public class AuthorizationService {
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuper() {
|
public boolean isSuper() {
|
||||||
|
return hasRole("SUPER");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasAnyRole(String... roles) {
|
||||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
if (auth.getPrincipal() instanceof LccOidcUser user) {
|
if (auth.getPrincipal() instanceof LccOidcUser user) {
|
||||||
return user.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_SUPER"));
|
return user.getAuthorities().stream().anyMatch(authority -> Arrays.asList(roles).contains(authority.getAuthority().replace("ROLE_", "")));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ForbiddenException("No user found");
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasRole(String role) {
|
||||||
|
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
if (auth.getPrincipal() instanceof LccOidcUser user) {
|
||||||
|
return user.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_" + role.toUpperCase()));
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new ForbiddenException("No user found");
|
throw new ForbiddenException("No user found");
|
||||||
|
|
|
||||||
|
|
@ -49,8 +49,7 @@ public class UserService {
|
||||||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||||
|
|
||||||
//todo make a service. and simulate user rights in dev profile.
|
//todo make a service. and simulate user rights in dev profile.
|
||||||
if (authentication != null && authentication.getPrincipal() instanceof LccOidcUser) {
|
if (authentication != null && authentication.getPrincipal() instanceof LccOidcUser oidcUser) {
|
||||||
LccOidcUser oidcUser = (LccOidcUser) authentication.getPrincipal();
|
|
||||||
|
|
||||||
return oidcUser.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_SUPER"));
|
return oidcUser.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_SUPER"));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
src/main/resources/db/migration/V9__Groups.sql
Normal file
20
src/main/resources/db/migration/V9__Groups.sql
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('none', 'no rights');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('basic', 'Login, generate reports');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('calculation', 'Login, generate reports, do calculations');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('freight', 'Login, generate reports, edit freight rates');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('packaging', 'Login, generate reports, edit packaging data');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('material', 'Login, generate reports, edit material data');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('super',
|
||||||
|
'Login, generate reports, do calculations, edit freight rates, edit packaging data');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('service', 'Register API Tokens');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('right-management',
|
||||||
|
'Add/Remove users, groups, etc.');
|
||||||
|
|
@ -18,6 +18,8 @@ VALUES ('freight', 'Login, generate reports, edit freight rates');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('packaging', 'Login, generate reports, edit packaging data');
|
VALUES ('packaging', 'Login, generate reports, edit packaging data');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
VALUES ('material', 'Login, generate reports, edit material data');
|
||||||
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
VALUES ('super',
|
VALUES ('super',
|
||||||
'Login, generate reports, do calculations, edit freight rates, edit packaging data');
|
'Login, generate reports, do calculations, edit freight rates, edit packaging data');
|
||||||
INSERT INTO sys_group(group_name, group_description)
|
INSERT INTO sys_group(group_name, group_description)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue