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

Préavis - Ajouter dans le formulaire -12 m la possibilité de joindre des fichiers #3384

Merged
merged 13 commits into from
Sep 6, 2024
Merged
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package fr.gouv.cnsp.monitorfish.domain.entities.prior_notification

import fr.gouv.cnsp.monitorfish.utils.CustomZonedDateTime

data class PriorNotificationDocument(
val id: String?,
val content: ByteArray,
val createdAt: CustomZonedDateTime,
val fileName: String,
val isManualPriorNotification: Boolean,
val mimeType: String,
val reportId: String,
val updatedAt: CustomZonedDateTime,
) {
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as PriorNotificationDocument

if (id != other.id) return false
if (!content.contentEquals(other.content)) return false
if (createdAt != other.createdAt) return false
if (fileName != other.fileName) return false
if (isManualPriorNotification != other.isManualPriorNotification) return false
if (mimeType != other.mimeType) return false
if (reportId != other.reportId) return false
if (updatedAt != other.updatedAt) return false

return true
}

override fun hashCode(): Int {
var result = id?.hashCode() ?: 0
result = 31 * result + content.contentHashCode()
result = 31 * result + createdAt.hashCode()
result = 31 * result + fileName.hashCode()
result = 31 * result + isManualPriorNotification.hashCode()
result = 31 * result + mimeType.hashCode()
result = 31 * result + reportId.hashCode()
result = 31 * result + updatedAt.hashCode()
return result
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package fr.gouv.cnsp.monitorfish.domain.entities.prior_notification

import java.time.ZonedDateTime

data class PriorNotificationIdentifier(
val reportId: String,
val operationDate: ZonedDateTime,
val isManualPriorNotification: Boolean,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package fr.gouv.cnsp.monitorfish.domain.repositories

import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationDocument

interface PriorNotificationUploadRepository {
fun findAllByReportId(reportId: String): List<PriorNotificationDocument>

fun findById(id: String): PriorNotificationDocument

fun save(newPriorNotificationDocument: PriorNotificationDocument): PriorNotificationDocument

fun deleteById(id: String)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationDocument
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationIdentifier
import fr.gouv.cnsp.monitorfish.domain.repositories.LogbookReportRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.ManualPriorNotificationRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationUploadRepository
import fr.gouv.cnsp.monitorfish.utils.CustomZonedDateTime

@UseCase
class CreatePriorNotificationUpload(
private val logbookReportRepository: LogbookReportRepository,
private val manualPriorNotificationRepository: ManualPriorNotificationRepository,
private val priorNotificationUploadRepository: PriorNotificationUploadRepository,
) {
fun execute(identifier: PriorNotificationIdentifier, content: ByteArray, fileName: String, mimeType: String) {
val createdAt = CustomZonedDateTime.now()

val newPriorNotificationDocument = PriorNotificationDocument(
id = null,
content = content,
createdAt = createdAt,
fileName = fileName,
isManualPriorNotification = identifier.isManualPriorNotification,
mimeType = mimeType,
reportId = identifier.reportId,
updatedAt = createdAt,
)

priorNotificationUploadRepository.save(newPriorNotificationDocument)

if (identifier.isManualPriorNotification) {
manualPriorNotificationRepository.updateState(
reportId = identifier.reportId,
isBeingSent = false,
isSent = false,
isVerified = false,
)
} else {
logbookReportRepository.updatePriorNotificationState(
reportId = identifier.reportId,
operationDate = identifier.operationDate,
isBeingSent = false,
isSent = false,
isVerified = false,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationIdentifier
import fr.gouv.cnsp.monitorfish.domain.repositories.LogbookReportRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.ManualPriorNotificationRepository
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationUploadRepository

@UseCase
class DeletePriorNotificationUpload(
private val logbookReportRepository: LogbookReportRepository,
private val manualPriorNotificationRepository: ManualPriorNotificationRepository,
private val priorNotificationUploadRepository: PriorNotificationUploadRepository,
) {
fun execute(identifier: PriorNotificationIdentifier, priorNotificationUploadId: String) {
priorNotificationUploadRepository.deleteById(priorNotificationUploadId)

if (identifier.isManualPriorNotification) {
manualPriorNotificationRepository.updateState(
reportId = identifier.reportId,
isBeingSent = false,
isSent = false,
isVerified = false,
)
} else {
logbookReportRepository.updatePriorNotificationState(
reportId = identifier.reportId,
operationDate = identifier.operationDate,
isBeingSent = false,
isSent = false,
isVerified = false,
)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationDocument
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationUploadRepository

@UseCase
class GetPriorNotificationUpload(
private val priorNotificationUploadRepository: PriorNotificationUploadRepository,
) {
fun execute(priorNotificationUploadId: String): PriorNotificationDocument {
return priorNotificationUploadRepository.findById(priorNotificationUploadId)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package fr.gouv.cnsp.monitorfish.domain.use_cases.prior_notification

import fr.gouv.cnsp.monitorfish.config.UseCase
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationDocument
import fr.gouv.cnsp.monitorfish.domain.repositories.PriorNotificationUploadRepository

@UseCase
class GetPriorNotificationUploads(
private val priorNotificationUploadRepository: PriorNotificationUploadRepository,
) {
fun execute(reportId: String): List<PriorNotificationDocument> {
return priorNotificationUploadRepository.findAllByReportId(reportId)
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package fr.gouv.cnsp.monitorfish.infrastructure.api.bff

import fr.gouv.cnsp.monitorfish.domain.entities.facade.SeafrontGroup
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationIdentifier
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationState
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.filters.PriorNotificationsFilter
import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.sorters.PriorNotificationsSortColumn
Expand All @@ -9,6 +10,8 @@ import fr.gouv.cnsp.monitorfish.infrastructure.api.input.LogbookPriorNotificatio
import fr.gouv.cnsp.monitorfish.infrastructure.api.input.ManualPriorNotificationComputeDataInput
import fr.gouv.cnsp.monitorfish.infrastructure.api.input.ManualPriorNotificationFormDataInput
import fr.gouv.cnsp.monitorfish.infrastructure.api.outputs.*
import fr.gouv.cnsp.monitorfish.infrastructure.exceptions.BackendRequestErrorCode
import fr.gouv.cnsp.monitorfish.infrastructure.exceptions.BackendRequestException
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.tags.Tag
Expand All @@ -19,6 +22,7 @@ import org.springframework.http.HttpStatus
import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import org.springframework.web.multipart.MultipartFile
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter.ISO_DATE_TIME

Expand All @@ -28,14 +32,18 @@ import java.time.format.DateTimeFormatter.ISO_DATE_TIME
class PriorNotificationController(
private val computeManualPriorNotification: ComputeManualPriorNotification,
private val createOrUpdateManualPriorNotification: CreateOrUpdateManualPriorNotification,
private val createPriorNotificationUpload: CreatePriorNotificationUpload,
private val deletePriorNotificationUpload: DeletePriorNotificationUpload,
private val getPriorNotification: GetPriorNotification,
private val getPriorNotificationPdfDocument: GetPriorNotificationPdfDocument,
private val getPriorNotificationUpload: GetPriorNotificationUpload,
private val getPriorNotificationUploads: GetPriorNotificationUploads,
private val getPriorNotifications: GetPriorNotifications,
private val getNumberToVerify: GetNumberToVerify,
private val getPriorNotificationTypes: GetPriorNotificationTypes,
private val invalidatePriorNotification: InvalidatePriorNotification,
private val updateLogbookPriorNotification: UpdateLogbookPriorNotification,
private val verifyAndSendPriorNotification: VerifyAndSendPriorNotification,
private val invalidatePriorNotification: InvalidatePriorNotification,
) {
data class Status(val status: String)

Expand Down Expand Up @@ -282,7 +290,7 @@ class PriorNotificationController(
}

@GetMapping("/{reportId}/pdf")
@Operation(summary = "Get the PDF document")
@Operation(summary = "Get the PNO PDF document")
fun getPdfDocument(
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
Expand Down Expand Up @@ -357,4 +365,87 @@ class PriorNotificationController(

return PriorNotificationDataOutput.fromPriorNotification(updatedPriorNotification)
}

@GetMapping("/{reportId}/uploads/{priorNotificationUploadId}")
@Operation(summary = "Download a prior notification attachment")
fun getUploads(
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
reportId: String,
@PathParam("Prior notification upload ID`")
@PathVariable(name = "priorNotificationUploadId")
priorNotificationUploadId: String,
): ResponseEntity<ByteArray> {
val document = getPriorNotificationUpload.execute(priorNotificationUploadId)

val headers = HttpHeaders().apply {
contentType = MediaType.parseMediaType(document.mimeType)
setContentDispositionFormData("attachment", document.fileName)
}

return ResponseEntity(document.content, headers, HttpStatus.OK)
}

@GetMapping("/{reportId}/uploads")
@Operation(summary = "Get all the attachment documents for a given prior notification")
fun getUploads(
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
reportId: String,
): List<PriorNotificationUploadDataOutput> {
return getPriorNotificationUploads.execute(reportId)
.map { PriorNotificationUploadDataOutput.fromPriorNotificationDocument(it) }
}

@PostMapping("/{reportId}/uploads")
@Operation(summary = "Attach a document to a prior notification")
fun createUpload(
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
reportId: String,
@Parameter(description = "Operation date (to optimize SQL query via Timescale).")
@RequestParam(name = "operationDate")
operationDate: ZonedDateTime,
@Parameter(description = "Is the prior notification manually created?")
@RequestParam(name = "isManualPriorNotification")
isManualPriorNotification: Boolean,
@RequestParam("file")
file: MultipartFile,
): ResponseEntity<*> {
val content = file.bytes
?: throw BackendRequestException(BackendRequestErrorCode.EMPTY_UPLOADED_FILE)
val fileName = file.originalFilename
?: throw BackendRequestException(BackendRequestErrorCode.MISSING_UPLOADED_FILE_NAME)
val mimeType = file.contentType
?: throw BackendRequestException(BackendRequestErrorCode.MISSING_UPLOADED_FILE_TYPE)

val identifier = PriorNotificationIdentifier(reportId, operationDate, isManualPriorNotification)

createPriorNotificationUpload.execute(identifier, content, fileName, mimeType)

return ResponseEntity("File uploaded successfully: " + file.originalFilename, HttpStatus.OK)
}

@DeleteMapping("/{reportId}/uploads/{priorNotificationUploadId}")
@Operation(summary = "Delete a prior notification attachment")
fun deleteUpload(
@PathParam("Logbook message `reportId`")
@PathVariable(name = "reportId")
reportId: String,
@Parameter(description = "Operation date (to optimize SQL query via Timescale).")
@RequestParam(name = "operationDate")
operationDate: ZonedDateTime,
@Parameter(description = "Is the prior notification manually created?")
@RequestParam(name = "isManualPriorNotification")
isManualPriorNotification: Boolean,
@PathParam("Prior notification upload ID")
@PathVariable(name = "priorNotificationUploadId")
priorNotificationUploadId: String,
): ResponseEntity<Unit> {
val identifier = PriorNotificationIdentifier(reportId, operationDate, isManualPriorNotification)

deletePriorNotificationUpload.execute(identifier, priorNotificationUploadId)

return ResponseEntity(HttpStatus.NO_CONTENT)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fr.gouv.cnsp.monitorfish.infrastructure.api.outputs

import fr.gouv.cnsp.monitorfish.domain.entities.prior_notification.PriorNotificationDocument
import fr.gouv.cnsp.monitorfish.utils.CustomZonedDateTime

class PriorNotificationUploadDataOutput(
val id: String,
val createdAt: CustomZonedDateTime,
val fileName: String,
val isManualPriorNotification: Boolean,
val mimeType: String,
val reportId: String,
val updatedAt: CustomZonedDateTime,
) {
companion object {
fun fromPriorNotificationDocument(priorNotificationDocument: PriorNotificationDocument): PriorNotificationUploadDataOutput {
val id = requireNotNull(priorNotificationDocument.id) {
"`id` is null."
}

return PriorNotificationUploadDataOutput(
id = id,
createdAt = priorNotificationDocument.createdAt,
fileName = priorNotificationDocument.fileName,
isManualPriorNotification = priorNotificationDocument.isManualPriorNotification,
mimeType = priorNotificationDocument.mimeType,
reportId = priorNotificationDocument.reportId,
updatedAt = priorNotificationDocument.updatedAt,
)
}
}
}
Loading
Loading