Skip to content

Commit

Permalink
VKT(Backend & Frontend) OPHKIOS-100 Ilmoittautumisen alkamisen ajasta…
Browse files Browse the repository at this point in the history
…minen (#696)

* VKT(Backend): support for exam event open and close times

* VKT(Backend & Frontend): support for exam event open and close times

* VKT(Backend & Frontend): support for exam event open and close times continues

* VKT(Backend) test fix

* VKT(Backend) test fix

* VKT(Backend & Frontend): registration opens front page listing refresh

* VKT(Backend & Frontend): registration opens front page listing refresh

* VKT(Backend & Frontend): some small tweaks and fixes

* VKT(Frontend & Backend): review fixes

* VKT(Frontend): Cypress test fix

* VKT(Backend): unit test fixes

* VKT(Frontend): time format localisation fix

* VKT(Frontend): oops, cypress fix

* VKT(Backend): deploy commit [deploy]

* VKT(Frontend): Review fix

* VKT(Frontend & Backend): Swedish translations [deploy]

* VKT(Backend): deploy commit [deploy]

* VKT(Backend): prettier commit [deploy]
  • Loading branch information
jrkkp authored Oct 4, 2024
1 parent 0c444d6 commit edf928b
Show file tree
Hide file tree
Showing 47 changed files with 472 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import fi.oph.vkt.model.type.ExamLanguage;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.NonNull;

Expand All @@ -11,6 +12,8 @@ public record PublicExamEventDTO(
@NonNull ExamLanguage language,
@NonNull LocalDate date,
@NonNull LocalDate registrationCloses,
@NonNull LocalDate registrationOpens,
@NonNull Long openings,
@NonNull Boolean isOpen,
@NonNull Boolean hasCongestion
) {}
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package fi.oph.vkt.api.dto.clerk;

import com.fasterxml.jackson.annotation.JsonFormat;
import fi.oph.vkt.model.type.ExamLanguage;
import fi.oph.vkt.model.type.ExamLevel;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.NonNull;

Expand All @@ -12,7 +14,8 @@ public record ClerkExamEventCreateDTO(
@NonNull @NotNull ExamLanguage language,
@NonNull @NotNull ExamLevel level,
@NonNull @NotNull LocalDate date,
@NonNull @NotNull LocalDate registrationCloses,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @NonNull @NotNull LocalDateTime registrationCloses,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @NonNull @NotNull LocalDateTime registrationOpens,
@NonNull @NotNull Boolean isHidden,
@NonNull @NotNull Long maxParticipants
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import fi.oph.vkt.model.type.ExamLevel;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import lombok.Builder;
import lombok.NonNull;
Expand All @@ -15,7 +16,8 @@ public record ClerkExamEventDTO(
@NonNull @NotNull ExamLanguage language,
@NonNull @NotNull ExamLevel level,
@NonNull @NotNull LocalDate date,
@NonNull @NotNull LocalDate registrationCloses,
@NonNull @NotNull LocalDateTime registrationCloses,
@NonNull @NotNull LocalDateTime registrationOpens,
@NonNull @NotNull Boolean isHidden,
@NonNull @NotNull Long maxParticipants,
@NonNull @NotNull List<ClerkEnrollmentDTO> enrollments
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
import fi.oph.vkt.model.type.ExamLanguage;
import fi.oph.vkt.model.type.ExamLevel;
import java.time.LocalDate;
import java.time.LocalDateTime;

public interface ClerkExamEventDTOCommonFields {
ExamLanguage language();
ExamLevel level();
LocalDate date();
LocalDate registrationCloses();
LocalDateTime registrationCloses();
LocalDateTime registrationOpens();
Boolean isHidden();
Long maxParticipants();
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import fi.oph.vkt.model.type.ExamLanguage;
import fi.oph.vkt.model.type.ExamLevel;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.NonNull;

Expand All @@ -12,7 +13,8 @@ public record ClerkExamEventListDTO(
@NonNull ExamLanguage language,
@NonNull ExamLevel level,
@NonNull LocalDate date,
@NonNull LocalDate registrationCloses,
@NonNull LocalDateTime registrationCloses,
@NonNull LocalDateTime registrationOpens,
@NonNull Long participants,
@NonNull Long maxParticipants,
@NonNull Boolean isUnusedSeats,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package fi.oph.vkt.api.dto.clerk;

import com.fasterxml.jackson.annotation.JsonFormat;
import fi.oph.vkt.model.type.ExamLanguage;
import fi.oph.vkt.model.type.ExamLevel;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDate;
import java.time.LocalDateTime;
import lombok.Builder;
import lombok.NonNull;

Expand All @@ -14,7 +16,8 @@ public record ClerkExamEventUpdateDTO(
@NonNull @NotNull ExamLanguage language,
@NonNull @NotNull ExamLevel level,
@NonNull @NotNull LocalDate date,
@NonNull @NotNull LocalDate registrationCloses,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @NonNull @NotNull LocalDateTime registrationCloses,
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss") @NonNull @NotNull LocalDateTime registrationOpens,
@NonNull @NotNull Boolean isHidden,
@NonNull @NotNull Long maxParticipants
)
Expand Down
6 changes: 5 additions & 1 deletion backend/vkt/src/main/java/fi/oph/vkt/model/ExamEvent.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
Expand Down Expand Up @@ -39,8 +40,11 @@ public class ExamEvent extends BaseEntity {
@Column(name = "date", nullable = false)
private LocalDate date;

@Column(name = "registration_opens", nullable = false)
private LocalDateTime registrationOpens;

@Column(name = "registration_closes", nullable = false)
private LocalDate registrationCloses;
private LocalDateTime registrationCloses;

@Column(name = "is_hidden", nullable = false)
private boolean isHidden;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import fi.oph.vkt.model.type.ExamLanguage;
import fi.oph.vkt.model.type.ExamLevel;
import java.time.LocalDate;
import java.time.LocalDateTime;

public record ClerkExamEventProjection(
long id,
ExamLanguage language,
ExamLevel level,
LocalDate date,
LocalDate registrationCloses,
LocalDateTime registrationCloses,
LocalDateTime registrationOpens,
long participants,
long maxParticipants,
boolean isHidden,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
public interface ExamEventRepository extends BaseRepository<ExamEvent> {
@Query(
"SELECT new fi.oph.vkt.repository.PublicExamEventProjection(e.id, e.language, e.date, e.registrationCloses," +
" COUNT(en), e.maxParticipants)" +
" e.registrationOpens, COUNT(en), e.maxParticipants)" +
" FROM ExamEvent e" +
" LEFT JOIN e.enrollments en ON en.status = 'COMPLETED' OR en.status = 'AWAITING_PAYMENT' OR en.status = 'AWAITING_APPROVAL' OR en.status = 'EXPECTING_PAYMENT_UNFINISHED_ENROLLMENT'" +
" WHERE e.level = ?1" +
" AND e.registrationCloses >= CURRENT_DATE" +
" AND e.registrationCloses >= CURRENT_TIMESTAMP" +
" AND e.isHidden = false" +
" GROUP BY e.id"
)
Expand All @@ -26,7 +26,7 @@ public interface ExamEventRepository extends BaseRepository<ExamEvent> {
" FROM ExamEvent e" +
" LEFT JOIN e.enrollments en ON en.status = 'QUEUED'" +
" WHERE e.level = ?1" +
" AND e.registrationCloses >= CURRENT_DATE" +
" AND e.registrationCloses >= CURRENT_TIMESTAMP" +
" AND e.isHidden = false" +
" GROUP BY e.id" +
" HAVING COUNT(en) > 0"
Expand All @@ -44,7 +44,7 @@ public interface ExamEventRepository extends BaseRepository<ExamEvent> {

@Query(
"SELECT new fi.oph.vkt.repository.ClerkExamEventProjection(e.id, e.language, e.level, e.date," +
" e.registrationCloses, COUNT(en), e.maxParticipants, e.isHidden, COUNT(en.id) filter (where en.status = 'AWAITING_APPROVAL'))" +
" e.registrationCloses, e.registrationOpens, COUNT(en), e.maxParticipants, e.isHidden, COUNT(en.id) filter (where en.status = 'AWAITING_APPROVAL'))" +
" FROM ExamEvent e" +
" LEFT JOIN e.enrollments en ON en.status = 'COMPLETED' OR en.status = 'AWAITING_PAYMENT' OR en.status = 'AWAITING_APPROVAL' OR en.status = 'EXPECTING_PAYMENT_UNFINISHED_ENROLLMENT'" +
" GROUP BY e.id"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

import fi.oph.vkt.model.type.ExamLanguage;
import java.time.LocalDate;
import java.time.LocalDateTime;

public record PublicExamEventProjection(
long id,
ExamLanguage language,
LocalDate date,
LocalDate registrationCloses,
LocalDateTime registrationCloses,
LocalDateTime registrationOpens,
long participants,
long maxParticipants
) {}
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ public List<ClerkExamEventListDTO> list() {
.level(e.level())
.date(e.date())
.registrationCloses(e.registrationCloses())
.registrationOpens(e.registrationOpens())
.participants(e.participants())
.maxParticipants(e.maxParticipants())
.isUnusedSeats(isUnusedSeats)
Expand Down Expand Up @@ -108,6 +109,7 @@ private ClerkExamEventDTO getExamEventWithoutAudit(final long examEventId) {
.level(examEvent.getLevel())
.date(examEvent.getDate())
.registrationCloses(examEvent.getRegistrationCloses())
.registrationOpens(examEvent.getRegistrationOpens())
.isHidden(examEvent.isHidden())
.maxParticipants(examEvent.getMaxParticipants())
.enrollments(enrollmentDTOs)
Expand Down Expand Up @@ -163,6 +165,7 @@ private void copyDtoFieldsToExamEvent(final ClerkExamEventDTOCommonFields dto, f
examEvent.setLevel(dto.level());
examEvent.setDate(dto.date());
examEvent.setRegistrationCloses(dto.registrationCloses());
examEvent.setRegistrationOpens(dto.registrationOpens());
examEvent.setHidden(dto.isHidden());
examEvent.setMaxParticipants(dto.maxParticipants());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import fi.oph.vkt.util.exception.APIException;
import fi.oph.vkt.util.exception.APIExceptionType;
import fi.oph.vkt.util.exception.NotFoundException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -74,7 +73,7 @@ public PublicEnrollmentInitialisationDTO initialiseEnrollment(final long examEve
if (ExamEventUtil.isCongested(examEvent)) {
throw new APIException(APIExceptionType.INITIALISE_ENROLLMENT_HAS_CONGESTION);
}
if (examEvent.getRegistrationCloses().isBefore(LocalDate.now())) {
if (examEvent.getRegistrationCloses().isBefore(LocalDateTime.now())) {
throw new APIException(APIExceptionType.INITIALISE_ENROLLMENT_REGISTRATION_CLOSED);
}
if (isPersonEnrolled(examEvent, person, enrollmentRepository)) {
Expand Down Expand Up @@ -211,9 +210,11 @@ private PublicEnrollmentInitialisationDTO createEnrollmentInitialisationDTO(
.id(examEvent.getId())
.language(examEvent.getLanguage())
.date(examEvent.getDate())
.registrationCloses(examEvent.getRegistrationCloses())
.registrationCloses(examEvent.getRegistrationCloses().toLocalDate())
.registrationOpens(examEvent.getRegistrationOpens().toLocalDate())
.openings(openings)
.hasCongestion(false)
.isOpen(ExamEventUtil.isOpen(examEvent))
.build();

final PublicPersonDTO personDTO = PersonUtil.createPublicPersonDTO(person);
Expand Down Expand Up @@ -255,7 +256,7 @@ public PublicEnrollmentInitialisationDTO initialiseEnrollmentToQueue(final long
if (openings > 0) {
throw new APIException(APIExceptionType.INITIALISE_ENROLLMENT_TO_QUEUE_HAS_ROOM);
}
if (examEvent.getRegistrationCloses().isBefore(LocalDate.now())) {
if (examEvent.getRegistrationCloses().isBefore(LocalDateTime.now())) {
throw new APIException(APIExceptionType.INITIALISE_ENROLLMENT_REGISTRATION_CLOSED);
}
if (isPersonEnrolled(examEvent, person, enrollmentRepository)) {
Expand Down Expand Up @@ -579,7 +580,7 @@ public Map<String, String> getPresignedPostRequest(
) {
final ExamEvent examEvent = examEventRepository.getReferenceById(examEventId);

if (person == null || examEvent.getRegistrationCloses().isBefore(LocalDate.now())) {
if (person == null || examEvent.getRegistrationCloses().isBefore(LocalDateTime.now())) {
throw new NotFoundException("Uploading not allowed. Person is null or exam is closed");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import fi.oph.vkt.util.ExamEventUtil;
import fi.oph.vkt.util.exception.NotFoundException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
Expand All @@ -28,7 +29,7 @@ public class PublicExamEventService {
public PublicExamEventDTO getExamEvent(final long examEventId) {
final ExamEvent examEvent = examEventRepository.getReferenceById(examEventId);

if (examEvent.getRegistrationCloses().isBefore(LocalDate.now())) {
if (examEvent.getRegistrationCloses().isBefore(LocalDateTime.now())) {
throw new NotFoundException(String.format("Exam event (%d) enrollment is closed", examEvent.getId()));
}

Expand All @@ -37,9 +38,11 @@ public PublicExamEventDTO getExamEvent(final long examEventId) {
.id(examEvent.getId())
.language(examEvent.getLanguage())
.date(examEvent.getDate())
.registrationCloses(examEvent.getRegistrationCloses())
.registrationCloses(examEvent.getRegistrationCloses().toLocalDate())
.registrationOpens(examEvent.getRegistrationOpens().toLocalDate())
.openings(ExamEventUtil.getOpenings(examEvent))
.hasCongestion(ExamEventUtil.isCongested(examEvent))
.isOpen(ExamEventUtil.isOpen(examEvent.getRegistrationCloses(), examEvent.getRegistrationOpens()))
.build();
}

Expand All @@ -64,9 +67,11 @@ public List<PublicExamEventDTO> listExamEvents(final ExamLevel level) {
.id(e.id())
.language(e.language())
.date(e.date())
.registrationCloses(e.registrationCloses())
.registrationCloses(e.registrationCloses().toLocalDate())
.registrationOpens(e.registrationOpens().toLocalDate())
.openings(openings)
.hasCongestion(hasCongestion)
.isOpen(ExamEventUtil.isOpen(e.registrationCloses(), e.registrationOpens()))
.build();
})
.sorted(Comparator.comparing(PublicExamEventDTO::date).thenComparing(PublicExamEventDTO::language))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import fi.oph.vkt.api.dto.PublicEducationDTO;
import fi.oph.vkt.model.Enrollment;
import fi.oph.vkt.model.FreeEnrollment;
import fi.oph.vkt.model.KoskiEducations;
import fi.oph.vkt.model.type.FreeEnrollmentSource;
import fi.oph.vkt.model.type.FreeEnrollmentType;
import fi.oph.vkt.repository.KoskiEducationsRepository;
import fi.oph.vkt.service.koski.dto.KoskiResponseDTO;
Expand Down
11 changes: 10 additions & 1 deletion backend/vkt/src/main/java/fi/oph/vkt/util/ExamEventUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import fi.oph.vkt.model.ExamEvent;
import fi.oph.vkt.model.Reservation;
import fi.oph.vkt.model.type.EnrollmentStatus;
import java.time.LocalDateTime;
import java.util.List;

public class ExamEventUtil {
Expand Down Expand Up @@ -33,6 +34,14 @@ public static boolean isCongested(final ExamEvent examEvent) {
return isCongested(openings, reservations);
}

public static boolean isOpen(final ExamEvent examEvent) {
return ExamEventUtil.isOpen(examEvent.getRegistrationCloses(), examEvent.getRegistrationOpens());
}

public static boolean isOpen(final LocalDateTime closes, final LocalDateTime opens) {
return closes.isAfter(LocalDateTime.now()) && opens.isBefore(LocalDateTime.now());
}

public static boolean isCongested(final long openings, final long reservations) {
return openings > 0 && openings <= reservations;
}
Expand All @@ -46,7 +55,7 @@ public static ClerkExamEventAuditDTO createExamEventAuditDTO(final ExamEvent exa
.language(examEvent.getLanguage())
.level(examEvent.getLevel())
.date(DateUtil.formatOptionalDate(examEvent.getDate()))
.registrationCloses(DateUtil.formatOptionalDate(examEvent.getRegistrationCloses()))
.registrationCloses(DateUtil.formatOptionalDatetime(examEvent.getRegistrationCloses()))
.isHidden(examEvent.isHidden())
.maxParticipants(examEvent.getMaxParticipants())
.build();
Expand Down
22 changes: 22 additions & 0 deletions backend/vkt/src/main/resources/db/changelog/db.changelog-1.0.xml
Original file line number Diff line number Diff line change
Expand Up @@ -837,4 +837,26 @@
referencedTableName="exam_event"
referencedColumnNames="exam_event_id" />
</changeSet>
<changeSet id="2024-09-11-registration-open-and-close-times-psql" author="jrkkp">
<preConditions onFail="CONTINUE">
<dbms type="postgresql" />
</preConditions>
<sql>
ALTER TABLE exam_event DROP CONSTRAINT IF EXISTS ck_exam_event_registration_closes;
ALTER TABLE exam_event ALTER COLUMN registration_closes TYPE TIMESTAMP WITH TIME ZONE USING registration_closes + time '16:00:00';
ALTER TABLE exam_event ADD COLUMN registration_opens TIMESTAMP WITH TIME ZONE;
UPDATE exam_event SET registration_opens = created_at;
ALTER TABLE exam_event ALTER COLUMN registration_opens SET NOT NULL;
</sql>
</changeSet>
<changeSet id="2024-09-11-registration-open-and-close-times-hsqldb" author="jrkkp">
<preConditions onFail="CONTINUE">
<dbms type="hsqldb" />
</preConditions>
<sql>
ALTER TABLE exam_event DROP CONSTRAINT CK_EXAM_EVENT_REGISTRATION_CLOSES;
ALTER TABLE exam_event ALTER COLUMN registration_closes TIMESTAMP WITH TIME ZONE;
ALTER TABLE exam_event ADD COLUMN registration_opens TIMESTAMP WITH TIME ZONE;
</sql>
</changeSet>
</databaseChangeLog>
3 changes: 2 additions & 1 deletion backend/vkt/src/test/java/fi/oph/vkt/Factory.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ public static ExamEvent examEvent(final ExamLanguage language) {
examEvent.setLanguage(language);
examEvent.setLevel(ExamLevel.EXCELLENT);
examEvent.setDate(LocalDate.now().plusDays(8));
examEvent.setRegistrationCloses(LocalDate.now());
examEvent.setRegistrationCloses(LocalDateTime.now().plusDays(4));
examEvent.setRegistrationOpens(LocalDateTime.now().minusDays(2));
examEvent.setHidden(false);
examEvent.setMaxParticipants(10);

Expand Down
Loading

0 comments on commit edf928b

Please sign in to comment.