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 class="bulk-operation-caption">dataset</div>
|
||||
<div class="bulk-operation-data">
|
||||
<radio-option name="export-dataset" value="NODE" v-model="exportDataset">nodes</radio-option>
|
||||
<radio-option name="export-dataset" value="COUNTRY_MATRIX" v-model="exportDataset">kilometer rates
|
||||
<radio-option v-if="canModify('nodes')" name="export-dataset" value="NODE" v-model="exportDataset">nodes
|
||||
</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 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 class="bulk-operation-caption">validity period</div>
|
||||
<div class="bulk-operation-data">
|
||||
<div v-if="canModify('rates')" class="bulk-operation-caption">validity period</div>
|
||||
<div v-if="canModify('rates')" class="bulk-operation-data">
|
||||
<div class="period-select-container">
|
||||
<dropdown :options="periods"
|
||||
emptyText="No property set available"
|
||||
|
|
@ -48,13 +55,20 @@
|
|||
<div class="bulk-operation-header">Import</div>
|
||||
<div class="bulk-operation-caption">dataset</div>
|
||||
<div class="bulk-operation-data">
|
||||
<radio-option name="import-dataset" value="NODE" v-model="importDataset">nodes</radio-option>
|
||||
<radio-option name="import-dataset" value="COUNTRY_MATRIX" v-model="importDataset">kilometer rates
|
||||
<radio-option v-if="canModify('nodes')" name="import-dataset" value="NODE" v-model="importDataset">nodes
|
||||
</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 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 class="bulk-operation-caption">file</div>
|
||||
|
|
@ -79,8 +93,11 @@
|
|||
<div class="bulk-operation-box-status-container">
|
||||
<div class="bulk-operation-status">
|
||||
<div class="bulk-operation-header">History</div>
|
||||
<div v-if="this.bulkOperationStore.getBulkOperations.length === 0" class="empty-container">No recent bulk operations</div>
|
||||
<bulk-operation v-else v-for="bulk in this.bulkOperationStore.getBulkOperations" :key="bulk.id" :operation="bulk" @download="fetchFile"></bulk-operation>
|
||||
<div v-if="this.bulkOperationStore.getBulkOperations.length === 0" class="empty-container">No recent bulk
|
||||
operations
|
||||
</div>
|
||||
<bulk-operation v-else v-for="bulk in this.bulkOperationStore.getBulkOperations" :key="bulk.id"
|
||||
:operation="bulk" @download="fetchFile"></bulk-operation>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -101,6 +118,7 @@ import {useValidityPeriodStore} from "@/store/validityPeriod.js";
|
|||
import {useBulkOperationStore} from "@/store/bulkOperation.js";
|
||||
import BulkOperation from "@/components/layout/bulkoperation/BulkOperation.vue";
|
||||
import logger from "@/logger.js";
|
||||
import {useActiveUserStore} from "@/store/activeuser.js";
|
||||
|
||||
export default {
|
||||
name: "BulkOperations",
|
||||
|
|
@ -125,13 +143,13 @@ export default {
|
|||
},
|
||||
watch: {
|
||||
async isSelected(newVal) {
|
||||
if(newVal === true)
|
||||
if (newVal === true && this.activeUserStore.allowRates)
|
||||
await this.validityPeriodStore.loadPeriods();
|
||||
await this.bulkOperationStore.manageStatus();
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapStores(useValidityPeriodStore, useBulkOperationStore),
|
||||
...mapStores(useValidityPeriodStore, useBulkOperationStore, useActiveUserStore),
|
||||
showValidityPeriod() {
|
||||
return this.exportType === "download" && (this.exportDataset === "COUNTRY_MATRIX" || this.exportDataset === "CONTAINER_RATE");
|
||||
},
|
||||
|
|
@ -167,8 +185,20 @@ export default {
|
|||
}
|
||||
},
|
||||
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) {
|
||||
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'}`
|
||||
},
|
||||
|
|
@ -195,7 +225,7 @@ export default {
|
|||
this.fileBlob = await this.readFileAsBlob(file);
|
||||
|
||||
// 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;
|
||||
|
||||
logger.info(`File loaded into memory: ${file.name} (${(file.size / 1024).toFixed(2)} KB)`);
|
||||
|
|
@ -220,7 +250,7 @@ export default {
|
|||
|
||||
reader.onload = (e) => {
|
||||
// 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);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -77,19 +77,22 @@ export default {
|
|||
tabsConfig() {
|
||||
const tabs = [];
|
||||
|
||||
if(this.activeUserStore.isSuper) {
|
||||
if (this.activeUserStore.isSuper) {
|
||||
tabs.push(this.propertiesTab);
|
||||
tabs.push(this.systemLogTab);
|
||||
}
|
||||
|
||||
if(this.activeUserStore.isService) {
|
||||
if (this.activeUserStore.isService) {
|
||||
tabs.push(this.appsTab);
|
||||
}
|
||||
|
||||
if (this.activeUserStore.isSuper || this.activeUserStore.isMaterial) {
|
||||
tabs.push(this.materialsTab);
|
||||
}
|
||||
|
||||
tabs.push(this.nodesTab);
|
||||
|
||||
if(this.activeUserStore.allowRates)
|
||||
if (this.activeUserStore.allowRates)
|
||||
tabs.push(this.ratesTab);
|
||||
|
||||
tabs.push(this.bulkOperationsTab);
|
||||
|
|
|
|||
|
|
@ -18,12 +18,12 @@ export const useActiveUserStore = defineStore('activeUser', {
|
|||
allowConfiguration(state) {
|
||||
if (state.user === null)
|
||||
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) {
|
||||
if (state.user === null)
|
||||
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) {
|
||||
if (state.user === null)
|
||||
|
|
@ -45,6 +45,11 @@ export const useActiveUserStore = defineStore('activeUser', {
|
|||
return false;
|
||||
return state.user.groups?.includes("freight");
|
||||
},
|
||||
isMaterial(state) {
|
||||
if (state.user === null)
|
||||
return false;
|
||||
return state.user.groups?.includes("material");
|
||||
},
|
||||
allowRates(state) {
|
||||
if (state.user === null)
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import {defineStore} from 'pinia'
|
|||
import {config} from '@/config'
|
||||
import {useErrorStore} from "@/store/error.js";
|
||||
import performRequest from "@/backend.js";
|
||||
import logger from "@/logger.js";
|
||||
|
||||
export const useMaterialStore = defineStore('material', {
|
||||
state() {
|
||||
|
|
|
|||
|
|
@ -14,63 +14,63 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
//@Configuration
|
||||
//@EnableWebMvc
|
||||
//@Order(Ordered.HIGHEST_PRECEDENCE)
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
@Value("${lcc.allowed_cors}")
|
||||
private String allowedCors;
|
||||
|
||||
public CorsConfig(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(@NotNull CorsRegistry registry) {
|
||||
String[] activeProfiles = environment.getActiveProfiles();
|
||||
|
||||
System.out.println("Active profiles: " + Arrays.toString(activeProfiles));
|
||||
System.out.println("Allowed CORS: " + allowedCors);
|
||||
|
||||
if (Arrays.asList(activeProfiles).contains("dev")) {
|
||||
|
||||
System.out.println("Applying DEV CORS configuration");
|
||||
|
||||
// Development CORS configuration
|
||||
registry.addMapping("/api/**")
|
||||
.allowedOriginPatterns("http://localhost:*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
||||
.allowCredentials(true);
|
||||
|
||||
// OAuth endpoints
|
||||
registry.addMapping("/oauth/**")
|
||||
.allowedOriginPatterns("http://localhost:*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true);
|
||||
} else {
|
||||
|
||||
System.out.println("Applying PROD CORS configuration");
|
||||
|
||||
// Production CORS configuration
|
||||
registry.addMapping("/api/**")
|
||||
.allowedOrigins(allowedCors)
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
||||
.allowCredentials(true);
|
||||
|
||||
// OAuth endpoints
|
||||
registry.addMapping("/oauth/**")
|
||||
.allowedOriginPatterns("*")
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
.allowedHeaders("*")
|
||||
.allowCredentials(true);
|
||||
}
|
||||
}
|
||||
// private final Environment environment;
|
||||
//
|
||||
// @Value("${lcc.allowed_cors}")
|
||||
// private String allowedCors;
|
||||
//
|
||||
// public CorsConfig(Environment environment) {
|
||||
// this.environment = environment;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void addCorsMappings(@NotNull CorsRegistry registry) {
|
||||
// String[] activeProfiles = environment.getActiveProfiles();
|
||||
//
|
||||
// System.out.println("Active profiles: " + Arrays.toString(activeProfiles));
|
||||
// System.out.println("Allowed CORS: " + allowedCors);
|
||||
//
|
||||
// if (Arrays.asList(activeProfiles).contains("dev")) {
|
||||
//
|
||||
// System.out.println("Applying DEV CORS configuration");
|
||||
//
|
||||
// // Development CORS configuration
|
||||
// registry.addMapping("/api/**")
|
||||
// .allowedOriginPatterns("http://localhost:*")
|
||||
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
// .allowedHeaders("*")
|
||||
// .exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
||||
// .allowCredentials(true);
|
||||
//
|
||||
// // OAuth endpoints
|
||||
// registry.addMapping("/oauth/**")
|
||||
// .allowedOriginPatterns("http://localhost:*")
|
||||
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
// .allowedHeaders("*")
|
||||
// .allowCredentials(true);
|
||||
// } else {
|
||||
//
|
||||
// System.out.println("Applying PROD CORS configuration");
|
||||
//
|
||||
// // Production CORS configuration
|
||||
// registry.addMapping("/api/**")
|
||||
// .allowedOrigins(allowedCors)
|
||||
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
// .allowedHeaders("*")
|
||||
// .exposedHeaders("X-Total-Count", "X-Page-Count", "X-Current-Page")
|
||||
// .allowCredentials(true);
|
||||
//
|
||||
// // OAuth endpoints
|
||||
// registry.addMapping("/oauth/**")
|
||||
// .allowedOriginPatterns("*")
|
||||
// .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
|
||||
// .allowedHeaders("*")
|
||||
// .allowCredentials(true);
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
|
@ -104,10 +104,13 @@ public class SecurityConfig {
|
|||
CorsConfiguration configuration = new CorsConfiguration();
|
||||
configuration.setAllowedOriginPatterns(List.of("http://localhost:*"));
|
||||
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
configuration.setAllowedHeaders(Arrays.asList("*"));
|
||||
configuration.setAllowedHeaders(List.of("*"));
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setMaxAge(3600L);
|
||||
|
||||
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
|
||||
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
|
|
@ -131,6 +134,9 @@ public class SecurityConfig {
|
|||
configuration.setAllowCredentials(true);
|
||||
configuration.setMaxAge(3600L);
|
||||
|
||||
configuration.setExposedHeaders(Arrays.asList("X-Total-Count", "X-Page-Count", "X-Current-Page"));
|
||||
|
||||
|
||||
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
|
||||
source.registerCorsConfiguration("/**", configuration);
|
||||
return source;
|
||||
|
|
|
|||
|
|
@ -37,20 +37,20 @@ public class BulkOperationController {
|
|||
}
|
||||
|
||||
@GetMapping({"/status/", "/status"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||
public ResponseEntity<List<BulkOperationDTO>> getBulkStatus() {
|
||||
return ResponseEntity.ok(bulkOperationService.getStatus());
|
||||
}
|
||||
|
||||
@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) {
|
||||
bulkOperationService.processFileImport(type, file);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@GetMapping({"/templates/{type}", "/templates/{type}/"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||
public ResponseEntity<InputStreamResource> generateTemplate(@PathVariable BulkFileType type) {
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("Content-Disposition", "attachment; filename=lcc_template_" + type.name().toLowerCase() + ".xlsx");
|
||||
|
|
@ -64,7 +64,7 @@ public class BulkOperationController {
|
|||
|
||||
|
||||
@GetMapping({"/download/{type}", "/download/{type}/"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type) {
|
||||
bulkOperationService.processFileExport(type);
|
||||
return ResponseEntity.ok().build();
|
||||
|
|
@ -72,7 +72,7 @@ public class BulkOperationController {
|
|||
|
||||
|
||||
@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) {
|
||||
bulkOperationService.processFileExport(type, validityPeriodId);
|
||||
return ResponseEntity.ok().build();
|
||||
|
|
@ -80,7 +80,7 @@ public class BulkOperationController {
|
|||
}
|
||||
|
||||
@GetMapping({"/file/{processId}", "/file/{processId}/"})
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||
public ResponseEntity<InputStreamResource> download(@PathVariable("processId") Integer 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).
|
||||
*/
|
||||
@GetMapping("/")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING')")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||
public ResponseEntity<List<MaterialDTO>> listMaterials(
|
||||
@RequestParam(defaultValue = "true") String excludeDeprecated,
|
||||
@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.
|
||||
*/
|
||||
@GetMapping("/{id}")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING')")
|
||||
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION', 'BASIC', 'FREIGHT', 'PACKAGING', 'MATERIAL')")
|
||||
public ResponseEntity<MaterialDetailDTO> getMaterialDetails(@PathVariable Integer id) {
|
||||
return ResponseEntity.ok(materialService.getMaterial(id));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,15 @@
|
|||
package de.avatic.lcc.dto.generic;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Represents a geographical location with latitude and longitude.
|
||||
* This immutable DTO (Data Transfer Object) is used to transfer location data across system layers.
|
||||
*/
|
||||
public class LocationDTO {
|
||||
|
||||
/**
|
||||
* The latitude of the location.
|
||||
*
|
||||
* @param latitude The latitude of the location.
|
||||
* Positive values indicate north and negative values indicate south.
|
||||
*/
|
||||
private final double latitude;
|
||||
|
||||
/**
|
||||
* The longitude of the location.
|
||||
* @param longitude The longitude of the location.
|
||||
* 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.
|
||||
|
|
@ -28,9 +17,7 @@ public class LocationDTO {
|
|||
* @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
|
||||
*/
|
||||
public LocationDTO(double latitude, double longitude) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
public LocationDTO {
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -46,7 +33,8 @@ public class LocationDTO {
|
|||
*
|
||||
* @return the latitude, where positive values indicate north and negative values indicate south
|
||||
*/
|
||||
public double getLatitude() {
|
||||
@Override
|
||||
public double latitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +43,8 @@ public class LocationDTO {
|
|||
*
|
||||
* @return the longitude, where positive values indicate east and negative values indicate west
|
||||
*/
|
||||
public double getLongitude() {
|
||||
@Override
|
||||
public double longitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
|
|
@ -68,11 +57,6 @@ public class LocationDTO {
|
|||
Double.compare(that.longitude, longitude) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(latitude, longitude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LocationDTO{" +
|
||||
|
|
|
|||
|
|
@ -160,18 +160,12 @@ public class BulkOperationRepository {
|
|||
);
|
||||
}
|
||||
|
||||
private static class BulkOperationRowMapper implements RowMapper<BulkOperation> {
|
||||
|
||||
private final boolean skipFile;
|
||||
private record BulkOperationRowMapper(boolean skipFile) implements RowMapper<BulkOperation> {
|
||||
|
||||
BulkOperationRowMapper() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
BulkOperationRowMapper(boolean skipFile) {
|
||||
this.skipFile = skipFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BulkOperation mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
BulkOperation operation = new BulkOperation();
|
||||
|
|
|
|||
|
|
@ -30,15 +30,18 @@ import java.util.Map;
|
|||
@Repository
|
||||
public class DumpRepository {
|
||||
|
||||
@Autowired
|
||||
private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
private JdbcTemplate jdbcTemplate;
|
||||
@Autowired
|
||||
private PremiseRepository premiseRepository;
|
||||
@Autowired
|
||||
private PremiseTransformer premiseTransformer;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final PremiseRepository premiseRepository;
|
||||
private final PremiseTransformer premiseTransformer;
|
||||
|
||||
public DumpRepository(NamedParameterJdbcTemplate namedParameterJdbcTemplate, JdbcTemplate jdbcTemplate, PremiseRepository premiseRepository, PremiseTransformer premiseTransformer) {
|
||||
this.namedParameterJdbcTemplate = namedParameterJdbcTemplate;
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
this.premiseRepository = premiseRepository;
|
||||
this.premiseTransformer = premiseTransformer;
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public CalculationJobDumpDTO getDump(Integer id) {
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ public class SysErrorRepository {
|
|||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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,
|
||||
e.calculation_job_id, e.bulk_operation_id, e.type, e.created_at
|
||||
FROM sys_error e
|
||||
""" + whereClause.toString() + """
|
||||
""" + whereClause + """
|
||||
ORDER BY e.created_at DESC
|
||||
LIMIT :limit OFFSET :offset
|
||||
""";
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import java.util.function.Function;
|
|||
*/
|
||||
public class SearchQueryResult<T> {
|
||||
|
||||
private List<T> result;
|
||||
private final List<T> result;
|
||||
|
||||
private final Integer page, totalPages, totalElements, elementsPerPage;
|
||||
|
||||
|
|
|
|||
|
|
@ -135,6 +135,28 @@ public class DestinationRepository {
|
|||
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
|
||||
public List<Destination> getByPremiseIdsAndNodeId(List<Integer> premiseId, Integer nodeId, Integer userId) {
|
||||
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> {
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -288,13 +288,7 @@ public class ContainerRateRepository {
|
|||
}
|
||||
|
||||
|
||||
private static class ContainerRateMapper implements RowMapper<ContainerRate> {
|
||||
|
||||
private final boolean fetchCountryIds;
|
||||
|
||||
public ContainerRateMapper(boolean fetchCountryIds) {
|
||||
this.fetchCountryIds = fetchCountryIds;
|
||||
}
|
||||
private record ContainerRateMapper(boolean fetchCountryIds) implements RowMapper<ContainerRate> {
|
||||
|
||||
public ContainerRateMapper() {
|
||||
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.transformer.premise.DestinationTransformer;
|
||||
import de.avatic.lcc.service.users.AuthorizationService;
|
||||
import de.avatic.lcc.util.exception.base.ForbiddenException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
|
|
@ -34,15 +33,12 @@ public class DestinationService {
|
|||
private final RouteSectionRepository routeSectionRepository;
|
||||
private final RouteNodeRepository routeNodeRepository;
|
||||
private final RoutingService routingService;
|
||||
;
|
||||
private final NodeRepository nodeRepository;
|
||||
private final PremiseRepository premiseRepository;
|
||||
private final UserNodeRepository userNodeRepository;
|
||||
private final PropertyRepository propertyRepository;
|
||||
private final PropertyService propertyService;
|
||||
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.destinationTransformer = destinationTransformer;
|
||||
this.routeRepository = routeRepository;
|
||||
|
|
@ -52,16 +48,16 @@ public class DestinationService {
|
|||
this.nodeRepository = nodeRepository;
|
||||
this.premiseRepository = premiseRepository;
|
||||
this.userNodeRepository = userNodeRepository;
|
||||
this.propertyRepository = propertyRepository;
|
||||
this.propertyService = propertyService;
|
||||
this.authorizationService = authorizationService;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public Map<Integer, List<DestinationDTO>> setDestination(DestinationSetDTO dto) {
|
||||
//TODO fix user authorization
|
||||
var userId = 1;
|
||||
//dto.getPremiseId().forEach(id -> destinationRepository.checkOwner(id, userId));
|
||||
var admin = authorizationService.isSuper();
|
||||
Integer userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
destinationRepository.checkOwner(dto.getPremiseId(), userId);
|
||||
|
||||
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) {
|
||||
|
||||
Node destinationNode = nodeRepository.getById(destinationNodeId).orElseThrow();
|
||||
|
|
@ -141,17 +136,22 @@ public class DestinationService {
|
|||
}
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void updateDestination(Integer id, DestinationUpdateDTO destinationUpdateDTO) {
|
||||
//todo check authorization
|
||||
var admin = authorizationService.isSuper();
|
||||
Integer userId = authorizationService.getUserId();
|
||||
destinationRepository.checkOwner(id, userId);
|
||||
|
||||
if (!admin)
|
||||
destinationRepository.checkOwner(id, userId);
|
||||
|
||||
var selectedRouteId = destinationUpdateDTO.getRouteSelectedId();
|
||||
|
||||
|
|
@ -159,7 +159,6 @@ public class DestinationService {
|
|||
routeRepository.updateSelectedByDestinationId(id, selectedRouteId);
|
||||
}
|
||||
|
||||
|
||||
destinationRepository.update(id,
|
||||
destinationUpdateDTO.getAnnualAmount(),
|
||||
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> userNodes = new HashMap<>();
|
||||
|
||||
for(var premise : premisses) {
|
||||
for(var destinationId : destinationIds) {
|
||||
for (var premise : premisses) {
|
||||
for (var destinationId : destinationIds) {
|
||||
boolean isUserSupplierNode = (premise.getSupplierNodeId() == null);
|
||||
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());
|
||||
}
|
||||
|
||||
if(!isUserSupplierNode && !nodes.containsKey(premise.getSupplierNodeId())) {
|
||||
if (!isUserSupplierNode && !nodes.containsKey(premise.getSupplierNodeId())) {
|
||||
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());
|
||||
}
|
||||
|
||||
|
|
@ -205,7 +204,6 @@ public class DestinationService {
|
|||
@Transactional
|
||||
public void saveRoute(List<RouteInformation> routeObjs, Integer destinationId) {
|
||||
|
||||
|
||||
for (var routeObj : routeObjs) {
|
||||
boolean first = true;
|
||||
Integer fromNodeId = null;
|
||||
|
|
@ -238,44 +236,12 @@ public class DestinationService {
|
|||
}
|
||||
}
|
||||
|
||||
private record RouteIds(Integer fromNodeId, Integer toNodeId, boolean isUserSupplierNode) {}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void findRouteAndSave(Integer destinationId, Node destination, Node supplier, boolean isUserSupplierNode) {
|
||||
|
||||
var routeObjs = routingService.findRoutes(destination, supplier, isUserSupplierNode);
|
||||
|
||||
for (var routeObj : routeObjs) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
saveRoute(routeObjs, destinationId);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
|
|
@ -289,14 +255,14 @@ public class DestinationService {
|
|||
destinations.forEach(destination -> deleteDestinationById(destination.getId(), deleteRoutesOnly));
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
public void deleteDestinationById(Integer id, boolean deleteRoutesOnly) {
|
||||
//todo check authorization
|
||||
var admin = authorizationService.isSuper();
|
||||
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);
|
||||
|
||||
for (var route : routes) {
|
||||
|
|
@ -310,11 +276,6 @@ public class DestinationService {
|
|||
if (!deleteRoutesOnly)
|
||||
destinationRepository.deleteById(id);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
throw new ForbiddenException("Not authorized to delete destination with id " + id);
|
||||
|
||||
}
|
||||
|
||||
@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)
|
||||
public List<PremiseDetailDTO> getPremises(List<Integer> premiseIds) {
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(premiseIds, userId);
|
||||
|
||||
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) {
|
||||
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(premises, userId);
|
||||
|
||||
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));
|
||||
|
||||
|
|
@ -183,11 +188,12 @@ public class PremisesService {
|
|||
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();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(packagingDTO.getPremiseIds(), userId);
|
||||
|
||||
var dimensions = packagingDTO.getDimensions() == null ? null : dimensionTransformer.toDimensionEntity(packagingDTO.getDimensions());
|
||||
|
|
@ -197,8 +203,10 @@ public class PremisesService {
|
|||
}
|
||||
|
||||
public void updateMaterial(MaterialUpdateDTO materialUpdateDTO) {
|
||||
//TODO check values. and return errors if needed
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(materialUpdateDTO.getPremiseIds(), userId);
|
||||
|
||||
var tariffRate = materialUpdateDTO.getTariffRate() == null ? null : BigDecimal.valueOf(materialUpdateDTO.getTariffRate().doubleValue());
|
||||
|
|
@ -207,8 +215,10 @@ public class PremisesService {
|
|||
}
|
||||
|
||||
public void updatePrice(PriceUpdateDTO priceUpdateDTO) {
|
||||
//TODO check values. and return errors if needed
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(priceUpdateDTO.getPremiseIds(), userId);
|
||||
|
||||
var price = priceUpdateDTO.getPrice() == null ? null : BigDecimal.valueOf(priceUpdateDTO.getPrice().doubleValue());
|
||||
|
|
@ -219,9 +229,13 @@ public class PremisesService {
|
|||
|
||||
@Transactional
|
||||
public void delete(List<Integer> premiseIds) {
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(premiseIds, userId);
|
||||
|
||||
|
||||
// only delete drafts.
|
||||
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) {
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(premiseIds, userId);
|
||||
|
||||
|
||||
// only archive completed.
|
||||
var premisses = premiseRepository.getPremisesById(premiseIds);
|
||||
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;
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public List<Integer> duplicate(List<Integer> premissIds) {
|
||||
var admin = authorizationService.isSuper();
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
if (!admin)
|
||||
premiseRepository.checkOwner(premissIds, userId);
|
||||
|
||||
var newIds = new ArrayList<Integer>();
|
||||
|
||||
premissIds.forEach(id -> {
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ public class PropertyValidationService {
|
|||
public void evaluate(String value) {
|
||||
if (operator == CompareOperator.ENUM) {
|
||||
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 {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ public class UserNodeService {
|
|||
|
||||
node.setName(dto.getName());
|
||||
node.setAddress(dto.getAddress());
|
||||
node.setGeoLng(BigDecimal.valueOf(dto.getLocation().getLongitude()));
|
||||
node.setGeoLat(BigDecimal.valueOf(dto.getLocation().getLatitude()));
|
||||
node.setGeoLng(BigDecimal.valueOf(dto.getLocation().longitude()));
|
||||
node.setGeoLat(BigDecimal.valueOf(dto.getLocation().latitude()));
|
||||
node.setDestination(false);
|
||||
node.setSource(true);
|
||||
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.BulkOperation;
|
||||
import de.avatic.lcc.repositories.NodeRepository;
|
||||
import de.avatic.lcc.service.api.BatchGeoApiService;
|
||||
import de.avatic.lcc.service.bulk.bulkImport.*;
|
||||
import de.avatic.lcc.service.excelMapper.*;
|
||||
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
|
||||
import de.avatic.lcc.util.exception.internalerror.ExcelValidationError;
|
||||
import org.apache.poi.ss.usermodel.Sheet;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
|
|
@ -26,8 +24,7 @@ public class BulkImportService {
|
|||
private final MaterialExcelMapper materialExcelMapper;
|
||||
private final PackagingExcelMapper packagingExcelMapper;
|
||||
private final NodeExcelMapper nodeExcelMapper;
|
||||
private final NodeRepository nodeRepository;
|
||||
private final NodeTransformer nodeTransformer;
|
||||
|
||||
private final NodeBulkImportService nodeBulkImportService;
|
||||
private final PackagingBulkImportService packagingBulkImportService;
|
||||
private final MaterialBulkImportService materialBulkImportService;
|
||||
|
|
@ -35,14 +32,12 @@ public class BulkImportService {
|
|||
private final ContainerRateImportService containerRateImportService;
|
||||
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.containerRateExcelMapper = containerRateExcelMapper;
|
||||
this.materialExcelMapper = materialExcelMapper;
|
||||
this.packagingExcelMapper = packagingExcelMapper;
|
||||
this.nodeExcelMapper = nodeExcelMapper;
|
||||
this.nodeRepository = nodeRepository;
|
||||
this.nodeTransformer = nodeTransformer;
|
||||
this.nodeBulkImportService = nodeBulkImportService;
|
||||
this.packagingBulkImportService = packagingBulkImportService;
|
||||
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.users.AuthorizationService;
|
||||
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.internalerror.ExcelValidationError;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
|
|
@ -39,6 +41,8 @@ public class BulkOperationService {
|
|||
public void processFileImport(BulkFileType fileType, MultipartFile file) {
|
||||
|
||||
var userId = authorizationService.getUserId();
|
||||
checkAuthorized(fileType);
|
||||
|
||||
|
||||
String contentType = file.getContentType();
|
||||
if (!"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType) &&
|
||||
|
|
@ -62,10 +66,23 @@ public class BulkOperationService {
|
|||
|
||||
|
||||
} 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) {
|
||||
var userId = authorizationService.getUserId();
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ public class TemplateExportService {
|
|||
|
||||
public InputStreamSource generateTemplate(BulkFileType bulkFileType) {
|
||||
try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
|
||||
Workbook workbook = new XSSFWorkbook();) {
|
||||
Workbook workbook = new XSSFWorkbook()) {
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -289,15 +289,7 @@ public class ContainerCalculationService {
|
|||
}
|
||||
|
||||
@Renderer(text = "getFullDebugInfo()")
|
||||
private static class Block {
|
||||
|
||||
private final PackagingDimension dimension;
|
||||
private final BlockType type;
|
||||
|
||||
public Block(PackagingDimension dimension, BlockType type) {
|
||||
this.dimension = dimension;
|
||||
this.type = type;
|
||||
}
|
||||
private record Block(PackagingDimension dimension, BlockType type) {
|
||||
|
||||
public int calculateBlockCount(int containerColumnLength) {
|
||||
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.repositories.NodeRepository;
|
||||
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.rates.ContainerRateRepository;
|
||||
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 java.math.BigDecimal;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.temporal.TemporalUnit;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
@Service
|
||||
public class PreCalculationCheckService {
|
||||
|
|
@ -48,8 +52,9 @@ public class PreCalculationCheckService {
|
|||
private final ContainerRateRepository containerRateRepository;
|
||||
private final ValidityPeriodRepository validityPeriodRepository;
|
||||
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.customApiService = customApiService;
|
||||
this.destinationRepository = destinationRepository;
|
||||
|
|
@ -64,6 +69,7 @@ public class PreCalculationCheckService {
|
|||
this.containerRateRepository = containerRateRepository;
|
||||
this.validityPeriodRepository = validityPeriodRepository;
|
||||
this.propertySetRepository = propertySetRepository;
|
||||
this.propertyRepository = propertyRepository;
|
||||
}
|
||||
|
||||
public void doPrecheck(Integer premiseId, Integer setId, Integer periodId) {
|
||||
|
|
@ -125,17 +131,30 @@ public class PreCalculationCheckService {
|
|||
private void periodCheck(ValidityPeriod period, PropertySet set) {
|
||||
|
||||
|
||||
|
||||
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)
|
||||
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())
|
||||
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())
|
||||
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);
|
||||
}
|
||||
|
||||
;
|
||||
|
||||
private WeightedTotalCosts getWeightedTotalCosts(Map<Integer, List<CalculationJobRouteSection>> sectionsMap) {
|
||||
|
||||
BigDecimal totalPreRunCost = BigDecimal.ZERO;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import org.springframework.security.core.Authentication;
|
|||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
@Service
|
||||
public class AuthorizationService {
|
||||
|
||||
|
|
@ -35,9 +37,22 @@ public class AuthorizationService {
|
|||
}
|
||||
|
||||
public boolean isSuper() {
|
||||
return hasRole("SUPER");
|
||||
}
|
||||
|
||||
public boolean hasAnyRole(String... roles) {
|
||||
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
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");
|
||||
|
|
|
|||
|
|
@ -49,8 +49,7 @@ public class UserService {
|
|||
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
|
||||
|
||||
//todo make a service. and simulate user rights in dev profile.
|
||||
if (authentication != null && authentication.getPrincipal() instanceof LccOidcUser) {
|
||||
LccOidcUser oidcUser = (LccOidcUser) authentication.getPrincipal();
|
||||
if (authentication != null && authentication.getPrincipal() instanceof LccOidcUser oidcUser) {
|
||||
|
||||
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)
|
||||
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)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue