- added navigation guards

- added roles to endpoints
- added user ids where needed
This commit is contained in:
Jan 2025-10-07 15:53:37 +02:00
parent 5760c7d30c
commit 431694ce22
30 changed files with 437 additions and 116 deletions

View file

@ -16,7 +16,6 @@ import ErrorNotification from "@/components/UI/ErrorNotifcation.vue";
export default {
components: {ErrorNotification, TheHeader},
}
</script>

View file

@ -3,9 +3,9 @@
<img alt="LCC logo" class="logo" src="../../../assets/logo.svg" width="125" height="125" />
<nav>
<ul>
<li><navigation-element class="navigationbox" to="/calculations">My calculations</navigation-element></li>
<li><navigation-element class="navigationbox" to="/reports">Reporting</navigation-element></li>
<li><navigation-element class="navigationbox" to="/config">Configuration</navigation-element></li>
<li v-if="showCalculation"><navigation-element class="navigationbox" to="/calculations">My calculations</navigation-element></li>
<li v-if="showReporting"><navigation-element class="navigationbox" to="/reports">Reporting</navigation-element></li>
<li v-if="showConfiguration"><navigation-element class="navigationbox" to="/config">Configuration</navigation-element></li>
</ul>
</nav>
</header>
@ -15,10 +15,27 @@
import {PhCube, PhHeart, PhHorse} from "@phosphor-icons/vue";
import NavigationElement from "@/components/UI/NavigationElement.vue";
import Config from "@/pages/Config.vue";
import {useActiveUserStore} from "@/store/activeuser.js";
import {mapStores} from "pinia";
export default {
name: "TheHeader",
components: {Parameterization: Config, NavigationElement, PhCube, PhHeart, PhHorse}
components: {Parameterization: Config, NavigationElement, PhCube, PhHeart, PhHorse},
computed: {
...mapStores(useActiveUserStore),
showCalculation() {
return this.activeUserStore.allowCalculation;
},
showReporting() {
return this.activeUserStore.allowReporting;
},
showConfiguration() {
return this.activeUserStore.allowConfiguration;
}
},
async created() {
await this.activeUserStore.loadIfRequired();
}
}
</script>

View file

@ -25,6 +25,8 @@ import Rates from "@/components/layout/config/Rates.vue";
import Nodes from "@/components/layout/config/Nodes.vue";
import Materials from "@/components/layout/config/Materials.vue";
import ErrorLog from "@/pages/ErrorLog.vue";
import {mapStores} from "pinia";
import {useActiveUserStore} from "@/store/activeuser.js";
export default {
name: "Config",
@ -32,50 +34,68 @@ export default {
data() {
return {
currentTab: null,
tabsConfig: [
{
title: 'Properties',
component: markRaw(Properties),
props: { isSelected: false},
},
{
title: 'System log',
component: markRaw(ErrorLog),
props: { isSelected: false},
},
{
title: 'Materials',
component: markRaw(Materials),
props: { isSelected: false},
},
{
title: 'Nodes',
component: markRaw(Nodes),
props: { isSelected: false},
},
{
title: 'Rates',
component: markRaw(Rates),
props: { isSelected: false},
},
{
title: 'Bulk operations',
component: markRaw(BulkOperations),
props: { isSelected: false},
}
]
propertiesTab: {
title: 'Properties',
component: markRaw(Properties),
props: {isSelected: false},
},
systemLogTab: {
title: 'System log',
component: markRaw(ErrorLog),
props: {isSelected: false},
},
materialsTab: {
title: 'Materials',
component: markRaw(Materials),
props: {isSelected: false},
},
nodesTab: {
title: 'Nodes',
component: markRaw(Nodes),
props: {isSelected: false},
},
ratesTab: {
title: 'Rates',
component: markRaw(Rates),
props: {isSelected: false},
},
bulkOperationsTab: {
title: 'Bulk operations',
component: markRaw(BulkOperations),
props: {isSelected: false},
}
}
},
computed: {
...mapStores(useActiveUserStore),
tabsConfig() {
const tabs = [];
if(this.activeUserStore.isSuper) {
tabs.push(this.propertiesTab);
tabs.push(this.systemLogTab);
}
tabs.push(this.materialsTab);
tabs.push(this.nodesTab);
if(this.activeUserStore.allowRates)
tabs.push(this.ratesTab);
tabs.push(this.bulkOperationsTab);
return tabs;
}
},
created() {
},
methods: {
handleTabChange(eventData) {
console.log("handleTabChange")
const { index, tab } = eventData;
console.log(`Tab ${index} activated:`, tab.title);
this.tabsConfig.forEach(t => t.props.isSelected = t.title === tab.title);
const {index, tab} = eventData;
this.tabsConfig.forEach(t => t.props.isSelected = t.title === tab.title);
}
}
}

View file

@ -0,0 +1,36 @@
<template>
<div class="empty-container">
<box><div class="space-around"><PhXCircle :size="32" /> Not authorized.</div></box>
</div>
</template>
<script>
import Box from "@/components/UI/Box.vue";
import {PhShieldWarning, PhXCircle} from "@phosphor-icons/vue";
export default {
name: "NotAuthorized",
components: {PhXCircle, PhShieldWarning, Box}
}
</script>
<style scoped>
.space-around {
display: flex;
justify-content: center;
align-items: center;
margin: 3rem;
gap: 1.6rem;
}
.empty-container {
display: flex;
justify-content: center;
align-items: center;
font-size: 1.6rem;
}
</style>

View file

@ -8,53 +8,118 @@ import CalculationAssistant from "@/pages/CalculationAssistant.vue";
import ErrorLog from "@/pages/ErrorLog.vue";
import CalculationDump from "@/components/layout/dev/CalculationDump.vue";
import DevPage from "@/pages/DevPage.vue";
import {useActiveUserStore} from "@/store/activeuser.js";
import NotAuthorized from "@/pages/NotAuthorized.vue";
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/not-authorized',
component: NotAuthorized,
name: 'not-authorized',
},
{
path: '/',
redirect: '/calculations',
name: 'calculation-list',
},
{
path: '/assistant',
component: CalculationAssistant,
name: 'assistant',
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowCalculation) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/calculations',
component: Calculations,
name: 'home',
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowCalculation) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/edit/:id',
component: CalculationSingleEdit,
name: 'edit',
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowCalculation) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/bulk/:ids',
component: CalculationMassEdit,
name: 'bulk',
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowCalculation) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/bulk/:ids/edit/:id',
component: CalculationSingleEdit,
name: 'bulk-single-edit',
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowCalculation) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/reports',
component: Reporting,
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowReporting) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/config',
component: Config
},
{
path: '/error',
component: ErrorLog
component: Config,
beforeEnter: async (to, from) => {
const userStore = useActiveUserStore();
await userStore.loadIfRequired();
if (userStore.allowConfiguration) {
return true;
}
return {name: 'not-authorized'};
},
},
{
path: '/dev/dump/:id',

View file

@ -0,0 +1,59 @@
import {defineStore} from 'pinia'
import {config} from '@/config'
import performRequest from "@/backend.js";
export const useActiveUserStore = defineStore('activeUser', {
state: () => {
return {
user: null,
}
},
getters: {
allowCalculation(state) {
if (state.user === null)
return false;
return state.user.groups?.includes("super") || state.user.groups?.includes("calculation");
},
allowConfiguration(state) {
if (state.user === null)
return false;
return state.user.groups?.includes("super") || state.user.groups?.includes("freight") || state.user.groups?.includes("packaging");
},
allowReporting(state) {
return state.user !== null;
},
isSuper(state) {
if (state.user === null)
return false;
return state.user.groups?.includes("super");
},
isPackaging(state) {
if (state.user === null)
return false;
return state.user.groups?.includes("packaging");
},
isFreight(state) {
if (state.user === null)
return false;
return state.user.groups?.includes("freight");
},
allowRates(state) {
if (state.user === null)
return false;
return state.user.groups?.includes("super") || state.user.groups?.includes("freight");
}
},
actions: {
async loadIfRequired() {
if (this.user === null)
await this.load();
},
async load() {
const resp = await performRequest(this, "GET", `${config.backendUrl}/active-user`, null, true);
this.user = resp.data;
}
}
});

View file

@ -47,12 +47,12 @@ public class DevUserEmulationFilter extends OncePerRequestFilter {
Integer emulatedUserId = (Integer) session.getAttribute(DEV_USER_ID_SESSION_KEY);
if(emulatedUserId != null) {
// if(emulatedUserId != null) {
User user = userRepository.getById(emulatedUserId == null ? 1 : emulatedUserId);
if (user != null) {
setEmulatedUser(user);
}
}
// }
filterChain.doFilter(request, response);
}

View file

@ -11,6 +11,7 @@ import org.jetbrains.annotations.NotNull;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
@ -33,6 +34,7 @@ import java.util.Set;
import java.util.function.Supplier;
@Configuration
@EnableMethodSecurity
public class SecurityConfig {
@Bean

View file

@ -81,8 +81,6 @@ public class GlobalExceptionHandler {
return new ResponseEntity<>(new ErrorResponseDTO(error), HttpStatus.BAD_REQUEST);
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<ErrorResponseDTO> handleConstraintViolation(MethodArgumentTypeMismatchException exception) { //

View file

@ -26,7 +26,6 @@ import java.util.List;
*/
@RestController
@RequestMapping("/api/bulk")
@RolesAllowed({"ROLE_SUPER", "ROLE_FREIGHT", "ROLE_PACKAGING"})
public class BulkOperationController {
private final BulkOperationService bulkOperationService;
@ -38,17 +37,20 @@ public class BulkOperationController {
}
@GetMapping({"/status/", "/status"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<List<BulkOperationDTO>> getBulkStatus() {
return ResponseEntity.ok(bulkOperationService.getStatus());
}
@PostMapping({"/upload/{type}", "/upload/{type}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
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')")
public ResponseEntity<InputStreamResource> generateTemplate(@PathVariable BulkFileType type) {
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment; filename=lcc_template_" + type.name().toLowerCase() + ".xlsx");
@ -62,6 +64,7 @@ public class BulkOperationController {
@GetMapping({"/download/{type}", "/download/{type}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type) {
bulkOperationService.processFileExport(type);
return ResponseEntity.ok().build();
@ -69,6 +72,7 @@ public class BulkOperationController {
@GetMapping({"/download/{type}/{validity_period_id}", "/download/{type}/{validity_period_id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<Void> scheduleDownload(@PathVariable BulkFileType type, @PathVariable("validity_period_id") Integer validityPeriodId) {
bulkOperationService.processFileExport(type, validityPeriodId);
return ResponseEntity.ok().build();
@ -76,6 +80,7 @@ public class BulkOperationController {
}
@GetMapping({"/file/{processId}", "/file/{processId}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<InputStreamResource> download(@PathVariable("processId") Integer id) {
var op = bulkOperationService.getBulkOperation(id);

View file

@ -22,11 +22,13 @@ import de.avatic.lcc.service.calculation.PremiseCreationService;
import de.avatic.lcc.service.calculation.PremiseSearchStringAnalyzerService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import de.avatic.lcc.util.exception.base.BadRequestException;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Min;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -60,6 +62,7 @@ public class PremiseController {
}
@GetMapping({"/view", "/view/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<List<PremiseDTO>> listPremises(@RequestParam(required = false) String filter,
@RequestParam(defaultValue = "20") @Min(1) int limit,
@RequestParam(defaultValue = "1") @Min(1) int page,
@ -78,6 +81,7 @@ public class PremiseController {
}
@GetMapping({"/search", "/search/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<PremiseSearchResultDTO> findMaterialsAndSuppliers(@RequestHeader String search) {
try {
@ -93,6 +97,7 @@ public class PremiseController {
}
@PostMapping({"/create", "/create/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<List<PremiseDetailDTO>> createPremises(@RequestBody @Valid CreatePremiseDTO dto) {
if ((dto.getSupplierIds() == null || dto.getSupplierIds().isEmpty()) && (dto.getUserSupplierIds() == null || dto.getUserSupplierIds().isEmpty())) {
@ -109,23 +114,27 @@ public class PremiseController {
@PostMapping({"/delete", "/delete/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> deletePremises(@RequestParam List<Integer> premissIds) {
premisesServices.delete(premissIds);
return ResponseEntity.ok().build();
}
@PostMapping({"/archive", "/archive/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> archivePremises(@RequestParam List<Integer> premissIds) {
premisesServices.archive(premissIds);
return ResponseEntity.ok().build();
}
@GetMapping({"/edit", "/edit/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<List<PremiseDetailDTO>> getPremises(@RequestParam List<Integer> premissIds) {
return ResponseEntity.ok(premisesServices.getPremises(premissIds));
}
@PutMapping({"/start", "/start/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> startCalculation(@RequestBody List<Integer> premiseIds) {
premisesServices.startCalculation(premiseIds);
return ResponseEntity.ok().build();
@ -138,45 +147,53 @@ public class PremiseController {
* @return A ResponseEntity with the bulk processing status payload.
*/
@GetMapping({"/status/{processing_id}", "/status/{processing_id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<CalculationStatus> getCalculationStatus(@PathVariable("processing_id") Integer id) {
return ResponseEntity.ok(premisesServices.getCalculationStatus(id));
}
@PostMapping({"/packaging", "/packaging/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> updatePackaging(@RequestBody PackagingUpdateDTO packagingDTO) {
premisesServices.updatePackaging(packagingDTO);
return ResponseEntity.ok().build();
}
@PostMapping({"/material", "/material/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> updateMaterial(@RequestBody @Valid MaterialUpdateDTO materialUpdateDTO) {
premisesServices.updateMaterial(materialUpdateDTO);
return ResponseEntity.ok().build();
}
@PostMapping({"/price", "/price/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> updatePrice(@RequestBody @Valid PriceUpdateDTO priceUpdateDTO) {
premisesServices.updatePrice(priceUpdateDTO);
return ResponseEntity.ok().build();
}
@PostMapping({"/destination", "/destination/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Map<Integer, DestinationDTO>> createDestination(@RequestBody @Valid DestinationCreateDTO destinationCreateDTO) {
return ResponseEntity.ok(destinationService.createDestination(destinationCreateDTO));
}
@PutMapping({"/destination", "/destination/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Map<Integer, List<DestinationDTO>>> setDestination(@RequestBody DestinationSetDTO destinationSetDTO) {
return ResponseEntity.ok(destinationService.setDestination(destinationSetDTO));
}
@GetMapping({"/destination/{id}", "/destination/{id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<DestinationDTO> getDestination(@PathVariable Integer id) {
return ResponseEntity.ok(destinationService.getDestination(id));
}
@PutMapping({"/destination/{id}", "/destination/{id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> updateDestination(@PathVariable @Min(1) Integer id, @RequestBody @Valid DestinationUpdateDTO destinationUpdateDTO) {
log.info("Updating destination {}", destinationUpdateDTO);
destinationService.updateDestination(id, destinationUpdateDTO);
@ -184,17 +201,20 @@ public class PremiseController {
}
@DeleteMapping({"/destination/{id}", "/destination/{id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> deleteDestination(@PathVariable Integer id) {
destinationService.deleteDestinationById(id, false);
return ResponseEntity.ok().build();
}
@PutMapping({"/supplier", "/supplier/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<List<PremiseDetailDTO>> setSupplier(@RequestBody SetDataDTO setSupplierDTO) {
return ResponseEntity.ok(changeSupplierService.setSupplier(setSupplierDTO));
}
@PutMapping({"/material", "/material/"})
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<List<PremiseDetailDTO>> setMaterial(@RequestBody SetDataDTO setMaterialDTO) {
return ResponseEntity.ok(changeMaterialService.setMaterial(setMaterialDTO));
}

View file

@ -7,6 +7,8 @@ import de.avatic.lcc.service.access.CountryService;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import jakarta.validation.constraints.Min;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -43,10 +45,13 @@ public class CountryController {
* and additional pagination headers
*/
@GetMapping({"/", ""})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<List<CountryDTO>> listCountries(@RequestParam(defaultValue = "20") @Min(1) int limit,
@RequestParam(defaultValue = "1") @Min(1) int page,
@RequestParam(required = false) Optional<String> filter) {
var auth = SecurityContextHolder.getContext().getAuthentication();
SearchQueryResult<CountryDTO> countries = countryService.listCountries(filter, page, limit);
return ResponseEntity.ok()
@ -65,6 +70,7 @@ public class CountryController {
* and additional headers with metadata
*/
@GetMapping({"/all", "/all/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<List<CountryDTO>> allCountries(@RequestParam(required = false) Optional<String> filter) {
SearchQueryResult<CountryDTO> countries = countryService.listCountries(filter);
@ -86,6 +92,7 @@ public class CountryController {
* @return a {@link ResponseEntity} containing a {@link CountryDetailDTO} with the country's details
*/
@GetMapping({"/{id}", "/{id}/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<CountryDetailDTO> getCountryDetails(@PathVariable String id, @RequestParam(name = "property_set", defaultValue = "0", required = false) @Min(0) Integer propertySetId) {
return ResponseEntity.ok(countryService.getCountry(id, propertySetId).orElseThrow(() -> new NotFoundException(NotFoundException.NotFoundType.COUNTRY, id)));
}

View file

@ -7,6 +7,7 @@ import de.avatic.lcc.service.access.MaterialService;
import jakarta.validation.constraints.Min;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -16,6 +17,7 @@ import java.util.Optional;
@RestController
@RequestMapping("/api/materials")
@Validated
@PreAuthorize("hasRole('SUPER')")
public class MaterialController {
@ -36,6 +38,7 @@ public class MaterialController {
* X-Total-Count (total elements), X-Page-Count (total pages), and X-Current-Page (current page).
*/
@GetMapping("/")
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<List<MaterialDTO>> listMaterials(
@RequestParam(defaultValue = "true") String excludeDeprecated,
@RequestParam(defaultValue = "20") @Min(1) int limit,
@ -59,6 +62,7 @@ public class MaterialController {
* @throws RuntimeException if the material with the given ID is not found.
*/
@GetMapping("/{id}")
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<MaterialDetailDTO> getMaterialDetails(@PathVariable Integer id) {
return ResponseEntity.ok(materialService.getMaterial(id));
}

View file

@ -11,8 +11,10 @@ import de.avatic.lcc.service.GeoApiService;
import de.avatic.lcc.service.access.NodeService;
import de.avatic.lcc.service.access.UserNodeService;
import de.avatic.lcc.util.Check;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.constraints.Min;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -21,6 +23,7 @@ import java.util.List;
@RestController
@RequestMapping("/api/nodes")
@Validated
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public class NodeController {
private final NodeService nodeService;
@ -34,6 +37,7 @@ public class NodeController {
}
@GetMapping({"","/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<List<NodeDTO>> listNodes(@RequestParam(required = false) String filter, @RequestParam(defaultValue = "1") @Min(1) Integer page, @RequestParam(defaultValue = "20") @Min(1) Integer limit) {
nodeService.listNodes(filter, page, limit);
@ -47,32 +51,38 @@ public class NodeController {
}
@GetMapping({"/search", "/search/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<List<NodeDTO>> searchNodes(@RequestParam(required = false) String filter, @RequestParam(defaultValue = "10") @Min(1) int limit, @RequestParam(name = "node_type", required = false) NodeType nodeType, @RequestParam(name = "include_user_node", defaultValue = "false") boolean includeUserNode) {
return ResponseEntity.ok(nodeService.searchNode(filter, limit, nodeType, includeUserNode));
}
@GetMapping("/{id}")
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<NodeDetailDTO> getNode(@PathVariable Integer id) {
return ResponseEntity.ok(nodeService.getNode(id));
}
@DeleteMapping("/{id}")
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Integer> deleteNode(@PathVariable Integer id) {
return ResponseEntity.ok(nodeService.deleteNode(id));
}
@PutMapping("/{id}")
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Integer> updateNode(@PathVariable Integer id, @RequestBody NodeUpdateDTO node) {
Check.equals(id, node.getId());
return ResponseEntity.ok(nodeService.updateNode(node));
}
@GetMapping("/locate")
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT', 'PACKAGING')")
public ResponseEntity<LocateNodeDTO> locateNode(@RequestParam String address) {
return ResponseEntity.ok(geoApiService.locate(address));
}
@PutMapping("/")
@PreAuthorize("hasAnyRole('SUPER', 'CALCULATION')")
public ResponseEntity<Void> addUserNode(@RequestBody AddUserNodeDTO node) {
userNodeService.addUserNode(node);
return ResponseEntity.ok().build();

View file

@ -8,8 +8,10 @@ import de.avatic.lcc.service.access.CountryService;
import de.avatic.lcc.service.access.PropertyService;
import de.avatic.lcc.service.configuration.PropertyApprovalService;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.constraints.Min;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -46,6 +48,7 @@ public class PropertyController {
* @return ResponseEntity containing the list of PropertyDTO objects.
*/
@GetMapping({"/", ""})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<List<PropertyDTO>> listProperties(@RequestParam(name = "property_set", defaultValue = "0", required = false) @Min(0) Integer propertySetId) {
var props = propertyService.listProperties(propertySetId);
@ -64,6 +67,7 @@ public class PropertyController {
* @return ResponseEntity containing the list of ValidityPeriodDTO objects.
*/
@GetMapping({"/periods", "/periods/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<List<ValidityPeriodDTO>> listPeriods() {
return ResponseEntity.ok(propertyService.listPropertySets());
}
@ -75,6 +79,7 @@ public class PropertyController {
* @return ResponseEntity indicating the operation status.
*/
@DeleteMapping({"/periods/{id}", "/periods/{id}/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Void> invalidatePeriod(@PathVariable @Min(1) Integer id) {
propertyService.invalidate(id);
return ResponseEntity.ok().build();
@ -90,6 +95,7 @@ public class PropertyController {
* @return ResponseEntity indicating the operation status.
*/
@PutMapping({"/country/{iso}/{external_mapping_id}", "/country/{iso}/{external_mapping_id}/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Void> setCountryProperty(@PathVariable("iso") IsoCode isoCode, @PathVariable(name = "external_mapping_id") String mappingId, @RequestBody SetPropertyDTO dto) {
countryService.setProperties(isoCode, mappingId, dto.getValue());
return ResponseEntity.ok().build();
@ -103,6 +109,7 @@ public class PropertyController {
* @return ResponseEntity indicating the operation status.
*/
@PutMapping({"/system/{external_mapping_id}", "/system/{external_mapping_id}/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Void> setProperties(@PathVariable(name = "external_mapping_id") String externalMappingId, @RequestBody SetPropertyDTO dto) {
propertyService.setProperties(externalMappingId, dto.getValue());
return ResponseEntity.ok().build();
@ -114,6 +121,7 @@ public class PropertyController {
* @return ResponseEntity containing true if drafts are present, false otherwise.
*/
@GetMapping({"/staged_changes", "/staged_changes/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Boolean> checkPropertiesDrafts() {
return ResponseEntity.ok(propertyApprovalService.hasPropertiesDraft());
}
@ -124,6 +132,7 @@ public class PropertyController {
* @return ResponseEntity indicating the operation status.
*/
@PutMapping({"/staged_changes", "/staged_changes/"})
@PreAuthorize("hasRole('SUPER')")
public ResponseEntity<Void> approvePropertiesDrafts() {
propertyApprovalService.applyDraft();
return ResponseEntity.ok().build();

View file

@ -9,9 +9,11 @@ import de.avatic.lcc.service.access.ContainerRateService;
import de.avatic.lcc.service.access.MatrixRateService;
import de.avatic.lcc.service.configuration.RateApprovalService;
import de.avatic.lcc.service.access.ValidityPeriodService;
import jakarta.annotation.security.RolesAllowed;
import jakarta.validation.constraints.Min;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -53,6 +55,7 @@ public class RateController {
* @return a ResponseEntity containing the list of container rates and additional pagination headers
*/
@GetMapping({"/container", "/container/" })
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<List<ContainerRateDTO>> listContainerRates(
@RequestParam(defaultValue = "") String filter,
@RequestParam(defaultValue = "20") @Min(1) int limit,
@ -86,6 +89,7 @@ public class RateController {
* @return a ResponseEntity containing the ContainerRateDTO with the rate information of the specified container
*/
@GetMapping({"/container/{id}", "/container/{id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<ContainerRateDTO> getContainerRate(@PathVariable Integer id) {
return ResponseEntity.ok(containerRateService.getContainerRate(id));
}
@ -101,6 +105,7 @@ public class RateController {
* including pagination headers.
*/
@GetMapping({"/matrix","/matrix/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<List<MatrixRateDTO>> listMatrixRates(
@RequestParam(defaultValue = "") String filter,
@RequestParam(defaultValue = "20") @Min(1) int limit,
@ -134,6 +139,7 @@ public class RateController {
* @return a ResponseEntity containing the MatrixRateDTO for the specified ID
*/
@GetMapping({"/matrix/{id}", "/matrix/{id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<MatrixRateDTO> getMatrixRate(@PathVariable Integer id) {
return ResponseEntity.ok(matrixRateService.getRate(id));
}
@ -144,6 +150,7 @@ public class RateController {
* @return ResponseEntity containing the list of ValidityPeriodDTO objects.
*/
@GetMapping({"/periods", "/periods/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<List<ValidityPeriodDTO>> listPeriods() {
return ResponseEntity.ok(validityPeriodService.listPeriods());
}
@ -155,6 +162,7 @@ public class RateController {
* @return ResponseEntity indicating the operation status.
*/
@DeleteMapping({"/periods/{id}", "/periods/{id}/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<Void> invalidatePeriod(@PathVariable Integer id) {
validityPeriodService.invalidate(id);
return ResponseEntity.ok().build();
@ -167,6 +175,7 @@ public class RateController {
* whether rate drafts exist (true) or not (false).
*/
@GetMapping( {"/staged_changes", "/staged_changes/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<StagedRatesDTO> checkRateDrafts() {
return ResponseEntity.ok(rateApprovalService.getStagedRateDTO());
}
@ -177,6 +186,7 @@ public class RateController {
* @return ResponseEntity with HTTP 200 status if the operation is successful.
*/
@PutMapping({"/staged_changes", "/staged_changes/"})
@PreAuthorize("hasAnyRole('SUPER', 'FREIGHT')")
public ResponseEntity<Void> approveRateDrafts() {
rateApprovalService.approveRateDrafts();
return ResponseEntity.ok().build();

View file

@ -1,5 +1,6 @@
package de.avatic.lcc.controller.maps;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
@ -15,6 +16,7 @@ import java.time.Instant;
@RestController
@RequestMapping("/api/maps")
@CrossOrigin(origins = {"http://localhost:3000", "http://localhost:8080", "https://yourdomain.com"})
@RolesAllowed({"ROLE_SUPER", "ROLE_CALCULATION"})
public class AzureMapsController {
private static final Logger logger = LoggerFactory.getLogger(AzureMapsController.class);

View file

@ -4,6 +4,7 @@ import de.avatic.lcc.dto.generic.NodeDTO;
import de.avatic.lcc.dto.report.ReportDTO;
import de.avatic.lcc.service.report.ExcelReportingService;
import de.avatic.lcc.service.report.ReportingService;
import jakarta.annotation.security.RolesAllowed;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;

View file

@ -1,12 +1,10 @@
package de.avatic.lcc.controller.users;
import de.avatic.lcc.config.LccOidcUser;
import de.avatic.lcc.dto.users.UserDTO;
import de.avatic.lcc.repositories.users.UserRepository;
import de.avatic.lcc.service.transformer.users.UserTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -16,24 +14,16 @@ import org.springframework.web.bind.annotation.RestController;
public class ActiveUserController {
private final UserTransformer userTransformer;
private final UserRepository userRepository;
private final AuthorizationService authorizationService;
public ActiveUserController(UserTransformer userTransformer, UserRepository userRepository) {
this.userTransformer = userTransformer;
this.userRepository = userRepository;
public ActiveUserController(AuthorizationService authorizationService) {
this.authorizationService = authorizationService;
}
@GetMapping
public ResponseEntity<UserDTO> getActiveUser() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if(auth.getPrincipal() instanceof LccOidcUser) {
LccOidcUser user = (LccOidcUser) auth.getPrincipal();
return ResponseEntity.ok(userTransformer.toUserDTO(userRepository.getById(user.getSqlUserId())));
}
var user = authorizationService.getActiveUser();
if (user != null) return ResponseEntity.ok(user);
return ResponseEntity.internalServerError().build();
}
}

View file

@ -14,6 +14,7 @@ import de.avatic.lcc.repositories.properties.PropertyRepository;
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;
@ -39,8 +40,9 @@ public class DestinationService {
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) {
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) {
this.destinationRepository = destinationRepository;
this.destinationTransformer = destinationTransformer;
this.routeRepository = routeRepository;
@ -52,6 +54,7 @@ public class DestinationService {
this.userNodeRepository = userNodeRepository;
this.propertyRepository = propertyRepository;
this.propertyService = propertyService;
this.authorizationService = authorizationService;
}
@Transactional
@ -115,7 +118,7 @@ public class DestinationService {
@Transactional
public Map<Integer, DestinationDTO> createDestination(DestinationCreateDTO dto) {
Integer userId = 1; //TODO get user id.
Integer userId = authorizationService.getUserId();
var existingDestinations = destinationRepository.getByPremiseIdsAndNodeId(dto.getPremiseId(), dto.getDestinationNodeId(), userId);
@ -146,7 +149,7 @@ public class DestinationService {
@Transactional
public void updateDestination(Integer id, DestinationUpdateDTO destinationUpdateDTO) {
//todo check authorization
Integer userId = 1;
Integer userId = authorizationService.getUserId();
destinationRepository.checkOwner(id, userId);
@ -290,10 +293,10 @@ public class DestinationService {
@Transactional
public void deleteDestinationById(Integer id, boolean deleteRoutesOnly) {
//todo check authorization
Integer userId = 1;
Integer userId = authorizationService.getUserId();
Optional<Integer> ownerId = destinationRepository.getOwnerIdById(id);
if (userId == 1 /* todo remove */ || ownerId.isPresent() && ownerId.get().equals(userId)) {
if (ownerId.isPresent() && ownerId.get().equals(userId)) {
List<Route> routes = routeRepository.getByDestinationId(id);
for (var route : routes) {

View file

@ -12,6 +12,7 @@ import de.avatic.lcc.repositories.users.UserNodeRepository;
import de.avatic.lcc.service.transformer.nodes.NodeUpdateDTOTransformer;
import de.avatic.lcc.service.transformer.nodes.NodeDetailTransformer;
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.badrequest.NodeNotFoundException;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import org.springframework.stereotype.Service;
@ -31,14 +32,15 @@ public class NodeService {
private final NodeDetailTransformer nodeDetailTransformer;
private final NodeUpdateDTOTransformer nodeUpdateDTOTransformer;
private final UserNodeRepository userNodeRepository;
private final AuthorizationService authorizationService;
public NodeService(NodeRepository nodeRepository, NodeTransformer nodeTransformer, NodeDetailTransformer nodeDetailTransformer, NodeUpdateDTOTransformer nodeUpdateDTOTransformer, UserNodeRepository userNodeRepository) {
public NodeService(NodeRepository nodeRepository, NodeTransformer nodeTransformer, NodeDetailTransformer nodeDetailTransformer, NodeUpdateDTOTransformer nodeUpdateDTOTransformer, UserNodeRepository userNodeRepository, AuthorizationService authorizationService) {
this.nodeRepository = nodeRepository;
this.nodeTransformer = nodeTransformer;
this.nodeDetailTransformer = nodeDetailTransformer;
this.nodeUpdateDTOTransformer = nodeUpdateDTOTransformer;
this.userNodeRepository = userNodeRepository;
this.authorizationService = authorizationService;
}
/**
@ -108,7 +110,7 @@ public class NodeService {
* @return a list of {@link NodeDTO} objects representing the search results.
*/
public List<NodeDTO> searchNode(String filter, int limit, NodeType nodeType, boolean includeUserNode) { List<NodeDTO> nodes = new ArrayList<>();
int userId = 1; //TODO get current user's id
int userId = authorizationService.getUserId();
if( includeUserNode && NodeType.SOURCE.equals(nodeType)) {
nodes.addAll(userNodeRepository.searchNode(filter, limit, userId, true).stream().map(nodeTransformer::toNodeDTO).toList());

View file

@ -25,6 +25,7 @@ import de.avatic.lcc.service.precalculation.PostCalculationCheckService;
import de.avatic.lcc.service.precalculation.PreCalculationCheckService;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.service.transformer.premise.PremiseTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.base.InternalErrorException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -61,8 +62,9 @@ public class PremisesService {
private final CalculationJobDestinationRepository calculationJobDestinationRepository;
private final CalculationJobRouteSectionRepository calculationJobRouteSectionRepository;
private final PostCalculationCheckService postCalculationCheckService;
private final AuthorizationService authorizationService;
public PremisesService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DimensionTransformer dimensionTransformer, DestinationService destinationService, CalculationJobRepository calculationJobRepository, PropertySetRepository propertySetRepository, ValidityPeriodRepository validityPeriodRepository, CalculationStatusService calculationStatusService, CalculationExecutionService calculationExecutionService, PreCalculationCheckService preCalculationCheckService, CalculationJobDestinationRepository calculationJobDestinationRepository, CalculationJobRouteSectionRepository calculationJobRouteSectionRepository, PostCalculationCheckService postCalculationCheckService) {
public PremisesService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DimensionTransformer dimensionTransformer, DestinationService destinationService, CalculationJobRepository calculationJobRepository, PropertySetRepository propertySetRepository, ValidityPeriodRepository validityPeriodRepository, CalculationStatusService calculationStatusService, CalculationExecutionService calculationExecutionService, PreCalculationCheckService preCalculationCheckService, CalculationJobDestinationRepository calculationJobDestinationRepository, CalculationJobRouteSectionRepository calculationJobRouteSectionRepository, PostCalculationCheckService postCalculationCheckService, AuthorizationService authorizationService) {
this.premiseRepository = premiseRepository;
this.premiseTransformer = premiseTransformer;
this.dimensionTransformer = dimensionTransformer;
@ -77,27 +79,19 @@ public class PremisesService {
this.calculationJobDestinationRepository = calculationJobDestinationRepository;
this.calculationJobRouteSectionRepository = calculationJobRouteSectionRepository;
this.postCalculationCheckService = postCalculationCheckService;
this.authorizationService = authorizationService;
}
@Transactional(readOnly = true)
public SearchQueryResult<PremiseDTO> listPremises(String filter, Integer page, Integer limit, Integer userId, Boolean deleted, Boolean archived, Boolean done) {
//TODO check if user is admin. if not: use the user_id of currently authorized user.
var admin = false;
//TODO use actual user.
userId = 1;
var admin = authorizationService.isSuper();
userId = authorizationService.getUserId();
return SearchQueryResult.map(premiseRepository.listPremises(filter, new SearchQueryPagination(page, limit), userId, deleted, archived, done), admin ? premiseTransformer::toPremiseDTOWithUserInfo : premiseTransformer::toPremiseDTO);
}
@Transactional(readOnly = true)
public List<PremiseDetailDTO> getPremises(List<Integer> premiseIds) {
//TODO use real user
var userId = 1;
var userId = authorizationService.getUserId();
premiseRepository.checkOwner(premiseIds, userId);
return premiseRepository.getPremisesById(premiseIds).stream().filter(p -> p.getState().equals(PremiseState.DRAFT)).map(premiseTransformer::toPremiseDetailDTO).toList();
@ -106,7 +100,7 @@ public class PremisesService {
public void startCalculation(List<Integer> premises) {
var userId = 1; // TODO get current user id
var userId = authorizationService.getUserId();
// todo check if user is allowed to schedule this
@ -182,7 +176,7 @@ public class PremisesService {
public void updatePackaging(PackagingUpdateDTO packagingDTO) {
//TODO check values. and return errors if needed
var userId = 1; // todo get id from current user.
var userId = authorizationService.getUserId();
premiseRepository.checkOwner(packagingDTO.getPremiseIds(), userId);
var dimensions = packagingDTO.getDimensions() == null ? null : dimensionTransformer.toDimensionEntity(packagingDTO.getDimensions());
@ -193,7 +187,7 @@ public class PremisesService {
public void updateMaterial(MaterialUpdateDTO materialUpdateDTO) {
//TODO check values. and return errors if needed
var userId = 1; // todo get id from current user.
var userId = authorizationService.getUserId();
premiseRepository.checkOwner(materialUpdateDTO.getPremiseIds(), userId);
var tariffRate = materialUpdateDTO.getTariffRate() == null ? null : BigDecimal.valueOf(materialUpdateDTO.getTariffRate().doubleValue());
@ -203,7 +197,7 @@ public class PremisesService {
public void updatePrice(PriceUpdateDTO priceUpdateDTO) {
//TODO check values. and return errors if needed
var userId = 1; // todo get id from current user.
var userId = authorizationService.getUserId();
premiseRepository.checkOwner(priceUpdateDTO.getPremiseIds(), userId);
var price = priceUpdateDTO.getPrice() == null ? null : BigDecimal.valueOf(priceUpdateDTO.getPrice().doubleValue());
@ -214,8 +208,7 @@ public class PremisesService {
@Transactional
public void delete(List<Integer> premiseIds) {
//TODO check authorization
var userId = 1;
var userId = authorizationService.getUserId();
premiseRepository.checkOwner(premiseIds, userId);
// only delete drafts.
@ -230,8 +223,7 @@ public class PremisesService {
}
public void archive(List<Integer> premiseIds) {
//TODO check authorization
var userId = 1;
var userId = authorizationService.getUserId();
premiseRepository.checkOwner(premiseIds, userId);
// only archive completed.

View file

@ -5,6 +5,7 @@ import de.avatic.lcc.model.country.IsoCode;
import de.avatic.lcc.model.nodes.Node;
import de.avatic.lcc.repositories.country.CountryRepository;
import de.avatic.lcc.repositories.users.UserNodeRepository;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import org.springframework.stereotype.Service;
@ -15,10 +16,12 @@ import java.math.BigDecimal;
public class UserNodeService {
private final CountryRepository countryRepository;
private final UserNodeRepository userNodeRepository;
private final AuthorizationService authorizationService;
public UserNodeService(CountryRepository countryRepository, UserNodeRepository userNodeRepository) {
public UserNodeService(CountryRepository countryRepository, UserNodeRepository userNodeRepository, AuthorizationService authorizationService) {
this.countryRepository = countryRepository;
this.userNodeRepository = userNodeRepository;
this.authorizationService = authorizationService;
}
public Node getUserNode(Integer id) {
@ -35,7 +38,7 @@ public class UserNodeService {
public void addUserNode(AddUserNodeDTO dto) {
// TODO: get real user id.
var userId = 1;
var userId = authorizationService.getUserId();
Node node = new Node();

View file

@ -8,6 +8,7 @@ import de.avatic.lcc.model.bulk.BulkOperation;
import de.avatic.lcc.repositories.bulk.BulkOperationRepository;
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.InternalErrorException;
import org.springframework.stereotype.Service;
@ -24,18 +25,20 @@ public class BulkOperationService {
private final ValidityPeriodRepository validityPeriodRepository;
private final BulkOperationTransformer bulkOperationTransformer;
private final BulkOperationExecutionService bulkOperationExecutionService;
private final AuthorizationService authorizationService;
public BulkOperationService(BulkOperationRepository bulkOperationRepository, ValidityPeriodRepository validityPeriodRepository, BulkOperationTransformer bulkOperationTransformer, BulkOperationExecutionService bulkOperationExecutionService) {
public BulkOperationService(BulkOperationRepository bulkOperationRepository, ValidityPeriodRepository validityPeriodRepository, BulkOperationTransformer bulkOperationTransformer, BulkOperationExecutionService bulkOperationExecutionService, AuthorizationService authorizationService) {
this.bulkOperationRepository = bulkOperationRepository;
this.validityPeriodRepository = validityPeriodRepository;
this.bulkOperationTransformer = bulkOperationTransformer;
this.bulkOperationExecutionService = bulkOperationExecutionService;
this.authorizationService = authorizationService;
}
public void processFileImport(BulkFileType fileType, MultipartFile file) {
int userId = 1; //TODO actual user
var userId = authorizationService.getUserId();
String contentType = file.getContentType();
if (!"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet".equals(contentType) &&
@ -64,7 +67,7 @@ public class BulkOperationService {
}
public void processFileExport(BulkFileType type, Integer validityPeriodId) {
int userId = 1; //TODO set actual user id
var userId = authorizationService.getUserId();
BulkOperation op = new BulkOperation();
op.setUserId(userId);
@ -82,7 +85,7 @@ public class BulkOperationService {
}
public List<BulkOperationDTO> getStatus() {
int userId = 1; //TODO actual user
var userId = authorizationService.getUserId();
return bulkOperationRepository.listByUserId(userId).stream().map(bulkOperationTransformer::toBulkOperationDTO).toList();
}

View file

@ -15,6 +15,7 @@ import de.avatic.lcc.repositories.premise.PremiseRepository;
import de.avatic.lcc.repositories.users.UserNodeRepository;
import de.avatic.lcc.service.CustomApiService;
import de.avatic.lcc.service.access.PremisesService;
import de.avatic.lcc.service.users.AuthorizationService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -32,8 +33,9 @@ public class ChangeMaterialService {
private final PackagingDimensionRepository packagingDimensionRepository;
private final PackagingPropertiesRepository packagingPropertiesRepository;
private final MaterialRepository materialRepository;
private final AuthorizationService authorizationService;
public ChangeMaterialService(PremiseRepository premiseRepository, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, MaterialRepository materialRepository) {
public ChangeMaterialService(PremiseRepository premiseRepository, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, MaterialRepository materialRepository, AuthorizationService authorizationService) {
this.premiseRepository = premiseRepository;
this.premisesService = premisesService;
this.customApiService = customApiService;
@ -43,11 +45,12 @@ public class ChangeMaterialService {
this.packagingDimensionRepository = packagingDimensionRepository;
this.packagingPropertiesRepository = packagingPropertiesRepository;
this.materialRepository = materialRepository;
this.authorizationService = authorizationService;
}
@Transactional
public List<PremiseDetailDTO> setMaterial(SetDataDTO dto) {
Integer userId = 1; /* TODO get user id */
var userId = authorizationService.getUserId();
Integer materialId = dto.getMaterialId();
List<Integer> premiseIds = dto.getPremiseId();

View file

@ -17,6 +17,7 @@ import de.avatic.lcc.repositories.users.UserNodeRepository;
import de.avatic.lcc.service.CustomApiService;
import de.avatic.lcc.service.access.DestinationService;
import de.avatic.lcc.service.access.PremisesService;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -40,8 +41,9 @@ public class ChangeSupplierService {
private final RouteRepository routeRepository;
private final RouteSectionRepository routeSectionRepository;
private final RouteNodeRepository routeNodeRepository;
private final AuthorizationService authorizationService;
public ChangeSupplierService(PremiseRepository premiseRepository, DestinationService destinationService, RoutingService routingService, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, DestinationRepository destinationRepository, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository) {
public ChangeSupplierService(PremiseRepository premiseRepository, DestinationService destinationService, RoutingService routingService, PremisesService premisesService, CustomApiService customApiService, NodeRepository nodeRepository, UserNodeRepository userNodeRepository, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, DestinationRepository destinationRepository, RouteRepository routeRepository, RouteSectionRepository routeSectionRepository, RouteNodeRepository routeNodeRepository, AuthorizationService authorizationService) {
this.premiseRepository = premiseRepository;
this.destinationService = destinationService;
this.routingService = routingService;
@ -56,13 +58,14 @@ public class ChangeSupplierService {
this.routeRepository = routeRepository;
this.routeSectionRepository = routeSectionRepository;
this.routeNodeRepository = routeNodeRepository;
this.authorizationService = authorizationService;
}
@Transactional
public List<PremiseDetailDTO> setSupplier(SetDataDTO dto) {
Integer userId = 1; // todo get current user;
var userId = authorizationService.getUserId();
Integer supplierNodeId = dto.getSupplierNodeId();
List<Integer> premiseIds = dto.getPremiseId();

View file

@ -17,6 +17,7 @@ import de.avatic.lcc.service.CustomApiService;
import de.avatic.lcc.service.access.DestinationService;
import de.avatic.lcc.service.transformer.generic.DimensionTransformer;
import de.avatic.lcc.service.transformer.premise.PremiseTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import de.avatic.lcc.util.exception.badrequest.InvalidArgumentException;
import de.avatic.lcc.util.exception.badrequest.NotFoundException;
import de.avatic.lcc.util.exception.base.ForbiddenException;
@ -40,8 +41,9 @@ public class PremiseCreationService {
private final PackagingDimensionRepository packagingDimensionRepository;
private final PackagingPropertiesRepository packagingPropertiesRepository;
private final CustomApiService customApiService;
private final AuthorizationService authorizationService;
public PremiseCreationService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DestinationService destinationService, UserNodeRepository userNodeRepository, NodeRepository nodeRepository, MaterialRepository materialRepository, DimensionTransformer dimensionTransformer, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, CustomApiService customApiService) {
public PremiseCreationService(PremiseRepository premiseRepository, PremiseTransformer premiseTransformer, DestinationService destinationService, UserNodeRepository userNodeRepository, NodeRepository nodeRepository, MaterialRepository materialRepository, DimensionTransformer dimensionTransformer, PackagingRepository packagingRepository, PackagingDimensionRepository packagingDimensionRepository, PackagingPropertiesRepository packagingPropertiesRepository, CustomApiService customApiService, AuthorizationService authorizationService) {
this.premiseRepository = premiseRepository;
this.premiseTransformer = premiseTransformer;
this.destinationService = destinationService;
@ -53,11 +55,12 @@ public class PremiseCreationService {
this.packagingDimensionRepository = packagingDimensionRepository;
this.packagingPropertiesRepository = packagingPropertiesRepository;
this.customApiService = customApiService;
this.authorizationService = authorizationService;
}
@Transactional
public List<PremiseDetailDTO> createPremises(List<Integer> materialIds, List<Integer> supplierIds, List<Integer> userSupplierIds, boolean createEmpty) {
Integer userId = 1; //TODO get user id
var userId = authorizationService.getUserId();
userNodeRepository.checkOwner(userSupplierIds, userId);
/* Build all resulting premises */

View file

@ -8,6 +8,7 @@ import de.avatic.lcc.repositories.premise.PremiseRepository;
import de.avatic.lcc.repositories.users.UserNodeRepository;
import de.avatic.lcc.service.transformer.generic.MaterialTransformer;
import de.avatic.lcc.service.transformer.generic.NodeTransformer;
import de.avatic.lcc.service.users.AuthorizationService;
import org.springframework.stereotype.Service;
import java.util.Collection;
@ -33,6 +34,7 @@ public class PremiseSearchStringAnalyzerService {
private final NodeTransformer nodeTransformer;
private final MaterialTransformer materialTransformer;
private final UserNodeRepository userNodeRepository;
private final AuthorizationService authorizationService;
/**
* Constructor for the PremiseSearchStringAnalyzerService, initializing the required repositories
@ -44,13 +46,14 @@ public class PremiseSearchStringAnalyzerService {
* @param nodeTransformer Transformer for mapping database node entities (suppliers) to DTOs.
* @param materialTransformer Transformer for mapping database material entities to DTOs.
*/
public PremiseSearchStringAnalyzerService(MaterialRepository materialRepository, NodeRepository nodeRepository, PremiseRepository premiseRepository, NodeTransformer nodeTransformer, MaterialTransformer materialTransformer, UserNodeRepository userNodeRepository) {
public PremiseSearchStringAnalyzerService(MaterialRepository materialRepository, NodeRepository nodeRepository, PremiseRepository premiseRepository, NodeTransformer nodeTransformer, MaterialTransformer materialTransformer, UserNodeRepository userNodeRepository, AuthorizationService authorizationService) {
this.materialRepository = materialRepository;
this.nodeRepository = nodeRepository;
this.premiseRepository = premiseRepository;
this.nodeTransformer = nodeTransformer;
this.materialTransformer = materialTransformer;
this.userNodeRepository = userNodeRepository;
this.authorizationService = authorizationService;
}
/**
@ -67,7 +70,7 @@ public class PremiseSearchStringAnalyzerService {
*/
public PremiseSearchResultDTO findMaterialAndSuppliers(String search) {
var userId = 1; //TODO get actual user id.
var userId = authorizationService.getUserId();
List<Material> material = materialRepository.getByPartNumbers(findPartNumbers(search));
List<Integer> materialIds = material.stream().map(Material::getId).toList();

View file

@ -6,6 +6,7 @@ import de.avatic.lcc.dto.error.FrontendErrorDTO;
import de.avatic.lcc.model.error.SysError;
import de.avatic.lcc.model.error.SysErrorTraceItem;
import de.avatic.lcc.model.error.SysErrorType;
import de.avatic.lcc.service.users.AuthorizationService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
@ -19,9 +20,14 @@ public class SysErrorTransformer {
private static final String TRACE_REGEX = "at\\s+(?:async\\s+)?(?:(.+?)\\s+)?\\(([^?]+(?:\\?[^:]*)?):(\\d+):\\d+\\)";
private static final Pattern TRACE_REGEX_PATTERN = Pattern.compile(TRACE_REGEX);
private final AuthorizationService authorizationService;
public SysErrorTransformer(AuthorizationService authorizationService) {
this.authorizationService = authorizationService;
}
public SysError toSysErrorEntity(FrontendErrorDTO frontendErrorDTO) {
int userId = 1; //TODO use actual user
var userId = authorizationService.getUserId();
SysError entity = new SysError();

View file

@ -0,0 +1,46 @@
package de.avatic.lcc.service.users;
import de.avatic.lcc.config.LccOidcUser;
import de.avatic.lcc.dto.users.UserDTO;
import de.avatic.lcc.model.users.User;
import de.avatic.lcc.repositories.users.UserRepository;
import de.avatic.lcc.service.transformer.users.UserTransformer;
import de.avatic.lcc.util.exception.base.ForbiddenException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
@Service
public class AuthorizationService {
private final UserRepository userRepository;
private final UserTransformer userTransformer;
public AuthorizationService(UserRepository userRepository, UserTransformer userTransformer) {
this.userRepository = userRepository;
this.userTransformer = userTransformer;
}
public UserDTO getActiveUser() {
var id = getUserId();
return id == null ? null : userTransformer.toUserDTO(userRepository.getById(id));
}
public Integer getUserId() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth.getPrincipal() instanceof LccOidcUser user) {
return user.getSqlUserId();
}
throw new ForbiddenException("No user found");
}
public boolean isSuper() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (auth.getPrincipal() instanceof LccOidcUser user) {
return user.getAuthorities().stream().anyMatch(authority -> authority.getAuthority().equals("ROLE_SUPER"));
}
throw new ForbiddenException("No user found");
}
}