Compare commits

...

3 Commits

Author SHA1 Message Date
Meutel ae4214c6ed Oauth2 2023-10-29 11:57:24 +01:00
Meutel f49301f200 lombok 2023-10-29 11:19:07 +01:00
Meutel ceb51e5351 Steps 2023-10-29 10:55:59 +01:00
19 changed files with 193 additions and 222 deletions

3
api/.gitignore vendored
View File

@ -31,3 +31,6 @@ build/
### VS Code ###
.vscode/
### secrets
/src/main/resources/application-secured.properties

View File

@ -21,6 +21,8 @@
<mapstruct.version>1.5.5.Final</mapstruct.version>
<openapi-generator.version>6.2.1</openapi-generator.version>
<findbugs.version>3.0.2</findbugs.version>
<lombok.version>1.18.30</lombok.version>
<lombok.mapstruct.version>0.2.0</lombok.mapstruct.version>
</properties>
<dependencies>
<dependency>
@ -51,6 +53,10 @@
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
<!--SpringDoc
dependencies -->
<dependency>
@ -86,6 +92,12 @@
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
@ -104,6 +116,16 @@
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok-mapstruct-binding</artifactId>
<version>${lombok.mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>

View File

@ -0,0 +1,19 @@
package net.meutel.recettes.api;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
public class RecettesSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.oauth2Login();
return http.build();
}
}

View File

@ -2,18 +2,17 @@ package net.meutel.recettes.api.controller;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RestController;
import lombok.extern.slf4j.Slf4j;
import net.meutel.recettes.api.ParametersApi;
import net.meutel.recettes.api.model.RecetteParam;
import net.meutel.recettes.api.service.ParametersService;
@Slf4j
@RestController
public class ParameterController implements ParametersApi {
private final Logger LOG = LoggerFactory.getLogger(ParameterController.class);
private final ParametersService service;
@ -23,7 +22,7 @@ public class ParameterController implements ParametersApi {
@Override
public ResponseEntity<List<RecetteParam>> listRecetteParamsByType(String paramType) {
LOG.info("list params: " + paramType);
log.info("list params: " + paramType);
return ResponseEntity.ok(service.loadAllParameters(paramType));
}

View File

@ -2,33 +2,15 @@ package net.meutel.recettes.api.entity;
import java.math.BigDecimal;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class QuantityEntity {
private BigDecimal value;
private String unit;
@Override
public String toString() {
return "QuantityEntity [value=" + value + ", unit=" + unit + "]";
}
public BigDecimal getValue() {
return value;
}
public void setValue(BigDecimal value) {
this.value = value;
}
public String getUnit() {
return unit;
}
public void setUnit(String unit) {
this.unit = unit;
}
}

View File

@ -5,6 +5,11 @@ import java.util.List;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
@Document("receipes")
public class ReceipeEntity {
@ -17,60 +22,6 @@ public class ReceipeEntity {
private String author;
private ReceipeYieldEntity receipeYield;
private List<ReceipeIngredientEntity> ingredients;
private List<ReceipeStepEntity> steps;
@Override
public String toString() {
return "ReceipeEntity [id=" + id + ", name=" + name + ", description=" + description + ", cookTime=" + cookTime
+ ", prepTime=" + prepTime + ", author=" + author + ", receipeYield=" + receipeYield + ", ingredients="
+ ingredients + "]";
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getCookTime() {
return cookTime;
}
public void setCookTime(String cookTime) {
this.cookTime = cookTime;
}
public String getPrepTime() {
return prepTime;
}
public void setPrepTime(String prepTime) {
this.prepTime = prepTime;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public ReceipeYieldEntity getReceipeYield() {
return receipeYield;
}
public void setReceipeYield(ReceipeYieldEntity receipeYield) {
this.receipeYield = receipeYield;
}
public List<ReceipeIngredientEntity> getIngredients() {
return ingredients;
}
public void setIngredients(List<ReceipeIngredientEntity> ingredients) {
this.ingredients = ingredients;
}
}

View File

@ -1,43 +1,16 @@
package net.meutel.recettes.api.entity;
import org.springframework.data.mongodb.core.mapping.DocumentReference;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class ReceipeIngredientEntity {
private QuantityEntity quantity;
private String text;
@DocumentReference(collection = "parameters")
private RecetteParamEntity ref;
@Override
public String toString() {
return "ReceipeIngredientEntity [quantity=" + quantity + ", text=" + text + ", ref=" + ref + "]";
}
public RecetteParamEntity getRef() {
return ref;
}
public void setRef(RecetteParamEntity ref) {
this.ref = ref;
}
public QuantityEntity getQuantity() {
return quantity;
}
public void setQuantity(QuantityEntity quantity) {
this.quantity = quantity;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
private String ref;
}

View File

@ -0,0 +1,16 @@
package net.meutel.recettes.api.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class ReceipeStepEntity {
private Integer position;
private String text;
private String hint;
}

View File

@ -1,32 +1,14 @@
package net.meutel.recettes.api.entity;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@Data
public class ReceipeYieldEntity {
private QuantityEntity quantity;
private String of;
@Override
public String toString() {
return "ReceipeYieldEntity [quantity=" + quantity + ", of=" + of + "]";
}
public QuantityEntity getQuantity() {
return quantity;
}
public void setQuantity(QuantityEntity quantity) {
this.quantity = quantity;
}
public String getOf() {
return of;
}
public void setOf(String of) {
this.of = of;
}
}

View File

@ -3,6 +3,11 @@ package net.meutel.recettes.api.entity;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@Document(collection = "parameters")
public class RecetteParamEntity {
@Id
@ -11,45 +16,5 @@ public class RecetteParamEntity {
public String _type;
public String name;
public RecetteParamEntity() {
}
public RecetteParamEntity(String id, String _type, String name) {
this.id = id;
this._type = _type;
this.name = name;
}
@Override
public String toString() {
return "RecetteParamEntity [id=" + id + ", _type=" + _type + ", name=" + name + "]";
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String get_type() {
return _type;
}
public void set_type(String _type) {
this._type = _type;
}
}

View File

@ -6,7 +6,7 @@ import org.mapstruct.Mapping;
import net.meutel.recettes.api.entity.ReceipeIngredientEntity;
import net.meutel.recettes.api.model.Ingredient;
@Mapper(componentModel = "spring", uses = {RecetteParamRefMapper.class})
@Mapper(componentModel = "spring")
public interface IngredientMapper {
Ingredient fromEntity(ReceipeIngredientEntity entity);

View File

@ -5,7 +5,7 @@ import org.mapstruct.Mapper;
import net.meutel.recettes.api.entity.ReceipeEntity;
import net.meutel.recettes.api.model.Receipe;
@Mapper(componentModel = "spring", uses = {IngredientMapper.class})
@Mapper(componentModel = "spring", uses = {IngredientMapper.class, StepMapper.class})
public interface ReceipeFullMapper {
Receipe fromEntity(ReceipeEntity entity);

View File

@ -11,9 +11,11 @@ public interface ReceipeSimplifiedMapper {
@Mapping(target = "ingredients", ignore = true)
@Mapping(target = "receipeYield", ignore = true)
@Mapping(target = "steps", ignore = true)
Receipe fromEntity(ReceipeEntity entity);
@Mapping(target = "ingredients", ignore = true)
@Mapping(target = "steps", ignore = true)
ReceipeEntity toEntity(Receipe model);
}

View File

@ -1,14 +0,0 @@
package net.meutel.recettes.api.mapper;
import org.mapstruct.Mapper;
import net.meutel.recettes.api.entity.RecetteParamEntity;
@Mapper(componentModel = "spring")
public interface RecetteParamRefMapper {
default String fromEntity(RecetteParamEntity entity) {
return entity.getId();
};
}

View File

@ -0,0 +1,14 @@
package net.meutel.recettes.api.mapper;
import org.mapstruct.Mapper;
import net.meutel.recettes.api.entity.ReceipeStepEntity;
import net.meutel.recettes.api.model.Step;
@Mapper(componentModel = "spring")
public interface StepMapper {
Step fromEntity(ReceipeStepEntity entity);
ReceipeStepEntity toEntity(Step model);
}

View File

@ -1,4 +1,24 @@
spring.profiles.active=secured
spring.data.mongodb.database=recettes
logging.level.org.springframework.data.mongodb=DEBUG
management.endpoint.health.show-details=always
spring.jackson.default-property-inclusion=non-null
#spring.security.oauth2.client.registration.gitea.client-id=
#spring.security.oauth2.client.registration.gitea.client-secret=
spring.security.oauth2.client.registration.gitea.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.gitea.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
# GITEA OAUTH2 PROVIDER
# OpenID Connect Discovery /.well-known/openid-configuration
# Authorization Endpoint /login/oauth/authorize
# Access Token Endpoint /login/oauth/access_token
# OpenID Connect UserInfo /login/oauth/userinfo
# JSON Web Key Set /login/oauth/keys
spring.security.oauth2.client.provider.gitea.authorization-uri=https://git.meutel.net/login/oauth/authorize
spring.security.oauth2.client.provider.gitea.token-uri=https://git.meutel.net/login/oauth/access_token
spring.security.oauth2.client.provider.gitea.jwk-set-uri=https://git.meutel.net/login/oauth/keys
spring.security.oauth2.client.provider.gitea.user-info-uri=https://git.meutel.net/login/oauth/userinfo
#spring.security.oauth2.client.provider.gitea.user-info-authentication-method=authorization_code
spring.security.oauth2.client.provider.gitea.userNameAttribute=sub

View File

@ -17,40 +17,46 @@ import net.meutel.recettes.api.repository.RecetteParamRepository;
@SpringBootTest
public class ParametersServiceImplTest {
@MockBean
RecetteParamRepository repo;
@MockBean
RecetteParamRepository repo;
@Autowired
ParametersService tested;
@Autowired
ParametersService tested;
@Test
void loadAllParameters_exists_list() {
var p1 = new RecetteParamEntity("1", "TEST", "p1");
var p2 = new RecetteParamEntity("2", "TEST", "p2");
@Test
void loadAllParameters_exists_list() {
var p1 = new RecetteParamEntity();
p1.setId("1");
p1.set_type("TEST");
p1.setName("p1");
var p2 = new RecetteParamEntity();
p2.setId("2");
p2.set_type("TEST");
p2.setName("p2");
when(repo.findBy_type("TEST"))
.thenReturn(List.of(p1, p2).stream());
when(repo.findBy_type("TEST"))
.thenReturn(List.of(p1, p2).stream());
var result = tested.loadAllParameters("TEST");
var result = tested.loadAllParameters("TEST");
assertThat(result)
.isNotNull()
.hasSize(2);
assertThat(result).element(0)
.returns("TEST", RecetteParam::getAtType)
.returns("p1", RecetteParam::getName);
assertThat(result).element(1)
.returns("TEST", RecetteParam::getAtType)
.returns("p2", RecetteParam::getName);
}
assertThat(result)
.isNotNull()
.hasSize(2);
assertThat(result).element(0)
.returns("TEST", RecetteParam::getAtType)
.returns("p1", RecetteParam::getName);
assertThat(result).element(1)
.returns("TEST", RecetteParam::getAtType)
.returns("p2", RecetteParam::getName);
}
@Test
void loadAllParameters_notExists_empty() {
var result = tested.loadAllParameters("TEST");
@Test
void loadAllParameters_notExists_empty() {
var result = tested.loadAllParameters("TEST");
assertThat(result)
.isNotNull()
.isEmpty();
}
assertThat(result)
.isNotNull()
.isEmpty();
}
}

View File

@ -16,11 +16,13 @@ import org.springframework.boot.test.mock.mockito.MockBean;
import net.meutel.recettes.api.entity.QuantityEntity;
import net.meutel.recettes.api.entity.ReceipeEntity;
import net.meutel.recettes.api.entity.ReceipeIngredientEntity;
import net.meutel.recettes.api.entity.ReceipeStepEntity;
import net.meutel.recettes.api.entity.ReceipeYieldEntity;
import net.meutel.recettes.api.exception.ItemNotFoundException;
import net.meutel.recettes.api.model.Ingredient;
import net.meutel.recettes.api.model.Receipe;
import net.meutel.recettes.api.model.ReceipeReceipeYield;
import net.meutel.recettes.api.model.Step;
import net.meutel.recettes.api.repository.ReceipeRepository;
@SpringBootTest
@ -66,6 +68,12 @@ public class ReceipeServiceImplTest {
.singleElement()
.extracting(Ingredient::getText)
.isEqualTo("Parmesan");
assertThat(result.getSteps())
.isNotNull();
assertThat(result.getSteps())
.singleElement()
.extracting(Step::getPosition, Step::getText, Step::getHint)
.contains(1, "Faire bouillir de l'eau", "attention aux explosions");
}
@Test
@ -114,6 +122,11 @@ public class ReceipeServiceImplTest {
i1.setQuantity(i1qty);
i1.setText("Parmesan");
r1.setIngredients(List.of(i1));
var step1 = new ReceipeStepEntity();
step1.setPosition(1);
step1.setText("Faire bouillir de l'eau");
step1.setHint("attention aux explosions");
r1.setSteps(List.of(step1));
return r1;
}

View File

@ -108,8 +108,9 @@ components:
type: object
required:
- id
- ingredients
- name
- ingredients
- steps
properties:
id:
description: Receipe unique id
@ -137,6 +138,10 @@ components:
type: array
items:
$ref: '#/components/schemas/Ingredient'
steps:
type: array
items:
$ref: '#/components/schemas/Step'
receipeYield:
description: Quantity produced by receipe
type: object
@ -162,6 +167,19 @@ components:
description: Link to ingredient parameter
type: string
format: url
Step:
description: Step in receipe
type: object
properties:
position:
description: position of step in receipe
type: integer
text:
description: step instruction
type: string
hint:
description: step hint
type: string
Quantity:
type: object
required: