Skip to content

Commit

Permalink
Merge pull request #96 from scc-digitalhub/models-entity
Browse files Browse the repository at this point in the history
Models
  • Loading branch information
matteo-s authored May 15, 2024
2 parents 55ecad0 + d572dcd commit 6a83ec2
Show file tree
Hide file tree
Showing 19 changed files with 1,601 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import it.smartcommunitylabdhub.commons.models.entities.dataitem.DataItem;
import it.smartcommunitylabdhub.commons.models.entities.function.Function;
import it.smartcommunitylabdhub.commons.models.entities.log.Log;
import it.smartcommunitylabdhub.commons.models.entities.model.Model;
import it.smartcommunitylabdhub.commons.models.entities.project.Project;
import it.smartcommunitylabdhub.commons.models.entities.run.Run;
import it.smartcommunitylabdhub.commons.models.entities.secret.Secret;
Expand All @@ -13,6 +14,7 @@
import it.smartcommunitylabdhub.core.models.entities.DataItemEntity;
import it.smartcommunitylabdhub.core.models.entities.FunctionEntity;
import it.smartcommunitylabdhub.core.models.entities.LogEntity;
import it.smartcommunitylabdhub.core.models.entities.ModelEntity;
import it.smartcommunitylabdhub.core.models.entities.ProjectEntity;
import it.smartcommunitylabdhub.core.models.entities.RunEntity;
import it.smartcommunitylabdhub.core.models.entities.SecretEntity;
Expand All @@ -22,6 +24,7 @@
import it.smartcommunitylabdhub.core.repositories.DataItemRepository;
import it.smartcommunitylabdhub.core.repositories.FunctionRepository;
import it.smartcommunitylabdhub.core.repositories.LogRepository;
import it.smartcommunitylabdhub.core.repositories.ModelRepository;
import it.smartcommunitylabdhub.core.repositories.ProjectRepository;
import it.smartcommunitylabdhub.core.repositories.RunRepository;
import it.smartcommunitylabdhub.core.repositories.SecretRepository;
Expand Down Expand Up @@ -63,6 +66,15 @@ public EntityService<DataItem, DataItemEntity> dataItemEntityService(
return new BaseEntityServiceImpl<>(repository, entityBuilder, dtoBuilder);
}

@Bean
public EntityService<Model, ModelEntity> modelEntityService(
ModelRepository repository,
Converter<Model, ModelEntity> entityBuilder,
Converter<ModelEntity, Model> dtoBuilder
) {
return new BaseEntityServiceImpl<>(repository, entityBuilder, dtoBuilder);
}

@Bean
public EntityService<Function, FunctionEntity> functionEntityService(
FunctionRepository repository,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package it.smartcommunitylabdhub.core.controllers.v1.base;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import it.smartcommunitylabdhub.commons.Keys;
import it.smartcommunitylabdhub.commons.exceptions.DuplicatedEntityException;
import it.smartcommunitylabdhub.commons.exceptions.NoSuchEntityException;
import it.smartcommunitylabdhub.commons.exceptions.SystemException;
import it.smartcommunitylabdhub.commons.models.entities.model.Model;
import it.smartcommunitylabdhub.commons.models.queries.SearchFilter;
import it.smartcommunitylabdhub.core.ApplicationKeys;
import it.smartcommunitylabdhub.core.annotations.ApiVersion;
import it.smartcommunitylabdhub.core.models.entities.ModelEntity;
import it.smartcommunitylabdhub.core.models.indexers.IndexableModelService;
import it.smartcommunitylabdhub.core.models.queries.filters.entities.ModelEntityFilter;
import it.smartcommunitylabdhub.core.models.queries.services.SearchableModelService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import javax.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindException;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@ApiVersion("v1")
@RequestMapping("/models")
//TODO evaluate permissions for project via lookup in dto
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
@Validated
@Slf4j
@Tag(name = "Model base API", description = "Endpoints related to models management out of the Context")
public class ModelController {

@Autowired
SearchableModelService modelService;

@Autowired
IndexableModelService indexService;

@Operation(summary = "Create model", description = "Create a model and return")
@PostMapping(
value = "",
consumes = { MediaType.APPLICATION_JSON_VALUE, "application/x-yaml" },
produces = "application/json; charset=UTF-8"
)
public Model createModel(@RequestBody @Valid @NotNull Model dto)
throws DuplicatedEntityException, SystemException, IllegalArgumentException, BindException {
return modelService.createModel(dto);
}

@Operation(summary = "List models", description = "Return a list of all models")
@GetMapping(path = "", produces = "application/json; charset=UTF-8")
public Page<Model> getModels(
@ParameterObject @Valid @Nullable ModelEntityFilter filter,
@ParameterObject @RequestParam(required = false, defaultValue = "all") String versions,
@ParameterObject @PageableDefault(page = 0, size = ApplicationKeys.DEFAULT_PAGE_SIZE) @SortDefault.SortDefaults(
{ @SortDefault(sort = "created", direction = Direction.DESC) }
) Pageable pageable
) {
SearchFilter<ModelEntity> sf = null;
if (filter != null) {
sf = filter.toSearchFilter();
}
if ("latest".equals(versions)) {
return modelService.searchLatestModels(pageable, sf);
} else {
return modelService.searchModels(pageable, sf);
}
}

@Operation(summary = "Get a model by id", description = "Return a model")
@GetMapping(path = "/{id}", produces = "application/json; charset=UTF-8")
public Model getModel(@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String id)
throws NoSuchEntityException {
return modelService.getModel(id);
}

@Operation(summary = "Update specific model", description = "Update and return the model")
@PutMapping(
path = "/{id}",
consumes = { MediaType.APPLICATION_JSON_VALUE, "application/x-yaml" },
produces = "application/json; charset=UTF-8"
)
public Model updateModel(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String id,
@RequestBody @Valid @NotNull Model dto
) throws NoSuchEntityException, SystemException, IllegalArgumentException, BindException {
return modelService.updateModel(id, dto);
}

@Operation(summary = "Delete a model", description = "Delete a specific model")
@DeleteMapping(path = "/{id}")
public void deleteModel(@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String id) {
modelService.deleteModel(id);
}

/*
* Search apis
*/
@PreAuthorize("hasAuthority('ROLE_ADMIN')")
@Operation(summary = "Reindex all models", description = "Reindex models")
@PostMapping(value = "/search/reindex", produces = "application/json; charset=UTF-8")
public void reindexModels() {
//via async
indexService.reindexModels();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package it.smartcommunitylabdhub.core.controllers.v1.context;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import it.smartcommunitylabdhub.commons.Keys;
import it.smartcommunitylabdhub.commons.exceptions.DuplicatedEntityException;
import it.smartcommunitylabdhub.commons.exceptions.NoSuchEntityException;
import it.smartcommunitylabdhub.commons.exceptions.SystemException;
import it.smartcommunitylabdhub.commons.models.entities.model.Model;
import it.smartcommunitylabdhub.commons.models.queries.SearchFilter;
import it.smartcommunitylabdhub.core.ApplicationKeys;
import it.smartcommunitylabdhub.core.annotations.ApiVersion;
import it.smartcommunitylabdhub.core.models.entities.ModelEntity;
import it.smartcommunitylabdhub.core.models.queries.filters.entities.ModelEntityFilter;
import it.smartcommunitylabdhub.core.models.queries.services.SearchableModelService;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import javax.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
import org.springdoc.core.annotations.ParameterObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.BindException;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@ApiVersion("v1")
@RequestMapping("/-/{project}/models")
@PreAuthorize(
"hasAuthority('ROLE_ADMIN') or (hasAuthority(#project+':ROLE_USER') or hasAuthority(#project+':ROLE_ADMIN'))"
)
@Validated
@Slf4j
@Tag(name = "Model context API", description = "Endpoints related to models management in project")
public class ModelContextController {

@Autowired
SearchableModelService modelService;

@Operation(summary = "Create a model in a project context")
@PostMapping(
value = "",
consumes = { MediaType.APPLICATION_JSON_VALUE, "application/x-yaml" },
produces = "application/json; charset=UTF-8"
)
public Model createModel(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String project,
@Valid @NotNull @RequestBody Model dto
) throws DuplicatedEntityException, SystemException, IllegalArgumentException, BindException {
//enforce project match
dto.setProject(project);

//create as new
return modelService.createModel(dto);
}

@Operation(summary = "Search models")
@GetMapping(path = "", produces = "application/json; charset=UTF-8")
public Page<Model> searchModels(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String project,
@ParameterObject @Valid @Nullable ModelEntityFilter filter,
@ParameterObject @RequestParam(required = false, defaultValue = "latest") String versions,
@ParameterObject @PageableDefault(page = 0, size = ApplicationKeys.DEFAULT_PAGE_SIZE) @SortDefault.SortDefaults(
{ @SortDefault(sort = "created", direction = Direction.DESC) }
) Pageable pageable
) {
SearchFilter<ModelEntity> sf = null;
if (filter != null) {
sf = filter.toSearchFilter();
}

if ("all".equals(versions)) {
return modelService.searchModelsByProject(project, pageable, sf);
} else {
return modelService.searchLatestModelsByProject(project, pageable, sf);
}
}

@Operation(summary = "Delete all version of a model")
@DeleteMapping(path = "")
public void deleteAllModel(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String project,
@ParameterObject @RequestParam @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String name
) {
modelService.deleteModels(project, name);
}

/*
* Versions
*/

@Operation(summary = "Retrieve a specific model version given the model id")
@GetMapping(path = "/{id}", produces = "application/json; charset=UTF-8")
public Model getModelById(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String project,
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String id
) throws NoSuchEntityException {
Model model = modelService.getModel(id);

//check for project and name match
if (!model.getProject().equals(project)) {
throw new IllegalArgumentException("invalid project");
}

return model;
}

@Operation(summary = "Update if exist a model in a project context")
@PutMapping(
value = "/{id}",
consumes = { MediaType.APPLICATION_JSON_VALUE, "application/x-yaml" },
produces = "application/json; charset=UTF-8"
)
public Model updateModelById(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String project,
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String id,
@RequestBody @Valid @NotNull Model modelDTO
) throws NoSuchEntityException, SystemException, IllegalArgumentException, BindException {
Model model = modelService.getModel(id);

//check for project and name match
if (!model.getProject().equals(project)) {
throw new IllegalArgumentException("invalid project");
}

return modelService.updateModel(id, modelDTO);
}

@Operation(
summary = "Delete a specific model version",
description = "First check if project exist, then delete a specific model version"
)
@DeleteMapping(path = "/{id}")
public void deleteModelById(
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String project,
@PathVariable @Valid @NotNull @Pattern(regexp = Keys.SLUG_PATTERN) String id
) throws NoSuchEntityException {
Model model = modelService.getModel(id);

//check for project and name match
if (!model.getProject().equals(project)) {
throw new IllegalArgumentException("invalid project");
}

modelService.deleteModel(id);
}
}
Loading

0 comments on commit 6a83ec2

Please sign in to comment.