Skip to content

Commit

Permalink
VKT(Backend): good and satisfactory level enrollment core functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
jrkkp committed Sep 17, 2024
1 parent d445b64 commit 0fb5eed
Show file tree
Hide file tree
Showing 9 changed files with 253 additions and 14 deletions.
55 changes: 45 additions & 10 deletions backend/vkt/src/main/java/fi/oph/vkt/api/PublicController.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import fi.oph.vkt.api.dto.PublicPersonDTO;
import fi.oph.vkt.api.dto.PublicReservationDTO;
import fi.oph.vkt.model.Enrollment;
import fi.oph.vkt.model.EnrollmentAppointment;
import fi.oph.vkt.model.FeatureFlag;
import fi.oph.vkt.model.Person;
import fi.oph.vkt.model.type.AppLocale;
Expand All @@ -18,6 +19,7 @@
import fi.oph.vkt.service.FeatureFlagService;
import fi.oph.vkt.service.PaymentService;
import fi.oph.vkt.service.PublicAuthService;
import fi.oph.vkt.service.PublicEnrollmentAppointmentService;
import fi.oph.vkt.service.PublicEnrollmentService;
import fi.oph.vkt.service.PublicExamEventService;
import fi.oph.vkt.service.PublicPersonService;
Expand Down Expand Up @@ -66,6 +68,9 @@ public class PublicController {
@Resource
private PublicEnrollmentService publicEnrollmentService;

@Resource
private PublicEnrollmentAppointmentService publicEnrollmentAppointmentService;

@Resource
private PublicExamEventService publicExamEventService;

Expand Down Expand Up @@ -180,6 +185,30 @@ public PublicReservationDTO renewReservation(@PathVariable final long reservatio
return publicReservationService.renewReservation(reservationId, person);
}

@GetMapping(path = "/appointment/{enrollmentAppointmentId:\\d+}/redirect/{authHash:[a-z0-9\\-]+}")
public void createSessionAndRedirectToEnrollmentAppointment(
final HttpServletResponse httpResponse,
@PathVariable final long enrollmentAppointmentId,
@PathVariable final String authHash,
final HttpSession session
) throws IOException {
try {
final EnrollmentAppointment enrollmentAppointment = publicEnrollmentAppointmentService.getEnrollmentAppointmentByHash(
enrollmentAppointmentId,
authHash
);
SessionUtil.setPersonId(session, enrollmentAppointment.getId());

httpResponse.sendRedirect(uiRouteUtil.getEnrollmentAppointmentUrl(enrollmentAppointment.getId()));
} catch (final APIException e) {
LOG.warn("Encountered known error, redirecting to front page. Error:", e);
httpResponse.sendRedirect(uiRouteUtil.getPublicFrontPageUrlWithError(e.getExceptionType()));
} catch (final Exception e) {
LOG.error("Encountered unknown error, redirecting to front page. Error:", e);
httpResponse.sendRedirect(uiRouteUtil.getPublicFrontPageUrlWithGenericError());
}
}

@GetMapping(path = "/examEvent/{examEventId:\\d+}/redirect/{paymentLinkHash:[a-z0-9\\-]+}")
public void createSessionAndRedirectToPreview(
final HttpServletResponse httpResponse,
Expand Down Expand Up @@ -211,16 +240,16 @@ public void deleteReservation(@PathVariable final long reservationId, final Http
publicReservationService.deleteReservation(reservationId, person);
}

@GetMapping(path = "/auth/login/{examEventId:\\d+}/{type:\\w+}")
@GetMapping(path = "/auth/login/{targetId:\\d+}/{type:\\w+}")
public void casLoginRedirect(
final HttpServletResponse httpResponse,
@PathVariable final long examEventId,
@PathVariable final long targetId,
@PathVariable final String type,
@RequestParam final Optional<String> locale,
final HttpSession session
) throws IOException {
final String casLoginUrl = publicAuthService.createCasLoginUrl(
examEventId,
targetId,
EnrollmentType.fromString(type),
locale.isPresent() ? AppLocale.fromString(locale.get()) : AppLocale.FI
);
Expand All @@ -232,26 +261,32 @@ public void casLoginRedirect(
httpResponse.sendRedirect(casLoginUrl);
}

@GetMapping(path = "/auth/validate/{examEventId:\\d+}/{type:\\w+}")
@GetMapping(path = "/auth/validate/{targetId:\\d+}/{type:\\w+}")
public void validateTicket(
@RequestParam final String ticket,
@PathVariable final long examEventId,
@PathVariable final long targetId,
@PathVariable final String type,
final HttpSession session,
final HttpServletResponse httpResponse
) throws IOException {
try {
final EnrollmentType enrollmentType = EnrollmentType.fromString(type);
final Person person = publicAuthService.createPersonFromTicket(ticket, examEventId, enrollmentType);
final Person person = publicAuthService.createPersonFromTicket(ticket, targetId, enrollmentType);
SessionUtil.setPersonId(session, person.getId());

if (enrollmentType.equals(EnrollmentType.QUEUE)) {
publicEnrollmentService.initialiseEnrollmentToQueue(examEventId, person);
} else {
publicEnrollmentService.initialiseEnrollment(examEventId, person);
publicEnrollmentService.initialiseEnrollmentToQueue(targetId, person);
} else if (enrollmentType.equals(EnrollmentType.RESERVATION)) {
publicEnrollmentService.initialiseEnrollment(targetId, person);
} else if (enrollmentType.equals(EnrollmentType.APPOINTMENT)) {
publicEnrollmentAppointmentService.savePersonInfo(targetId, person);
}

httpResponse.sendRedirect(uiRouteUtil.getEnrollmentContactDetailsUrl(examEventId));
if (enrollmentType.equals(EnrollmentType.APPOINTMENT)) {
httpResponse.sendRedirect(uiRouteUtil.getEnrollmentAppointmentUrl(targetId));
} else {
httpResponse.sendRedirect(uiRouteUtil.getEnrollmentContactDetailsUrl(targetId));
}
} catch (final APIException e) {
LOG.warn("Encountered known error, redirecting to front page. Error:", e);
httpResponse.sendRedirect(uiRouteUtil.getPublicFrontPageUrlWithError(e.getExceptionType()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package fi.oph.vkt.model;

import fi.oph.vkt.model.type.EnrollmentStatus;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.OneToMany;
import jakarta.persistence.OneToOne;
import jakarta.persistence.Table;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
@Entity
@Table(name = "enrollment")
public class EnrollmentAppointment extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "enrollment_appointment_id", nullable = false)
private long id;

@Column(name = "skill_oral")
private boolean oralSkill;

@Column(name = "skill_textual")
private boolean textualSkill;

@Column(name = "skill_understanding")
private boolean understandingSkill;

@Column(name = "partial_exam_speaking")
private boolean speakingPartialExam;

@Column(name = "partial_exam_speech_comprehension")
private boolean speechComprehensionPartialExam;

@Column(name = "partial_exam_writing")
private boolean writingPartialExam;

@Column(name = "partial_exam_reading_comprehension")
private boolean readingComprehensionPartialExam;

@Column(name = "digital_certificate_consent")
private boolean digitalCertificateConsent;

@Column(name = "email")
private String email;

@Column(name = "phone_number")
private String phoneNumber;

@Column(name = "street")
private String street;

@Column(name = "postal_code")
private String postalCode;

@Column(name = "town")
private String town;

@Column(name = "country")
private String country;

@Size(max = 255)
@Column(name = "auth_hash", unique = true)
private String authHash;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "person_id", referencedColumnName = "person_id")
private Person person;

@OneToMany(mappedBy = "enrollmentAppointment")
private List<Payment> payments = new ArrayList<>();
}
8 changes: 6 additions & 2 deletions backend/vkt/src/main/java/fi/oph/vkt/model/Payment.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,14 @@ public class Payment extends BaseEntity {
@Column(name = "payment_id", nullable = false)
private long id;

@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "enrollment_id", referencedColumnName = "enrollment_id", nullable = false)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "enrollment_id", referencedColumnName = "enrollment_id")
private Enrollment enrollment;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "enrollment_appointment_id", referencedColumnName = "enrollment_appointment_id")
private EnrollmentAppointment enrollmentAppointment;

@Column(name = "amount", nullable = false)
private int amount;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

public enum EnrollmentType {
RESERVATION("reservation"),
APPOINTMENT("appointment"),
QUEUE("queue");

private final String text;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package fi.oph.vkt.repository;

import fi.oph.vkt.api.dto.FreeEnrollmentDetails;
import fi.oph.vkt.model.Enrollment;
import fi.oph.vkt.model.EnrollmentAppointment;
import fi.oph.vkt.model.ExamEvent;
import fi.oph.vkt.model.Person;
import fi.oph.vkt.model.type.EnrollmentStatus;
import java.util.List;
import java.util.Optional;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

@Repository
public interface EnrollmentAppointmentRepository extends BaseRepository<EnrollmentAppointment> {
Optional<EnrollmentAppointment> findByIdAndAuthHash(final long id, final String paymentLinkHash);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@ public class PublicAuthService {
private final CasTicketRepository casTicketRepository;
private final CasSessionMappingStorage sessionMappingStorage;

public String createCasLoginUrl(final long examEventId, final EnrollmentType type, final AppLocale appLocale) {
public String createCasLoginUrl(final long targetId, final EnrollmentType type, final AppLocale appLocale) {
final String casLoginUrl = environment.getRequiredProperty("app.cas-oppija.login-url");
final String casServiceUrl = URLEncoder.encode(
String.format(environment.getRequiredProperty("app.cas-oppija.service-url"), examEventId, type),
String.format(environment.getRequiredProperty("app.cas-oppija.service-url"), targetId, type),
StandardCharsets.UTF_8
);
return casLoginUrl + "?service=" + casServiceUrl + "&locale=" + appLocale.name().toLowerCase();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package fi.oph.vkt.service;

import fi.oph.vkt.api.dto.FreeEnrollmentAttachmentDTO;
import fi.oph.vkt.api.dto.FreeEnrollmentDetails;
import fi.oph.vkt.api.dto.FreeEnrollmentDetailsDTO;
import fi.oph.vkt.api.dto.PublicEducationDTO;
import fi.oph.vkt.api.dto.PublicEnrollmentCreateDTO;
import fi.oph.vkt.api.dto.PublicEnrollmentDTO;
import fi.oph.vkt.api.dto.PublicEnrollmentInitialisationDTO;
import fi.oph.vkt.api.dto.PublicExamEventDTO;
import fi.oph.vkt.api.dto.PublicFreeEnrollmentBasisDTO;
import fi.oph.vkt.api.dto.PublicPersonDTO;
import fi.oph.vkt.api.dto.PublicReservationDTO;
import fi.oph.vkt.model.Enrollment;
import fi.oph.vkt.model.EnrollmentAppointment;
import fi.oph.vkt.model.ExamEvent;
import fi.oph.vkt.model.FeatureFlag;
import fi.oph.vkt.model.FreeEnrollment;
import fi.oph.vkt.model.Person;
import fi.oph.vkt.model.Reservation;
import fi.oph.vkt.model.UploadedFileAttachment;
import fi.oph.vkt.model.type.EnrollmentStatus;
import fi.oph.vkt.model.type.FreeEnrollmentSource;
import fi.oph.vkt.model.type.FreeEnrollmentType;
import fi.oph.vkt.repository.EnrollmentAppointmentRepository;
import fi.oph.vkt.repository.EnrollmentRepository;
import fi.oph.vkt.repository.ExamEventRepository;
import fi.oph.vkt.repository.FreeEnrollmentRepository;
import fi.oph.vkt.repository.ReservationRepository;
import fi.oph.vkt.repository.UploadedFileAttachmentRepository;
import fi.oph.vkt.service.aws.S3Service;
import fi.oph.vkt.service.koski.KoskiService;
import fi.oph.vkt.util.EnrollmentUtil;
import fi.oph.vkt.util.ExamEventUtil;
import fi.oph.vkt.util.PersonUtil;
import fi.oph.vkt.util.exception.APIException;
import fi.oph.vkt.util.exception.APIExceptionType;
import fi.oph.vkt.util.exception.NotFoundException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import lombok.RequiredArgsConstructor;
import org.apache.commons.io.FilenameUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@RequiredArgsConstructor
public class PublicEnrollmentAppointmentService extends AbstractEnrollmentService {

private final EnrollmentAppointmentRepository enrollmentAppointmentRepository;

public EnrollmentAppointment getEnrollmentAppointmentByHash(
final long enrollmentAppointmentId,
final String authHash
) {
return enrollmentAppointmentRepository.findByIdAndAuthHash(enrollmentAppointmentId, authHash).orElseThrow();
}

public void savePersonInfo(long targetId, Person person) {}
}
4 changes: 4 additions & 0 deletions backend/vkt/src/main/java/fi/oph/vkt/util/UIRouteUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@ public String getPublicFrontPageUrlWithError(final APIExceptionType exceptionTyp
private String getPublicBaseUrl() {
return environment.getRequiredProperty("app.base-url.public");
}

public String getEnrollmentAppointmentUrl(final long enrollmentAppointmentId) {
return String.format("%s/ota-yhteytta/%s/tunnistaudu", getPublicBaseUrl(), enrollmentAppointmentId);
}
}
28 changes: 28 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 @@ -859,4 +859,32 @@
ALTER TABLE exam_event ADD COLUMN registration_opens TIMESTAMP WITH TIME ZONE;
</sql>
</changeSet>
<changeSet id="2024-09-16-enrollment_appointment" author="jrkkp">
<createTable tableName="enrollment_appointment">
<column autoIncrement="true" name="enrollment_appointment_id" type="BIGSERIAL">
<constraints primaryKey="true" primaryKeyName="enrollment_appointment_pkey" />
</column>
<column name="created_by" type="TEXT"/>
<column name="modified_by" type="TEXT"/>
<column name="deleted_by" type="TEXT"/>
<column name="created_at" type="TIMESTAMP WITH TIME ZONE" defaultValueComputed="CURRENT_TIMESTAMP">
<constraints nullable="false"/>
</column>
<column name="modified_at" type="TIMESTAMP WITH TIME ZONE" defaultValueComputed="CURRENT_TIMESTAMP">
<constraints nullable="false"/>
</column>
<column name="deleted_at" type="TIMESTAMP WITH TIME ZONE"/>
<column name="auth_hash" type="TEXT" />
<column name="email" type="TEXT" />
<column name="phone" type="TEXT" />
<column name="street" type="TEXT"/>
<column name="postal_code" type="TEXT"/>
<column name="town" type="TEXT"/>
<column name="country" type="TEXT"/>
<column name="person_id" type="BIGINT" />
</createTable>
<addColumn tableName="payment">
<column name="enrollment_appointment_id" type="BIGINT" />
</addColumn>
</changeSet>
</databaseChangeLog>

0 comments on commit 0fb5eed

Please sign in to comment.