Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[hotfix/OS-1328 => DEV] Back-office : Checklist > Hauteur anormale du textarea de commentaire #2288

Open
wants to merge 3 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions api/serializers/submission.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2022 Université catholique de Louvain (http://www.uclouvain.be)
# Copyright (C) 2015-2024 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
Expand Down Expand Up @@ -55,5 +55,5 @@ class PropositionErrorsSerializer(serializers.Serializer):

class SubmitPropositionSerializer(serializers.Serializer):
annee = serializers.IntegerField()
pool = serializers.ChoiceField(choices=[calendar.event_reference for calendar in ICalendrierInscription.pools])
pool = serializers.ChoiceField(choices=[calendar.event_reference for calendar in ICalendrierInscription.all_pools])
elements_confirmation = serializers.JSONField()
56 changes: 40 additions & 16 deletions ddd/admission/domain/service/i_calendrier_inscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2023 Université catholique de Louvain (http://www.uclouvain.be)
# Copyright (C) 2015-2024 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
Expand Down Expand Up @@ -64,7 +64,6 @@ class ICalendrierInscription(interface.DomainService):
DoctorateAdmissionCalendar(),
ContinuingEducationAdmissionCalendar(),
AdmissionPoolExternalEnrollmentChangeCalendar(),
AdmissionPoolExternalReorientationCalendar(),
AdmissionPoolVipCalendar(),
AdmissionPoolHueUclPathwayChangeCalendar(),
AdmissionPoolInstituteChangeCalendar(),
Expand All @@ -74,6 +73,10 @@ class ICalendrierInscription(interface.DomainService):
AdmissionPoolHue5ForeignResidencyCalendar(),
AdmissionPoolNonResidentQuotaCalendar(),
]
priority_pools = [
AdmissionPoolExternalReorientationCalendar(),
]
all_pools = priority_pools + pools

# Les inscriptions pour une formation contingentée pour un candidat non résident au sens du décret via osis
# sont interdites pour le moment
Expand Down Expand Up @@ -106,7 +109,7 @@ def determiner_annee_academique_et_pot(
and getattr(proposition.comptabilite, 'type_situation_assimilation', None)
)
ue_plus_5 = cls.est_ue_plus_5(identification, situation_assimilation)
annees = cls.get_annees_academiques_pour_calcul(type_formation=type_formation)
annees_prioritaires, annees = cls.get_annees_academiques_pour_calcul(type_formation=type_formation)
changements_etablissement = profil_candidat_translator.get_changements_etablissement(matricule_candidat, annees)

log_messages = [
Expand All @@ -124,20 +127,36 @@ def determiner_annee_academique_et_pot(
proposition={('Proposition(' + pformat(attr.asdict(proposition)) + ')') if proposition else 'None'},
""",
]
current_kwargs = dict(
logs=log_messages,
pool_ouverts=pool_ouverts,
sigle=formation_id.sigle,
ue_plus_5=ue_plus_5,
access_diplomas=titres_acces.get_valid_conditions(),
training_type=type_formation,
residential_address=residential_address,
annee_derniere_inscription_ucl=identification.annee_derniere_inscription_ucl,
matricule_candidat=matricule_candidat,
changements_etablissement=changements_etablissement,
proposition=proposition,
)

for annee in annees_prioritaires:
pool = cls.determiner_pool_pour_annee_academique(
pools=cls.priority_pools,
annee_academique=annee,
**current_kwargs,
)
if pool:
logger.debug('\n'.join(log_messages))
return InfosDetermineesDTO(annee, pool)
log_messages.append("")

for annee in annees:
pool = cls.determiner_pool_pour_annee_academique(
log_messages,
pool_ouverts,
pools=cls.pools,
annee_academique=annee,
sigle=formation_id.sigle,
ue_plus_5=ue_plus_5,
access_diplomas=titres_acces.get_valid_conditions(),
training_type=type_formation,
residential_address=residential_address,
annee_derniere_inscription_ucl=identification.annee_derniere_inscription_ucl,
matricule_candidat=matricule_candidat,
changements_etablissement=changements_etablissement,
proposition=proposition,
**current_kwargs,
)
if pool:
logger.debug('\n'.join(log_messages))
Expand All @@ -152,9 +171,10 @@ def determiner_pool_pour_annee_academique(
cls,
logs: List[str],
pool_ouverts: List[Tuple[str, int]],
pools: List[PoolCalendar],
**kwargs,
) -> Optional['AcademicCalendarTypes']:
for pool in cls.pools:
for pool in pools:
annee = kwargs['annee_academique']
logs.append(
f"{str(AcademicCalendarTypes.get_value(pool.event_reference)):<70} {annee}"
Expand Down Expand Up @@ -271,7 +291,11 @@ def get_pool_ouverts(cls) -> List[Tuple[str, int]]:
raise NotImplementedError

@classmethod
def get_annees_academiques_pour_calcul(cls, type_formation: TrainingType) -> List[int]:
def get_annees_academiques_pour_calcul(cls, type_formation: TrainingType) -> Tuple[List[int], List[int]]:
"""
Retourne un tuple contenant les deux listes des années académiques utilisées dans le calcul des pots, la
première pour les pots prioritaires et la seconde pour les autres pots.
"""
raise NotImplementedError

@classmethod
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,7 @@ def soumettre(
self.pot_calcule = pool
self.elements_confirmation = elements_confirmation
self.soumise_le = now()
if pool != AcademicCalendarTypes.ADMISSION_POOL_HUE_UCL_PATHWAY_CHANGE:
if pool != AcademicCalendarTypes.ADMISSION_POOL_EXTERNAL_REORIENTATION:
self.attestation_inscription_reguliere = []
if pool != AcademicCalendarTypes.ADMISSION_POOL_EXTERNAL_ENROLLMENT_CHANGE:
self.formulaire_modification_inscription = []
Expand Down
19 changes: 19 additions & 0 deletions ddd/admission/test/domain/service/test_calendrier_inscription.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ def test_verification_calendrier_inscription_reorientation_validee(self):
proposition = PropositionFactory(est_bachelier_en_reorientation=True)
profil = ProfilCandidatFactory(matricule=proposition.matricule_candidat)
self.profil_candidat_translator.profil_candidats.append(profil.identification)
self.profil_candidat_translator.get_coordonnees = lambda m: profil.coordonnees
dto = CalendrierInscriptionInMemory.determiner_annee_academique_et_pot(
formation_id=proposition.formation_id,
proposition=proposition,
Expand All @@ -250,6 +251,24 @@ def test_verification_calendrier_inscription_reorientation_validee(self):
profil_candidat_translator=self.profil_candidat_translator,
)
self.assertEqual(dto.pool, AcademicCalendarTypes.ADMISSION_POOL_EXTERNAL_REORIENTATION)
self.assertEqual(dto.annee, 2022)

@freezegun.freeze_time('2022-03-15')
def test_verification_calendrier_inscription_reorientation_validee_hors_periode(self):
# Nous ne sommes pas dans la période réorientation mais le candidat l'a validée
proposition = PropositionFactory(est_bachelier_en_reorientation=True)
profil = ProfilCandidatFactory(matricule=proposition.matricule_candidat)
self.profil_candidat_translator.profil_candidats.append(profil.identification)
self.profil_candidat_translator.get_coordonnees = lambda m: profil.coordonnees
dto = CalendrierInscriptionInMemory.determiner_annee_academique_et_pot(
formation_id=proposition.formation_id,
proposition=proposition,
matricule_candidat=proposition.matricule_candidat,
titres_acces=Titres(AdmissionConditionsDTOFactory()),
type_formation=TrainingType.BACHELOR,
profil_candidat_translator=self.profil_candidat_translator,
)
self.assertNotEqual(dto.pool, AcademicCalendarTypes.ADMISSION_POOL_EXTERNAL_REORIENTATION)

@freezegun.freeze_time('2022-12-15')
def test_verification_calendrier_inscription_reorientation_non_choisie(self):
Expand Down
19 changes: 19 additions & 0 deletions forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -356,3 +356,22 @@ def clean(self, value):
return html.unescape(cleaned_value)

return cleaned_value


class AutoGrowTextareaWidget(forms.Textarea):
"""A textarea widget whose minimum height is automatically adjusted to fit its content."""

template_name = "admission/widgets/autogrow_textarea.html"

def __init__(self, attrs=None):
if not attrs:
attrs = {}

attrs['onInput'] = 'this.parentNode.dataset.value = this.value'

super().__init__(attrs)

class Media:
css = {
'all': ('admission/autogrow_textarea.css',),
}
15 changes: 8 additions & 7 deletions forms/admission/checklist.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@
)

from admission.constants import CONTEXT_GENERAL, CONTEXT_DOCTORATE
from admission.models import GeneralEducationAdmission, DoctorateAdmission
from admission.models.base import training_campus_subquery
from admission.models.checklist import (
RefusalReason,
AdditionalApprovalCondition,
)
from admission.ddd import DUREE_MINIMALE_PROGRAMME, DUREE_MAXIMALE_PROGRAMME
from admission.ddd.admission.domain.model.enums.authentification import EtatAuthentificationParcours
from admission.ddd.admission.domain.model.enums.condition_acces import recuperer_conditions_acces_par_formation
Expand All @@ -79,9 +73,16 @@
EMPTY_CHOICE_AS_LIST,
get_initial_choices_for_additional_approval_conditions,
AdmissionHTMLCharField,
AutoGrowTextareaWidget,
)
from admission.forms import get_academic_year_choices
from admission.forms.admission.document import ChangeRequestDocumentForm
from admission.models import GeneralEducationAdmission, DoctorateAdmission
from admission.models.base import training_campus_subquery
from admission.models.checklist import (
RefusalReason,
AdditionalApprovalCondition,
)
from admission.views.autocomplete.learning_unit_years import LearningUnitYearAutocomplete
from admission.views.common.detail_tabs.comments import (
COMMENT_TAG_SIC,
Expand Down Expand Up @@ -114,7 +115,7 @@

class CommentForm(forms.Form):
comment = forms.CharField(
widget=forms.Textarea(
widget=AutoGrowTextareaWidget(
attrs={
'rows': 2,
'hx-trigger': 'keyup changed delay:2s',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2023 Université catholique de Louvain (http://www.uclouvain.be)
# Copyright (C) 2015-2024 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
Expand Down Expand Up @@ -39,9 +39,9 @@

class CalendrierInscription(ICalendrierInscription):
@classmethod
def get_annees_academiques_pour_calcul(cls, type_formation: TrainingType) -> List[int]:
def get_annees_academiques_pour_calcul(cls, type_formation: TrainingType) -> Tuple[List[int], List[int]]:
year = AnneeInscriptionFormationTranslator().recuperer_annee_selon_type_formation(type_formation)
return [year, year - 1, year + 1, year + 2]
return ([year - 1, year], [year, year - 1, year + 1, year + 2])

@classmethod
def get_pool_ouverts(cls) -> List[Tuple[str, int]]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
# The core business involves the administration of students, teachers,
# courses, programs and so on.
#
# Copyright (C) 2015-2023 Université catholique de Louvain (http://www.uclouvain.be)
# Copyright (C) 2015-2024 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
Expand All @@ -24,12 +24,18 @@
#
# ##############################################################################
from datetime import date, timedelta
from typing import List, Tuple
from typing import List, Tuple, Optional

from admission.constants import CONTEXT_GENERAL, CONTEXT_DOCTORATE, CONTEXT_CONTINUING
from admission.ddd.admission.domain.service.i_annee_inscription_formation import IAnneeInscriptionFormationTranslator
from admission.ddd.admission.domain.service.i_calendrier_inscription import ICalendrierInscription
from admission.ddd.admission.dtos import IdentificationDTO
from admission.ddd.admission.enums import TypeSituationAssimilation
from admission.infrastructure.admission.domain.service.in_memory.annee_inscription_formation import (
AnneeInscriptionFormationInMemoryTranslator,
)
from admission.infrastructure.admission.domain.service.in_memory.profil_candidat import ProfilCandidatInMemoryTranslator
from base.models.enums.academic_calendar_type import AcademicCalendarTypes
from base.models.enums.education_group_types import TrainingType
from base.tests.factories.academic_year import get_current_year
from osis_profile import PLUS_5_ISO_CODES
Expand All @@ -41,24 +47,35 @@ class CalendrierInscriptionInMemory(ICalendrierInscription):
pool.cutover_date,
getattr(pool, 'end_date', None),
)
for pool in ICalendrierInscription.pools
for pool in ICalendrierInscription.all_pools
}

@classmethod
def get_annees_academiques_pour_calcul(cls, type_formation: TrainingType) -> List[int]:
return cls._get_annees_academiques_pour_calcul()
def get_annees_academiques_pour_calcul(cls, type_formation: TrainingType) -> Tuple[List[int], List[int]]:
from admission.infrastructure.admission.domain.service.annee_inscription_formation import (
ADMISSION_CONTEXT_BY_OSIS_EDUCATION_TYPE,
)

@classmethod
def _get_annees_academiques_pour_calcul(cls) -> List[int]:
current_year = get_current_year()
return [current_year, current_year - 1, current_year + 1, current_year + 2]
current_year = AnneeInscriptionFormationInMemoryTranslator.recuperer(
{
CONTEXT_GENERAL: AcademicCalendarTypes.GENERAL_EDUCATION_ENROLLMENT,
CONTEXT_DOCTORATE: AcademicCalendarTypes.DOCTORATE_EDUCATION_ENROLLMENT,
CONTEXT_CONTINUING: AcademicCalendarTypes.CONTINUING_EDUCATION_ENROLLMENT,
}[ADMISSION_CONTEXT_BY_OSIS_EDUCATION_TYPE[type_formation.name]]
)

return (
[current_year - 1, current_year],
[current_year, current_year - 1, current_year + 1, current_year + 2],
)

@classmethod
def get_pool_ouverts(cls) -> List[Tuple[str, int]]:
opened = []
today = date.today()
annees = [today.year, today.year - 1, today.year + 1, today.year + 2]
for pool_name, dates in cls.periodes_ouvertes.items():
for annee in cls._get_annees_academiques_pour_calcul():
for annee in annees:
date_debut, date_fin = cls._get_dates_completes(annee, dates[0], dates[1])
if date_debut <= today <= date_fin:
opened.append((pool_name, annee))
Expand Down
2 changes: 1 addition & 1 deletion schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11004,10 +11004,10 @@ components:
type: integer
pool:
enum:
- ADMISSION_POOL_EXTERNAL_REORIENTATION
- DOCTORATE_EDUCATION_ENROLLMENT
- CONTINUING_EDUCATION_ENROLLMENT
- ADMISSION_POOL_EXTERNAL_ENROLLMENT_CHANGE
- ADMISSION_POOL_EXTERNAL_REORIENTATION
- ADMISSION_POOL_VIP
- ADMISSION_POOL_HUE_UCL_PATHWAY_CHANGE
- ADMISSION_POOL_INSTITUT_CHANGE
Expand Down
42 changes: 42 additions & 0 deletions static/admission/autogrow_textarea.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
*
* 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-2024 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/.
*
*/

.autogrow-textarea-wrapper {
display: grid;
}

.autogrow-textarea-wrapper:after {
content: attr(data-value) ' ';
visibility: hidden;
display: block;
white-space: pre-wrap;
}

.autogrow-textarea-wrapper textarea, .autogrow-textarea-wrapper:after {
min-height: 100% !important;
grid-area: 1 / 1 / 1 / 1;
padding: 0.5em;
}
Loading