Skip to content

Commit

Permalink
refactor: move all import function calls to management, leave only El…
Browse files Browse the repository at this point in the history
…ementImportHelper

Signed-off-by: David Wallace <david.wallace@tu-darmstadt.de>
  • Loading branch information
MyPyDavid committed Jan 30, 2024
1 parent 0c86522 commit c54680d
Show file tree
Hide file tree
Showing 8 changed files with 103 additions and 348 deletions.
35 changes: 1 addition & 34 deletions rdmo/conditions/imports.py
Original file line number Diff line number Diff line change
@@ -1,43 +1,10 @@
import logging
from typing import Callable, Tuple
from rdmo.core.imports import ElementImportHelper

from rdmo.core.imports import (
ElementImportHelper,
validate_instance,
)

from .models import Condition
from .serializers.v1 import ConditionSerializer
from .validators import ConditionLockedValidator, ConditionUniqueURIValidator

logger = logging.getLogger(__name__)


def import_condition(
instance: Condition,
element: dict,
validators: Tuple[Callable],
save: bool = False,
):

# set_foreign_field are already set in management/import.py
# check_permissions already done in management/import.py
# extra_fields are set in in management/import.py
validate_instance(instance, element, *validators)

if element.get('errors'):
return instance

if save:
instance.save()
# sites and editors are added in management/import.py

return instance


import_helper_condition = ElementImportHelper(
model="conditions.condition",
import_func=import_condition,
validators=(ConditionLockedValidator, ConditionUniqueURIValidator),
foreign_fields=('source', 'target_option'),
serializer=ConditionSerializer,
Expand Down
20 changes: 15 additions & 5 deletions rdmo/core/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from os.path import join as pj
from pathlib import Path
from random import randint
from typing import Callable, Iterable, Optional, Sequence, Tuple
from typing import Callable, Dict, Iterable, Optional, Sequence, Tuple

from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
Expand Down Expand Up @@ -63,13 +63,15 @@ def make_import_info_msg(verbose_name: str, created: bool, uri: Optional[str]=No
@dataclass
class ElementImportHelper:
model: str
import_func: Callable
validators: Iterable[Callable]
serializer: Callable
common_fields: Sequence[str] = field(default=ELEMENT_COMMON_FIELDS)
lang_fields: Sequence[str] = field(default_factory=list)
foreign_fields: Sequence[str] = field(default_factory=list)
extra_fields: Sequence[str] = field(default_factory=list)
m2m_instance_fields: Sequence[str] = field(default_factory=list)
m2m_through_instance_fields: Sequence[Dict[str, str]] = field(default_factory=list)
reverse_m2m_through_instance_fields: Sequence[Dict[str, str]] = field(default_factory=list)
add_current_site_editors: bool = True
add_current_site_sites: bool = False

Expand Down Expand Up @@ -144,11 +146,13 @@ def set_extra_field(instance, field_name, element, questions_widget_types=None)
extra_value = element_value
else:
extra_value = default_value
if field_name == "path" and hasattr(instance, "build_path"):
extra_value = instance.build_path(instance.key, instance.parent)

setattr(instance, field_name, extra_value)


def set_m2m_instances(instance, field_name, element):
def set_m2m_instances(instance, element, field_name):
if field_name not in element:
return

Expand Down Expand Up @@ -182,9 +186,12 @@ def set_m2m_instances(instance, field_name, element):
getattr(instance, field_name).set(foreign_instances)


def set_m2m_through_instances(instance, field_name, element, source_name, target_name, through_name) -> None:
def set_m2m_through_instances(instance, element, field_name=None, source_name=None,
target_name=None, through_name=None) -> None:
if field_name not in element:
return
if not all([source_name, target_name, through_name]):
return

target_elements = element.get(field_name) or []

Expand Down Expand Up @@ -236,9 +243,12 @@ def set_m2m_through_instances(instance, field_name, element, source_name, target
through_instance.delete()


def set_reverse_m2m_through_instance(instance, field_name, element, source_name, target_name, through_name) -> None:
def set_reverse_m2m_through_instance(instance, element, field_name=None, source_name=None,
target_name=None, through_name=None) -> None:
if field_name not in element:
return
if not all([source_name, target_name, through_name]):
return

target_element = element.get(field_name)

Expand Down
26 changes: 1 addition & 25 deletions rdmo/domain/imports.py
Original file line number Diff line number Diff line change
@@ -1,42 +1,18 @@
import logging
from typing import Callable, Tuple

from rdmo.core.imports import (
ElementImportHelper,
validate_instance,
)

from .models import Attribute
from .serializers.v1 import BaseAttributeSerializer
from .validators import AttributeLockedValidator, AttributeParentValidator, AttributeUniqueURIValidator

logger = logging.getLogger(__name__)


def import_attribute(
instance: Attribute, element: dict,
validators: Tuple[Callable],
save: bool = False) -> Attribute:

# set_foreign_field are already set in management/import.py
# check_permissions already done in management/import.py
instance.path = instance.build_path(instance.key, instance.parent)
validate_instance(instance, element, *validators)

if element.get('errors'):
return instance

if save:
instance.save()
# sites and editors are added in management/import.py

return instance


import_helper_attribute = ElementImportHelper(
model="domain.attribute",
import_func=import_attribute,
validators=(AttributeLockedValidator, AttributeParentValidator, AttributeUniqueURIValidator),
foreign_fields=('parent',),
extra_fields=('path',),
serializer=BaseAttributeSerializer,
)
20 changes: 16 additions & 4 deletions rdmo/management/imports.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
set_extra_field,
set_foreign_field,
set_lang_field,
set_m2m_instances,
set_m2m_through_instances,
set_reverse_m2m_through_instance,
validate_instance,
)
from rdmo.domain.imports import import_helper_attribute
from rdmo.options.imports import import_helper_option, import_helper_optionset
Expand Down Expand Up @@ -94,7 +98,6 @@ def import_element(
model = RDMO_MODEL_PATH_MAPPER[model_path]
user = request.user if request is not None else None
import_helper = ELEMENT_IMPORT_HELPERS[model_path]
import_func = import_helper.import_func
validators = import_helper.validators
common_fields = import_helper.common_fields
lang_field_names = import_helper.lang_fields
Expand Down Expand Up @@ -138,23 +141,32 @@ def import_element(
for extra_field in extra_field_names:
set_extra_field(instance, extra_field, element, questions_widget_types=questions_widget_types)

# call the element specific import method
instance = import_func(instance, element, validators, save)
# call the validators on the instance
validate_instance(instance, element, *validators)

if element.get('errors'):
return element

if _updated and not _created:
element['updated'] = _updated
# and instance is not original_instance
# keep only strings, make json serializable
serializer = import_helper.serializer
changes = get_updated_changes(element, instance, original_instance, serializer, request=None)
changes = get_updated_changes(element, instance, original_instance, serializer, request=request)
element['updated_and_changed'] = changes

if save:
logger.info(_msg)
element['created'] = _created
element['updated'] = _updated
instance.save()
for m2m_field in import_helper.m2m_instance_fields:
set_m2m_instances(instance, element, m2m_field)
for m2m_through_fields in import_helper.m2m_through_instance_fields:
set_m2m_through_instances(instance, element, **m2m_through_fields)
for reverse_m2m_fields in import_helper.reverse_m2m_through_instance_fields:
set_reverse_m2m_through_instance(instance, element, **reverse_m2m_fields)

if import_helper.add_current_site_editors:
instance.editors.add(current_site)
if import_helper.add_current_site_sites:
Expand Down
71 changes: 11 additions & 60 deletions rdmo/options/imports.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,7 @@
import logging
from typing import Callable, Tuple

from rdmo.core.imports import (
ElementImportHelper,
set_m2m_instances,
set_m2m_through_instances,
set_reverse_m2m_through_instance,
validate_instance,
)

from .models import Option, OptionSet
from .serializers.v1 import OptionSerializer, OptionSetSerializer
from .validators import (
OptionLockedValidator,
Expand All @@ -18,67 +10,26 @@
OptionUniqueURIValidator,
)

logger = logging.getLogger(__name__)


def import_option(
instance: Option,
element: dict,
validators: Tuple[Callable],
save: bool = False,
):
# check_permissions already done in management/import.py
# extra_fields are set in in management/import.py
validate_instance(instance, element, *validators)

if element.get('errors'):
return instance

if save:
instance.save()
set_m2m_instances(instance, 'conditions', element)
set_m2m_through_instances(instance, 'options', element, 'optionset', 'option', 'optionset_options')
# sites and editors are added in management/import.py

return instance


import_helper_option = ElementImportHelper(
model="options.option",
import_func=import_option,
validators=(OptionLockedValidator, OptionUniqueURIValidator),
lang_fields=('text',),
serializer = OptionSerializer,
extra_fields = ('order', 'provider_key', 'additional_input')
extra_fields = ('order', 'provider_key', 'additional_input'),
m2m_instance_fields = ('conditions', ),
m2m_through_instance_fields = [
{'field_name': 'options', 'source_name': 'optionset',
'target_name': 'option', 'through_name': 'optionset_options'}
]
)


def import_optionset(
instance: OptionSet,
element: dict,
validators: Tuple[Callable],
save: bool = False,
):
# lang_fields are already set in management/import.py
# check_permissions already done in management/import.py
# extra_fields are set in in management/import.py
validate_instance(instance, element, *validators)

if element.get('errors'):
return instance

if save:
instance.save()
set_reverse_m2m_through_instance(instance, 'optionset', element, 'option', 'optionset', 'option_optionsets')
# sites and editors are added in management/import.py

return instance


import_helper_optionset = ElementImportHelper(
model="options.optionset",
import_func=import_optionset,
validators=(OptionSetLockedValidator, OptionSetUniqueURIValidator),
serializer = OptionSetSerializer,
extra_fields=('additional_input',)
extra_fields=('additional_input',),
reverse_m2m_through_instance_fields=[
{'field_name': 'optionset', 'source_name': 'option',
'target_name': 'optionset', 'through_name': 'option_optionsets'}
]
)
Loading

0 comments on commit c54680d

Please sign in to comment.