Skip to content

Commit

Permalink
[OS-664] Do not use a builder with implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
jcougnaud committed Jan 16, 2025
1 parent 8dc705a commit c1b34d7
Show file tree
Hide file tree
Showing 22 changed files with 368 additions and 337 deletions.
94 changes: 94 additions & 0 deletions admission_utils/copy_documents.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# ##############################################################################
#
# OSIS stands for Open Student Information System. It's an application
# designed to manage the core business of higher education institutions,
# such as universities, faculties, institutes and professional schools.
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2025 Université catholique de Louvain (http://www.uclouvain.be)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# A copy of this license - GNU General Public License - is available
# at the root of the source code of this program. If not,
# see http://www.gnu.org/licenses/.
#
# ##############################################################################
import uuid


def copy_documents(objs):
"""
Create copies of the files of the specified objects and affect them to the specified objects.
:param objs: The list of objects.
"""
from osis_document.api.utils import get_several_remote_metadata, get_remote_tokens, documents_remote_duplicate
from osis_document.contrib import FileField
from osis_document.utils import generate_filename

all_document_uuids = []
all_document_upload_paths = {}
document_fields_by_obj_uuid = {}

# Get all the document fields and the uuids of the documents to duplicate
for obj in objs:
document_fields_by_obj_uuid[obj.uuid] = {}

for field in obj._meta.get_fields():
if isinstance(field, FileField):
document_uuids = getattr(obj, field.name)

if document_uuids:
document_fields_by_obj_uuid[obj.uuid][field.name] = field
all_document_uuids += [document_uuid for document_uuid in document_uuids if document_uuid]

all_tokens = get_remote_tokens(all_document_uuids)
metadata_by_token = get_several_remote_metadata(tokens=list(all_tokens.values()))

# Get the upload paths of the documents to duplicate
for obj in objs:
for field_name, field in document_fields_by_obj_uuid[obj.uuid].items():
document_uuids = getattr(obj, field_name)

for document_uuid in document_uuids:
if not document_uuid:
continue

document_uuid_str = str(document_uuid)
file_name = 'file'

if document_uuid_str in all_tokens and all_tokens[document_uuid_str] in metadata_by_token:
metadata = metadata_by_token[all_tokens[document_uuid_str]]
if metadata.get('name'):
file_name = metadata['name']

all_document_upload_paths[document_uuid_str] = generate_filename(obj, file_name, field.upload_to)

# Make a copy of the documents and return the uuids of the copied documents
duplicates_documents_uuids = documents_remote_duplicate(
uuids=all_document_uuids,
with_modified_upload=True,
upload_path_by_uuid=all_document_upload_paths,
)

# Update the uuids of the documents with the uuids of the copied documents
for obj in objs:
for field_name in document_fields_by_obj_uuid[obj.uuid]:
setattr(
obj,
field_name,
[
uuid.UUID(duplicates_documents_uuids[str(document_uuid)])
for document_uuid in getattr(obj, field_name)
if duplicates_documents_uuids.get(str(document_uuid))
],
)
80 changes: 68 additions & 12 deletions ddd/admission/doctorat/preparation/builder/proposition_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,11 @@
# see http://www.gnu.org/licenses/.
#
##############################################################################
from abc import abstractmethod
from typing import Optional, Union

from admission.ddd.admission.doctorat.preparation.builder.proposition_identity_builder import PropositionIdentityBuilder
from admission.ddd.admission.doctorat.preparation.commands import InitierPropositionCommand
from admission.ddd.admission.doctorat.preparation.domain.model._detail_projet import projet_non_rempli
from admission.ddd.admission.doctorat.preparation.domain.model.doctorat_formation import DoctoratFormation
from admission.ddd.admission.doctorat.preparation.domain.model.enums import (
ChoixCommissionProximiteCDEouCLSM,
ChoixCommissionProximiteCDSS,
Expand All @@ -49,7 +47,7 @@
from osis_common.ddd import interface


class IPropositionBuilder(interface.RootEntityBuilder):
class PropositionBuilder(interface.RootEntityBuilder):
@classmethod
def build_from_repository_dto(cls, dto_object: 'interface.DTO') -> 'Proposition':
raise NotImplementedError
Expand All @@ -64,7 +62,7 @@ def initier_proposition(
cmd: 'InitierPropositionCommand',
doctorat_translator: 'IDoctoratTranslator',
proposition_repository: 'IPropositionRepository',
) -> 'PropositionIdentity ':
) -> 'Proposition':
if cmd.pre_admission_associee:
return cls.initier_nouvelle_proposition_attachee_a_pre_admission(
cmd,
Expand All @@ -84,7 +82,7 @@ def initier_nouvelle_proposition_non_attachee_a_pre_admission(
cmd: 'InitierPropositionCommand',
doctorat_translator: 'IDoctoratTranslator',
proposition_repository: 'IPropositionRepository',
) -> 'PropositionIdentity':
) -> 'Proposition':
doctorat = doctorat_translator.get(cmd.sigle_formation, cmd.annee_formation)
InitierPropositionValidatorList(
type_admission=cmd.type_admission,
Expand All @@ -102,7 +100,8 @@ def initier_nouvelle_proposition_non_attachee_a_pre_admission(
elif cmd.commission_proximite and cmd.commission_proximite in ChoixSousDomaineSciences.get_names():
commission_proximite = ChoixSousDomaineSciences[cmd.commission_proximite]
reference = proposition_repository.recuperer_reference_suivante()
proposition = Proposition(

return Proposition(
entity_id=PropositionIdentityBuilder.build(),
reference=reference,
statut=ChoixStatutPropositionDoctorale.EN_BROUILLON,
Expand All @@ -114,16 +113,73 @@ def initier_nouvelle_proposition_non_attachee_a_pre_admission(
projet=projet_non_rempli,
auteur_derniere_modification=cmd.matricule_candidat,
)
proposition_repository.save(proposition)

return proposition.entity_id

@classmethod
@abstractmethod
def initier_nouvelle_proposition_attachee_a_pre_admission(
cls,
cmd: 'InitierPropositionCommand',
doctorat_translator: 'IDoctoratTranslator',
proposition_repository: 'IPropositionRepository',
) -> 'PropositionIdentity':
raise NotImplementedError
) -> 'Proposition':
pre_admission = proposition_repository.get(entity_id=PropositionIdentity(uuid=cmd.pre_admission_associee))

doctorat = doctorat_translator.get(
sigle=pre_admission.formation_id.sigle, annee=pre_admission.formation_id.annee
)

reference = proposition_repository.recuperer_reference_suivante()

proposition = Proposition(
entity_id=PropositionIdentityBuilder.build(),
reference=reference,
statut=ChoixStatutPropositionDoctorale.EN_BROUILLON,
type_admission=ChoixTypeAdmission[cmd.type_admission],
formation_id=pre_admission.formation_id,
matricule_candidat=pre_admission.matricule_candidat,
projet=projet_non_rempli,
auteur_derniere_modification=cmd.matricule_candidat,
pre_admission_associee=pre_admission.entity_id,
curriculum=pre_admission.curriculum,
)

proposition.completer(
doctorat=doctorat,
justification=pre_admission.justification,
commission_proximite=pre_admission.commission_proximite.name if pre_admission.commission_proximite else '',
type_financement=pre_admission.financement.type.name if pre_admission.financement.type else '',
type_contrat_travail=pre_admission.financement.type_contrat_travail
if pre_admission.financement.type_contrat_travail
else '',
eft=pre_admission.financement.eft,
bourse_recherche=pre_admission.financement.bourse_recherche,
autre_bourse_recherche=pre_admission.financement.autre_bourse_recherche,
bourse_date_debut=pre_admission.financement.bourse_date_debut,
bourse_date_fin=pre_admission.financement.bourse_date_fin,
bourse_preuve=pre_admission.financement.bourse_preuve,
duree_prevue=pre_admission.financement.duree_prevue,
temps_consacre=pre_admission.financement.temps_consacre,
est_lie_fnrs_fria_fresh_csc=pre_admission.financement.est_lie_fnrs_fria_fresh_csc,
commentaire_financement=pre_admission.financement.commentaire,
langue_redaction_these=pre_admission.projet.langue_redaction_these,
institut_these=str(pre_admission.projet.institut_these.uuid) if pre_admission.projet.institut_these else '',
lieu_these=pre_admission.projet.lieu_these,
titre=pre_admission.projet.titre,
resume=pre_admission.projet.resume,
doctorat_deja_realise=pre_admission.experience_precedente_recherche.doctorat_deja_realise.name
if pre_admission.experience_precedente_recherche.doctorat_deja_realise
else '',
institution=pre_admission.experience_precedente_recherche.institution,
domaine_these=pre_admission.experience_precedente_recherche.domaine_these,
date_soutenance=pre_admission.experience_precedente_recherche.date_soutenance,
raison_non_soutenue=pre_admission.experience_precedente_recherche.raison_non_soutenue,
projet_doctoral_deja_commence=pre_admission.projet.deja_commence,
projet_doctoral_institution=pre_admission.projet.deja_commence_institution,
projet_doctoral_date_debut=pre_admission.projet.date_debut,
documents=pre_admission.projet.documents,
graphe_gantt=pre_admission.projet.graphe_gantt,
proposition_programme_doctoral=pre_admission.projet.proposition_programme_doctoral,
projet_formation_complementaire=pre_admission.projet.projet_formation_complementaire,
lettres_recommandation=pre_admission.projet.lettres_recommandation,
)

return proposition
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ class Proposition(interface.RootEntity):

profil_soumis_candidat: ProfilCandidat = None

pre_admission_associee: Optional[PropositionIdentity] = None

fiche_archive_signatures_envoyees: List[str] = attr.Factory(list)
comptabilite: 'Comptabilite' = comptabilite_non_remplie
reponses_questions_specifiques: Dict = attr.Factory(dict)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,19 @@
#
# ##############################################################################
import abc
from abc import abstractmethod
from typing import List, Optional, Union

from admission.models.enums.actor_type import ActorType
from admission.ddd.admission.doctorat.preparation.domain.model._cotutelle import Cotutelle, pas_de_cotutelle
from admission.ddd.admission.doctorat.preparation.domain.model.doctorat import DoctoratIdentity
from admission.ddd.admission.doctorat.preparation.domain.model.groupe_de_supervision import (
GroupeDeSupervision,
GroupeDeSupervisionIdentity,
SignataireIdentity,
)
from admission.ddd.admission.doctorat.preparation.domain.model.proposition import PropositionIdentity
from admission.ddd.admission.doctorat.preparation.domain.model.proposition import PropositionIdentity, Proposition
from admission.ddd.admission.doctorat.preparation.dtos import CotutelleDTO, MembreCADTO, PromoteurDTO
from admission.models.enums.actor_type import ActorType
from osis_common.ddd import interface
from osis_common.ddd.interface import ApplicationService

Expand Down Expand Up @@ -151,3 +152,12 @@ def get_cotutelle_dto_from_model(cls, cotutelle: Optional[Cotutelle]) -> 'Cotute
convention=cotutelle and cotutelle.convention or [],
autres_documents=cotutelle and cotutelle.autres_documents or [],
)

@classmethod
@abstractmethod
def initialize_supervision_group_from_proposition(
cls,
uuid_proposition_originale: str,
nouvelle_proposition: 'Proposition',
):
raise NotImplementedError
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ def delete(cls, entity_id: 'PropositionIdentity', **kwargs: ApplicationService)

@classmethod
@abc.abstractmethod
def save(cls, entity: 'Proposition') -> None: # type: ignore[override]
def save(cls, entity: 'Proposition', dupliquer_documents=False) -> None: # type: ignore[override]
raise NotImplementedError

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,14 @@
# see http://www.gnu.org/licenses/.
#
##############################################################################
from admission.ddd.admission.doctorat.preparation.builder.proposition_builder import IPropositionBuilder
from admission.ddd.admission.doctorat.preparation.builder.proposition_builder import PropositionBuilder
from admission.ddd.admission.doctorat.preparation.commands import InitierPropositionCommand
from admission.ddd.admission.doctorat.preparation.domain.model.proposition import PropositionIdentity
from admission.ddd.admission.doctorat.preparation.domain.service.i_doctorat import IDoctoratTranslator
from admission.ddd.admission.doctorat.preparation.domain.service.i_historique import IHistorique
from admission.ddd.admission.doctorat.preparation.repository.i_groupe_de_supervision import (
IGroupeDeSupervisionRepository,
)
from admission.ddd.admission.doctorat.preparation.repository.i_proposition import IPropositionRepository
from admission.ddd.admission.domain.service.i_maximum_propositions import IMaximumPropositionsAutorisees

Expand All @@ -38,19 +41,29 @@ def initier_proposition(
doctorat_translator: 'IDoctoratTranslator',
historique: 'IHistorique',
maximum_propositions_service: 'IMaximumPropositionsAutorisees',
proposition_builder: 'IPropositionBuilder',
groupe_supervision_repository: 'IGroupeDeSupervisionRepository',
) -> 'PropositionIdentity':
# GIVEN
maximum_propositions_service.verifier_nombre_propositions_en_cours(cmd.matricule_candidat)

# WHEN
proposition_identity = proposition_builder.initier_proposition(
proposition = PropositionBuilder().initier_proposition(
cmd,
doctorat_translator,
proposition_repository,
)

# THEN
historique.historiser_initiation(proposition_identity, cmd.matricule_candidat)
proposition_repository.save(
proposition,
dupliquer_documents=bool(cmd.pre_admission_associee),
)

groupe_supervision_repository.initialize_supervision_group_from_proposition(
uuid_proposition_originale=cmd.pre_admission_associee,
nouvelle_proposition=proposition,
)

historique.historiser_initiation(proposition.entity_id, cmd.matricule_candidat)

return proposition_identity
return proposition.entity_id
Empty file.
Empty file.

This file was deleted.

Loading

0 comments on commit c1b34d7

Please sign in to comment.