From 9d41bd7c44a33bef25a9ada9787bc335b0459145 Mon Sep 17 00:00:00 2001 From: "fabio.d.mota" Date: Tue, 10 Oct 2023 17:34:41 +0100 Subject: [PATCH] fix(Country Risk Documentation): Add new DTOS and change dtos from controller --- CHANGELOG.md | 1 + docs/swagger/dashboard_controller.yml | 59 ++++---- docs/swagger/sharing_controller.yml | 137 ++++++++---------- .../InputSharingBusinessPartnerDTO.java | 58 ++++++++ .../ShareDTOs/InputSharingDataSourceDTO.java | 67 +++++++++ .../dto/ShareDTOs/ShareDTO.java | 2 + .../dto/ShareDTOs/ShareRatingDTO.java | 3 + .../service/DashboardService.java | 6 +- .../service/logic/ShareLogicService.java | 15 +- .../web/rest/SharingResource.java | 7 +- src/main/resources/config/application.yml | 4 +- 11 files changed, 239 insertions(+), 120 deletions(-) create mode 100644 src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingBusinessPartnerDTO.java create mode 100644 src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingDataSourceDTO.java diff --git a/CHANGELOG.md b/CHANGELOG.md index e281c9d0..5ab72b82 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed Dependencies file with new library versions. - Changed Mapping to adapt new Data Model on BPDM Gate - Enable Hidden endpoints for Sharing Controller +- Change Dtos of Sharing Controllers ### Fixes diff --git a/docs/swagger/dashboard_controller.yml b/docs/swagger/dashboard_controller.yml index 3a942e52..0d7ff710 100644 --- a/docs/swagger/dashboard_controller.yml +++ b/docs/swagger/dashboard_controller.yml @@ -154,6 +154,7 @@ paths: type: array items: $ref: '#/components/schemas/RangeDTO' + maxItems: 3 required: true responses: '200': @@ -227,6 +228,7 @@ paths: type: array items: $ref: '#/components/schemas/DataSourceDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -246,6 +248,7 @@ paths: type: array items: $ref: '#/components/schemas/RatingDTO' + maxItems: 20 default: [] - name: companyUser in: query @@ -268,6 +271,7 @@ paths: type: array items: $ref: '#/components/schemas/DashBoardWorldMapDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -294,6 +298,7 @@ paths: type: array items: $ref: '#/components/schemas/RangeDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -320,6 +325,7 @@ paths: type: array items: $ref: '#/components/schemas/CompanyUserDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -347,6 +353,7 @@ paths: items: type: string format: byte + maxItems: 20 '401': description: Authentication Required security: @@ -367,6 +374,7 @@ paths: items: $ref: '#/components/schemas/RatingDTO' default: [] + maxItems: 20 - name: year in: query required: false @@ -388,6 +396,7 @@ paths: type: array items: $ref: '#/components/schemas/DashBoardTableDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -419,6 +428,7 @@ paths: type: array items: $ref: '#/components/schemas/ReportValuesDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -445,6 +455,7 @@ paths: type: array items: $ref: '#/components/schemas/ReportDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -471,6 +482,7 @@ paths: type: array items: $ref: '#/components/schemas/CountryDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -497,6 +509,7 @@ paths: type: array items: $ref: '#/components/schemas/BusinessPartnerDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -523,6 +536,7 @@ paths: type: array items: $ref: '#/components/schemas/CountryDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -549,6 +563,7 @@ paths: type: array items: $ref: '#/components/schemas/CompanyGatesDTO' + maxItems: 20 '401': description: Authentication Required security: @@ -576,6 +591,7 @@ paths: items: type: integer format: int32 + maxItems: 20 '401': description: Authentication Required security: @@ -666,6 +682,7 @@ components: type: array items: $ref: '#/components/schemas/ReportValuesDTO' + maxItems: 20 ReportValuesDTO: type: object properties: @@ -767,7 +784,7 @@ components: example: '633104' city: type: string - example: Covilhã + example: Covilha country: type: string example: Portugal @@ -783,35 +800,6 @@ components: customer: type: boolean example: true - ShareDTO: - type: object - properties: - id: - type: integer - format: int64 - bpn: - type: string - example: BPN-NUMBER - country: - type: string - example: Portugal - iso2: - type: string - example: PT - rating: - type: array - items: - $ref: '#/components/schemas/ShareRatingDTO' - ShareRatingDTO: - type: object - properties: - dataSourceName: - type: string - example: Fake Rating - score: - type: number - format: float - example: 100 RatingDTO: type: object properties: @@ -840,9 +828,13 @@ components: type: string example: Germany iso3: + maxLength: 2 + minLength: 0 type: string example: DEU iso2: + maxLength: 3 + minLength: 0 type: string example: DE continent: @@ -890,7 +882,7 @@ components: example: '633104' city: type: string - example: Covilhã + example: Covilha country: type: string example: Portugal @@ -933,7 +925,12 @@ components: authorizationCode: authorizationUrl: https://centralidp.dev.demo.catena-x.net/auth/realms/CX-Central/protocol/openid-connect/auth tokenUrl: https://centralidp.dev.demo.catena-x.net/auth/realms/CX-Central/protocol/openid-connect/token + scopes: + read: Grants read access + write: Grants write access + admin: Grants access to admin operations bearerAuth: type: http scheme: bearer bearerFormat: JWT + diff --git a/docs/swagger/sharing_controller.yml b/docs/swagger/sharing_controller.yml index 2ca8f41a..526308b2 100644 --- a/docs/swagger/sharing_controller.yml +++ b/docs/swagger/sharing_controller.yml @@ -55,7 +55,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/DataSourceDTO' + $ref: '#/components/schemas/InputSharingDataSourceDTO' maxItems: 20 default: [] - name: bpns[] @@ -64,7 +64,7 @@ paths: schema: type: array items: - $ref: '#/components/schemas/BusinessPartnerDTO' + $ref: '#/components/schemas/InputSharingBusinessPartnerDTO' maxItems: 20 default: [] - name: companyUser @@ -94,91 +94,44 @@ paths: - Sharing Controller components: schemas: - BusinessPartnerDTO: - additionalProperties: false - properties: - bpn: - example: BPN-NUMBER - type: string - city: - example: Covilha - type: string - country: - example: Portugal - type: string - customer: - example: true - type: boolean - houseNumber: - example: Sutteridge - type: string - id: - format: int64 - type: integer - latitude: - example: '-6.6889038' - type: string - legalName: - example: Divape Company - type: string - longitude: - example: '107.6185727' - type: string - street: - example: 1st - type: string - supplier: - example: false - type: boolean - zipCode: - example: '633104' - type: string - type: object CompanyUserDTO: - additionalProperties: false - properties: - companyName: - example: TestCompany - type: string - email: - example: John@email.com - type: string - name: - example: John - type: string required: - companyName - email - name type: object - DataSourceDTO: - additionalProperties: false properties: - dataSourceName: - example: Fake Rating + name: type: string - fileName: - example: Test Company Rating + example: John + email: type: string - id: - format: int64 - type: integer - type: - enum: - - Global - - Custom - - Company - example: Custom + example: John@email.com + companyName: type: string - yearPublished: - example: 2021 - format: int32 - type: integer + example: TestCompany + InputSharingDataSourceDTO: required: - dataSourceName - - type - yearPublished type: object + properties: + dataSourceName: + type: string + example: Fake Rating + yearPublished: + type: integer + format: int32 + example: 2021 + InputSharingBusinessPartnerDTO: + type: object + properties: + bpn: + type: string + example: BPN-NUMBER + country: + type: string + example: Portugal ShareDTO: additionalProperties: false properties: @@ -202,16 +155,46 @@ components: type: array type: object ShareRatingDTO: - additionalProperties: false + type: object properties: dataSourceName: - example: Fake Rating type: string + example: Fake Rating score: - example: 100 - format: float type: number + format: float + example: 100 + yearPublished: + type: integer + format: int32 + example: 2021 + DataSourceDTO: + required: + - dataSourceName + - type + - yearPublished type: object + properties: + id: + type: integer + format: int64 + dataSourceName: + type: string + example: Fake Rating + type: + type: string + example: Custom + enum: + - Global + - Custom + - Company + yearPublished: + type: integer + format: int32 + example: 2021 + fileName: + type: string + example: Test Company Rating securitySchemes: bearerAuth: bearerFormat: JWT diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingBusinessPartnerDTO.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingBusinessPartnerDTO.java new file mode 100644 index 00000000..507b8802 --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingBusinessPartnerDTO.java @@ -0,0 +1,58 @@ +/******************************************************************************** +* Copyright (c) 2022,2023 BMW Group AG +* Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* This program and the accompanying materials are made available under the +* terms of the Apache License, Version 2.0 which is available at +* https://www.apache.org/licenses/LICENSE-2.0. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +* +* SPDX-License-Identifier: Apache-2.0 +********************************************************************************/ +package org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.*; + +import java.io.Serializable; + + +@Setter +@Getter +@ToString +@AllArgsConstructor(access = AccessLevel.PUBLIC) +@NoArgsConstructor(access = AccessLevel.PUBLIC) +public class InputSharingBusinessPartnerDTO implements Serializable { + + @Schema(example = "BPN-NUMBER") + private String bpn; + + @Schema(example = "Portugal") + private String country; + + + public InputSharingBusinessPartnerDTO(String json) { + + try { + InputSharingBusinessPartnerDTO businessPartnerDTO = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readValue(json, InputSharingBusinessPartnerDTO.class); + this.bpn = businessPartnerDTO.getBpn(); + this.country = businessPartnerDTO.getCountry(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + } + +} diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingDataSourceDTO.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingDataSourceDTO.java new file mode 100644 index 00000000..82754431 --- /dev/null +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/InputSharingDataSourceDTO.java @@ -0,0 +1,67 @@ +/******************************************************************************** +* Copyright (c) 2022,2023 BMW Group AG +* Copyright (c) 2022,2023 Contributors to the Eclipse Foundation +* +* See the NOTICE file(s) distributed with this work for additional +* information regarding copyright ownership. +* +* This program and the accompanying materials are made available under the +* terms of the Apache License, Version 2.0 which is available at +* https://www.apache.org/licenses/LICENSE-2.0. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +* License for the specific language governing permissions and limitations +* under the License. +* +* SPDX-License-Identifier: Apache-2.0 +********************************************************************************/ +package org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import lombok.ToString; +import org.eclipse.tractusx.valueaddedservice.domain.DataSource; + +import javax.validation.constraints.NotNull; +import java.io.Serializable; + + +/** + * A DTO for the {@link DataSource} entity. + */ +@Setter +@Getter +@ToString +@NoArgsConstructor +@JsonIgnoreProperties("companyUser") +public class InputSharingDataSourceDTO implements Serializable { + + @Schema(example = "Fake Rating") + @NotNull + private String dataSourceName; + + @Schema(example = "2021") + @NotNull + private Integer yearPublished; + + public InputSharingDataSourceDTO(String json) { + + try { + InputSharingDataSourceDTO dataSourceDTO = new ObjectMapper() + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false).readValue(json, InputSharingDataSourceDTO.class); + this.dataSourceName = dataSourceDTO.getDataSourceName(); + this.yearPublished = dataSourceDTO.getYearPublished(); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + + } +} diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareDTO.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareDTO.java index 263851bb..8de85cc2 100644 --- a/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareDTO.java +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareDTO.java @@ -19,6 +19,7 @@ ********************************************************************************/ package org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs; +import com.fasterxml.jackson.annotation.JsonIgnore; import io.swagger.v3.oas.annotations.media.Schema; import lombok.*; @@ -33,6 +34,7 @@ @NoArgsConstructor(access = AccessLevel.PUBLIC) public class ShareDTO implements Serializable { + @JsonIgnore private Long id; @Schema(example = "BPN-NUMBER") diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareRatingDTO.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareRatingDTO.java index ea00bdb9..21c9b870 100644 --- a/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareRatingDTO.java +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/dto/ShareDTOs/ShareRatingDTO.java @@ -41,4 +41,7 @@ public class ShareRatingDTO implements Serializable { @Schema(example = "100") private Float score = 0F; + @Schema(example = "2021") + private Integer yearPublished; + } \ No newline at end of file diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/service/DashboardService.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/service/DashboardService.java index 95bbe4da..6eae018b 100644 --- a/src/main/java/org/eclipse/tractusx/valueaddedservice/service/DashboardService.java +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/service/DashboardService.java @@ -23,6 +23,8 @@ import org.eclipse.tractusx.valueaddedservice.config.ApplicationVariables; import org.eclipse.tractusx.valueaddedservice.domain.DataSource; import org.eclipse.tractusx.valueaddedservice.dto.*; +import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.InputSharingBusinessPartnerDTO; +import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.InputSharingDataSourceDTO; import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.ShareDTO; import org.eclipse.tractusx.valueaddedservice.service.logic.*; import org.springframework.beans.factory.annotation.Autowired; @@ -30,6 +32,8 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -174,7 +178,7 @@ public List findRatingsByYearAndCompanyUserCompany(Integer year, return dataSourceDTOList; } - public List findRatingsScoresForEachBpn(List datasource, List businessPartner, CompanyUserDTO companyUser) { + public List findRatingsScoresForEachBpn(@NotNull @Valid List datasource, @NotNull @Valid List businessPartner, CompanyUserDTO companyUser) { return shareLogicService.findRatingsScoresForEachBpn(datasource, businessPartner ,companyUser,applicationVariables.getToken(), applicationVariables.getAuthPropertiesDTO().getRoles(applicationVariables.getAuthPropertiesDTO().getClientResource())); } diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/service/logic/ShareLogicService.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/service/logic/ShareLogicService.java index d32af78f..777c8196 100644 --- a/src/main/java/org/eclipse/tractusx/valueaddedservice/service/logic/ShareLogicService.java +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/service/logic/ShareLogicService.java @@ -23,13 +23,16 @@ import org.eclipse.tractusx.valueaddedservice.dto.BusinessPartnerDTO; import org.eclipse.tractusx.valueaddedservice.dto.CompanyUserDTO; import org.eclipse.tractusx.valueaddedservice.dto.DataDTO; -import org.eclipse.tractusx.valueaddedservice.dto.DataSourceDTO; +import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.InputSharingBusinessPartnerDTO; +import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.InputSharingDataSourceDTO; import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.ShareDTO; import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.ShareRatingDTO; import org.eclipse.tractusx.valueaddedservice.service.DataSourceValueService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.validation.Valid; +import javax.validation.constraints.NotNull; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -48,8 +51,8 @@ public class ShareLogicService { @Autowired BusinessPartnersLogicService businessPartnersLogicService; - public List findRatingsScoresForEachBpn(List datasource, List businessPartnerToMap, CompanyUserDTO companyUser, - String token,List roles) { + public List findRatingsScoresForEachBpn(@NotNull @Valid List datasource, @NotNull @Valid List businessPartnerToMap, CompanyUserDTO companyUser, + String token, List roles) { List shareDTOSList = new ArrayList<>(); @@ -67,9 +70,9 @@ public List findRatingsScoresForEachBpn(List datasource }); List countryList = new ArrayList<>();; - countryList.addAll(businessPartnerToMap.stream().map(BusinessPartnerDTO::getCountry).collect(Collectors.toSet())); + countryList.addAll(businessPartnerToMap.stream().map(InputSharingBusinessPartnerDTO::getCountry).collect(Collectors.toSet())); - List dataSources = datasource.stream().map(DataSourceDTO::getDataSourceName).collect(Collectors.toList()); + List dataSources = datasource.stream().map(InputSharingDataSourceDTO::getDataSourceName).collect(Collectors.toList()); List dataDTOS = new ArrayList<>(); datasource.forEach(ds -> { @@ -89,7 +92,7 @@ public List findRatingsScoresForEachBpn(List datasource return shareDTOSList; } - private ShareDTO setShareDTO(BusinessPartnerDTO bp, List dataDTOS, Integer id ) { + private ShareDTO setShareDTO(InputSharingBusinessPartnerDTO bp, List dataDTOS, Integer id ) { List shareRatingDTOList = new ArrayList<>(); ShareDTO shareDTO = new ShareDTO(); shareDTO.setId(Long.valueOf(id)); diff --git a/src/main/java/org/eclipse/tractusx/valueaddedservice/web/rest/SharingResource.java b/src/main/java/org/eclipse/tractusx/valueaddedservice/web/rest/SharingResource.java index 1999f269..2fff93e2 100644 --- a/src/main/java/org/eclipse/tractusx/valueaddedservice/web/rest/SharingResource.java +++ b/src/main/java/org/eclipse/tractusx/valueaddedservice/web/rest/SharingResource.java @@ -28,9 +28,10 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirements; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.extern.slf4j.Slf4j; -import org.eclipse.tractusx.valueaddedservice.dto.BusinessPartnerDTO; import org.eclipse.tractusx.valueaddedservice.dto.CompanyUserDTO; import org.eclipse.tractusx.valueaddedservice.dto.DataSourceDTO; +import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.InputSharingBusinessPartnerDTO; +import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.InputSharingDataSourceDTO; import org.eclipse.tractusx.valueaddedservice.dto.ShareDTOs.ShareDTO; import org.eclipse.tractusx.valueaddedservice.service.DashboardService; import org.springframework.beans.factory.annotation.Autowired; @@ -73,8 +74,8 @@ public ResponseEntity> getAllRatingsForCompany(@RequestParam @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Ratings of inserted custom year retrieved with success"), @ApiResponse(responseCode = "401", description = "Authentication Required", content = @Content)}) @GetMapping("/sharing/getAllRatingsScoresForEachBpn") - public ResponseEntity> getAllRatingsScoresForEachBpn(@NotNull @Parameter(name = "datasource[]", description = "", required = true) @Valid @RequestParam(value = "datasource[]", required = true) List datasource, - @NotNull @Parameter(name = "bpns[]", description = "", required = true) @Valid @RequestParam(value = "bpns[]", required = true) List businessPartnerDTOS, + public ResponseEntity> getAllRatingsScoresForEachBpn(@NotNull @Parameter(name = "datasource[]", description = "", required = true) @Valid @RequestParam(value = "datasource[]", required = true) List datasource, + @NotNull @Parameter(name = "bpns[]", description = "", required = true) @Valid @RequestParam(value = "bpns[]", required = true) List businessPartnerDTOS, CompanyUserDTO companyUserDTO) { log.debug( "REST request to retrieve Mapped ratings to the Business Partners based on inserted year, Company User, Ratings, BPN"); List shareDTOS; diff --git a/src/main/resources/config/application.yml b/src/main/resources/config/application.yml index 6d610e68..d1553715 100644 --- a/src/main/resources/config/application.yml +++ b/src/main/resources/config/application.yml @@ -34,8 +34,8 @@ vas: url: http://localhost:8081 keycloak: - clientId: - clientSecret: + clientId: test + clientSecret: test clientName: country-risk-client authentication-url: token-url: ${vas.auth.url}/auth/realms/CX-Central/protocol/openid-connect/token