diff --git a/service/src/structure_comparer/data/mapping.py b/service/src/structure_comparer/data/mapping.py index c1fc229..f29d5e0 100644 --- a/service/src/structure_comparer/data/mapping.py +++ b/service/src/structure_comparer/data/mapping.py @@ -113,7 +113,12 @@ def classify_remark_field( if self.action in EXTRA_ACTIONS: # Cut away the common part with the parent and add the remainder to the parent's extra - self.other = parent_update.other + self.name[len(self.name_parent) :] + if parent_update.other is not None: + self.other = ( + parent_update.other + self.name[len(self.name_parent) :] + ) + else: + raise ValueError("Error with the data: parent_update.other is None") self.remark = REMARKS[self.action].format(self.other) # Else use the parent's remark diff --git a/service/src/structure_comparer/data/profile.py b/service/src/structure_comparer/data/profile.py index b954c02..a4c578a 100644 --- a/service/src/structure_comparer/data/profile.py +++ b/service/src/structure_comparer/data/profile.py @@ -165,7 +165,7 @@ def ref_types(self) -> list[str]: [ p for t in self.__data.type - if t.code == "Reference" + if t.code == "Reference" and t.targetProfile is not None for p in t.targetProfile ] if self.__data.type is not None diff --git a/service/src/structure_comparer/data/project.py b/service/src/structure_comparer/data/project.py index f840e42..a10775e 100644 --- a/service/src/structure_comparer/data/project.py +++ b/service/src/structure_comparer/data/project.py @@ -23,7 +23,7 @@ def __init__(self, path: Path): self.__load_packages() self.load_comparisons() - self.__load_mappings() + self.load_mappings() self.__read_manual_entries() def __load_packages(self) -> None: @@ -53,7 +53,7 @@ def load_comparisons(self): c.id: Comparison(c, self).init_ext() for c in self.config.comparisons } - def __load_mappings(self): + def load_mappings(self): self.mappings = { m.id: Mapping(m, self).init_ext() for m in self.config.mappings } diff --git a/service/src/structure_comparer/handler/mapping.py b/service/src/structure_comparer/handler/mapping.py index 9b9ca65..b27522a 100644 --- a/service/src/structure_comparer/handler/mapping.py +++ b/service/src/structure_comparer/handler/mapping.py @@ -1,4 +1,6 @@ +from datetime import datetime from typing import List +from uuid import uuid4 from ..action import Action from ..data.mapping import MappingField @@ -14,11 +16,16 @@ from ..helpers import get_field_by_name from ..model.manual_entries import ManualEntriesMapping from ..model.mapping import MappingBase as MappingBaseModel +from ..model.mapping import MappingCreate as MappingCreateModel from ..model.mapping import MappingDetails as MappingDetailsModel from ..model.mapping import MappingField as MappingFieldModel from ..model.mapping import MappingFieldBase as MappingFieldBaseModel from ..model.mapping import MappingFieldMinimal as MappingFieldMinimalModel from ..model.mapping import MappingFieldsOutput as MappingFieldsOutputModel +from ..data.config import MappingConfig as MappingConfigModel +from ..data.config import ComparisonProfilesConfig as ComparisonProfilesConfigModel +from ..data.config import ComparisonProfileConfig as ComparisonProfileConfigModel +from ..data.mapping import Mapping as MappingModel from .project import ProjectsHandler @@ -126,6 +133,39 @@ def set_field( return new_entry + def create_new( + self, project_key, mapping: MappingCreateModel + ) -> MappingDetailsModel: + proj = self.project_handler._get(project_key) + if proj is None: + raise ProjectNotFound() + + new_mappingConfig = MappingConfigModel( + id=str(uuid4()), + version="1.0", + last_updated=datetime.now().isoformat(), + status="active", + mappings=ComparisonProfilesConfigModel( + sourceprofiles=[ + self._to_profiles_config(id) for id in mapping.source_ids + ], + targetprofile=self._to_profiles_config(mapping.target_id), + ), + ) + new_mapping = MappingModel(new_mappingConfig, proj) + new_mapping.fill_action_remark(proj.manual_entries) + + proj.config.mappings.append(new_mappingConfig) + proj.write_config() + proj.load_mappings() + + mapping = proj.mappings.get(new_mapping.id) + return mapping.to_details_model() + + def _to_profiles_config(self, url: str) -> ComparisonProfileConfigModel: + url, version = url.split("|") + return ComparisonProfileConfigModel(url=url, version=version) + def __get(self, project_key, mapping_id, proj: Project | None = None): if proj is None: proj = self.project_handler._get(project_key) diff --git a/service/src/structure_comparer/model/mapping.py b/service/src/structure_comparer/model/mapping.py index f01c7b2..657ab1e 100644 --- a/service/src/structure_comparer/model/mapping.py +++ b/service/src/structure_comparer/model/mapping.py @@ -37,6 +37,11 @@ class MappingBase(BaseModel): target: Profile +class MappingCreate(BaseModel): + source_ids: list[str] + target_id: str + + class MappingDetails(MappingBase): fields: list[MappingField] diff --git a/service/src/structure_comparer/serve.py b/service/src/structure_comparer/serve.py index 05eb328..5f3568c 100644 --- a/service/src/structure_comparer/serve.py +++ b/service/src/structure_comparer/serve.py @@ -36,6 +36,7 @@ from .model.get_mappings_output import GetMappingsOutput from .model.init_project_input import InitProjectInput from .model.mapping import MappingBase as MappingBaseModel +from .model.mapping import MappingCreate as MappingCreateModel from .model.mapping import MappingDetails as MappingDetailsModel from .model.mapping import MappingField as MappingFieldModel from .model.mapping import MappingFieldMinimal as MappingFieldMinimalModel @@ -993,6 +994,63 @@ async def get_mapping_field( return ErrorModel.from_except(e) +@app.post( + "/project/{project_key}/mapping", + tags=["Mappings"], + response_model_exclude_unset=True, + response_model_exclude_none=True, + responses={400: {}, 404: {}}, +) +async def post_mapping( + project_key: str, + mappingData: MappingCreateModel, + response: Response, +) -> MappingDetailsModel | ErrorModel: + """ + Post a new mapping for a project + Creates a new mapping in the project with the given key. + The mapping needs to be a valid MappingBaseModel. + + --- + consumes: + - application/json + parameters: + - in: path + name: project_key + type: string + required: true + description: The key of the project + responses: + 200: + description: The mapping was created + 400: + description: There was something wrong with the request + schema: + properties: + error: + type: string + description: An error message + 404: + description: Project not found + """ + global mapping_handler + try: + return mapping_handler.create_new(project_key, mappingData) + + except ProjectNotFound as e: + response.status_code = 404 + return ErrorModel.from_except(e) + + except ( + MappingActionNotAllowed, + MappingTargetMissing, + MappingTargetNotFound, + MappingValueMissing, + ) as e: + response.status_code = 400 + return ErrorModel.from_except(e) + + @app.post( "/mapping/{mapping_id}/field/{field_id}/classification", tags=["Fields"],