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

Signalements - Retouches UI #3644

Merged
merged 4 commits into from
Sep 13, 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
171 changes: 114 additions & 57 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
INFRA_FOLDER="$(shell pwd)/infra/configurations/"
HOST_MIGRATIONS_FOLDER=$(shell pwd)/backend/src/main/resources/db/migration

.PHONY: clean install test
SHELL := /bin/bash
.SHELLFLAGS = -ec
.SILENT:
MAKEFLAGS += --silent
.ONESHELL:

.DEFAULT_GOAL: help

.PHONY: help ##OTHER 🛟 To display this prompts. This will list all available targets with their documentation
help:
echo "❓ Use \`make <target>' where <target> is one of 👇"
echo ""
echo -e "\033[1mLocal Development\033[0m:"
grep -E '^\.PHONY: [a-zA-Z0-9_-]+ .*?##LOCAL' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = "(: |##LOCAL)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'
echo ""
echo -e "\033[1mTesting\033[0m:"
grep -E '^\.PHONY: [a-zA-Z0-9_-]+ .*?##TEST' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = "(: |##TEST)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'
echo ""
echo -e "\033[1mCommands for RUN (STAGING and PROD)\033[0m:"
grep -E '^\.PHONY: [a-zA-Z0-9_-]+ .*?##RUN' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = "(: |##RUN)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'
echo ""
echo -e "\033[1mOther commands\033[0m:"
grep -E '^\.PHONY: [a-zA-Z0-9_-]+ .*?##OTHER' $(MAKEFILE_LIST) | \
awk 'BEGIN {FS = "(: |##OTHER)"}; {printf "\033[36m%-30s\033[0m %s\n", $$2, $$3}'
echo ""
echo "Tips 💡"
echo " - use tab for auto-completion"
echo " - use the dry run option '-n' to show what make is attempting to do. example: environmentName=dev make -n deploy"

docker-env:
cd ./infra/docker && ../../frontend/node_modules/.bin/import-meta-env-prepare -u -x ./.env.local.defaults\
Expand All @@ -10,9 +40,11 @@ docker-env:
################################################################################
# Local Development

check-clean-archi:
.PHONY: check-clean-archi ##LOCAL Check clean architecture imports
check-clean-archi:
cd backend/tools && ./check-clean-architecture.sh

.PHONY: clean ##LOCAL Clean all backend assets and stop docker containers
clean: docker-env
rm -Rf ./backend/target
docker compose down -v
Expand All @@ -26,31 +58,39 @@ compile-back:
init-local-sig:
./infra/local/postgis_insert_layers.sh && ./infra/init/geoserver_init_layers.sh

.PHONY: install-front ##LOCAL ⬇️ Install frontend dependencies
install-front:
cd ./frontend && npm i

.PHONY: run-back ##LOCAL ▶️ Run backend API
run-back: run-stubbed-apis
docker compose up -d --quiet-pull --wait db keycloak
cd backend && ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'

run-back-for-cypress: run-stubbed-apis
docker compose up -d --quiet-pull --wait db keycloak
cd backend && MONITORFISH_OIDC_ENABLED=false ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'
.PHONY: run-front ##LOCAL ▶️ Run frontend for development
run-front:
cd ./frontend && npm run dev

.PHONY: run-back-with-monitorenv ##LOCAL ▶️ Run backend API when running MonitorEnv app (in another terminal)
run-back-with-monitorenv: run-monitorenv
docker compose up -d --quiet-pull --wait db
cd backend && MONITORENV_URL=http://localhost:9880 ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'

run-front:
cd ./frontend && npm run dev

.PHONY: run-monitorenv ##LOCAL ▶️ Run MonitorEnv app containers
run-monitorenv: docker-env
docker compose \
--project-directory ./infra/docker \
--env-file ./infra/docker/.env \
-f ./infra/docker/docker-compose.monitorenv.dev.yml \
up -d monitorenv_app

.PHONY: lint-back ##LOCAL 🪮 ✨ Lint and format backend code
lint-back:
cd ./backend && ./gradlew ktlintFormat | grep -v \
-e "Exceeded max line length" \
-e "Package name must not contain underscore" \
-e "Wildcard import"

run-stubbed-apis:
docker compose stop geoserver-monitorenv-stubs
docker compose up -d --quiet-pull --wait geoserver-monitorenv-stubs
Expand All @@ -71,6 +111,72 @@ dev-restore-db:
@export CONFIG_FILE_PATH=$$(pwd)/infra/dev/database/pg_backup.config; \
./infra/remote/backup/pg_restore.sh -t "$(TAG)"

################################################################################
# Testing

.PHONY: test ##TEST ✅ Run all tests
test: test-back
cd frontend && CI=true npm run test:unit -- --coverage

.PHONY: run-back-for-cypress ##TEST ▶️ Run backend API when using Cypress 📝
run-back-for-cypress: run-stubbed-apis
docker compose up -d --quiet-pull --wait db keycloak
cd backend && MONITORFISH_OIDC_ENABLED=false ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'

.PHONY: run-front-for-cypress ##TEST ▶️ Run frontend when using Cypress 📝
run-front-for-cypress:
cd ./frontend && npm run dev-cypress

.PHONY: run-cypress ##TEST ▶️ Run Cypress 📝
run-cypress:
cd ./frontend && npm run test:e2e:open

test-back: check-clean-archi
@if [ -z "$(class)" ]; then \
echo "Running all Backend tests..."; \
cd backend && ./gradlew clean test; \
else \
echo "Running single Backend test class $(class)..."; \
cd backend && ./gradlew test --console plain --no-continue --parallel --tests "$(class)"; \
fi

.PHONY: test-back-watch ##TEST ✅ Watch backend tests
test-back-watch:
./backend/scripts/test-watch.sh

.PHONY: run-back-for-puppeteer ##TEST ▶️ Run backend API when using Puppeteer 📝
run-back-for-puppeteer: docker-env run-stubbed-apis
docker compose up -d --quiet-pull --wait db
docker compose -f ./infra/docker/docker-compose.puppeteer.yml up -d monitorenv-app
cd backend && MONITORENV_URL=http://localhost:9880 ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'

.PHONY: run-front-for-puppeteer ##TEST ▶️ Run frontend when using Puppeteer 📝
run-front-for-puppeteer:
cd ./frontend && npm run dev-puppeteer

################################################################################
# Remote (Integration / Production)

# ----------------------------------------------------------
# Remote: Run commands

.PHONY: restart-remote-app ##RUN ▶️ Restart app
restart-remote-app:
cd infra/remote && docker compose pull && docker compose up -d --build app --force-recreate

.PHONY: register-pipeline-flows-prod ##RUN ▶️ Register pipeline flows in PROD
register-pipeline-flows-prod:
docker pull docker.pkg.github.com/mtes-mct/monitorfish/monitorfish-pipeline:$(MONITORFISH_VERSION) && \
infra/remote/data-pipeline/register-flows-prod.sh

.PHONY: register-pipeline-flows-int ##RUN ▶️ Register pipeline flows in STAGING
register-pipeline-flows-int:
docker pull docker.pkg.github.com/mtes-mct/monitorfish/monitorfish-pipeline:$(MONITORFISH_VERSION) && \
infra/remote/data-pipeline/register-flows-int.sh

.PHONY: init-remote-sig ##RUN Initialize Geoserver layers
init-remote-sig:
./infra/remote/postgis_insert_layers.sh && ./infra/init/geoserver_init_layers.sh

################################################################################
# Database upgrade
Expand Down Expand Up @@ -113,38 +219,6 @@ add_timescaledb_to_shared_preload_libraries:
bash -c "echo \"shared_preload_libraries = 'timescaledb'\" >> /var/lib/postgresql/data/postgresql.conf";


################################################################################
# Testing

test: test-back
cd frontend && CI=true npm run test:unit -- --coverage

test-back: check-clean-archi
@if [ -z "$(class)" ]; then \
echo "Running all Backend tests..."; \
cd backend && ./gradlew clean test; \
else \
echo "Running single Backend test class $(class)..."; \
cd backend && ./gradlew test --console plain --no-continue --parallel --tests "$(class)"; \
fi

test-back-watch:
./backend/scripts/test-watch.sh

lint-back:
cd ./backend && ./gradlew ktlintFormat | grep -v \
-e "Exceeded max line length" \
-e "Package name must not contain underscore" \
-e "Wildcard import"

run-back-for-puppeteer: docker-env run-stubbed-apis
docker compose up -d --quiet-pull --wait db
docker compose -f ./infra/docker/docker-compose.puppeteer.yml up -d monitorenv-app
cd backend && MONITORENV_URL=http://localhost:9880 ./gradlew bootRun --args='--spring.profiles.active=local --spring.config.additional-location=$(INFRA_FOLDER)'

run-front-for-puppeteer:
cd ./frontend && npm run dev-puppeteer


################################################################################
# CI
Expand Down Expand Up @@ -195,23 +269,6 @@ docker-push-pipeline:
docker push docker.pkg.github.com/mtes-mct/monitorfish/monitorfish-pipeline:$(VERSION)


################################################################################
# Remote (Integration / Production)

# ----------------------------------------------------------
# Remote: Run commands

init-remote-sig:
./infra/remote/postgis_insert_layers.sh && ./infra/init/geoserver_init_layers.sh
restart-remote-app:
cd infra/remote && docker compose pull && docker compose up -d --build app --force-recreate

register-pipeline-flows-prod:
docker pull docker.pkg.github.com/mtes-mct/monitorfish/monitorfish-pipeline:$(MONITORFISH_VERSION) && \
infra/remote/data-pipeline/register-flows-prod.sh
register-pipeline-flows-int:
docker pull docker.pkg.github.com/mtes-mct/monitorfish/monitorfish-pipeline:$(MONITORFISH_VERSION) && \
infra/remote/data-pipeline/register-flows-int.sh

# ----------------------------------------------------------
# Remote: Pipeline commands
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import fr.gouv.cnsp.monitorfish.domain.repositories.ReportingRepository
import fr.gouv.cnsp.monitorfish.domain.use_cases.control_units.GetAllControlUnits
import org.slf4j.LoggerFactory
import java.time.ZonedDateTime
import kotlin.time.measureTimedValue

@UseCase
class GetVesselReportings(
Expand All @@ -29,41 +30,51 @@ class GetVesselReportings(
vesselIdentifier: VesselIdentifier?,
fromDate: ZonedDateTime,
): VesselReportings {
val controlUnits = getAllControlUnits.execute()

val reportings =
findReportings(
val (controlUnits, controlUnitsTimeTaken) = measureTimedValue { getAllControlUnits.execute() }
logger.info("TIME_RECORD - 'getAllControlUnits' took $controlUnitsTimeTaken")

val (reportings, reportingsTimeTaken) =
measureTimedValue { findReportings(
vesselId,
vesselIdentifier,
internalReferenceNumber,
fromDate,
ircs,
externalReferenceNumber,
)
) }
logger.info("TIME_RECORD - 'findReportings' took $reportingsTimeTaken")

val current =
getReportingsAndOccurrences(reportings.filter { !it.isArchived })
.sortedWith(compareByDescending { it.reporting.validationDate ?: it.reporting.creationDate })
.map { reportingAndOccurrences ->
enrichWithInfractionAndControlUnit(reportingAndOccurrences, controlUnits)
}

val yearsRange = fromDate.year..ZonedDateTime.now().year
val archivedYearsToReportings =
yearsRange.associateWith { year ->
val reportingsOfYear =
reportings
.filter { it.isArchived }
.filter { filterByYear(it, year) }

getReportingsAndOccurrences(reportingsOfYear)
val (current, currentTimeTaken) =
measureTimedValue {
getReportingsAndOccurrences(reportings.filter { !it.isArchived })
.sortedWith(compareByDescending { it.reporting.validationDate ?: it.reporting.creationDate })
.map { reportingAndOccurrences ->
enrichWithInfractionAndControlUnit(reportingAndOccurrences, controlUnits)
}
}
logger.info("TIME_RECORD - 'current' took $currentTimeTaken")

val yearsRange = fromDate.year..ZonedDateTime.now().year
val (archivedYearsToReportings, archivedYearsToReportingsTimeTaken) =
measureTimedValue {
yearsRange.associateWith { year ->
val reportingsOfYear =
reportings
.filter { it.isArchived }
.filter { filterByYear(it, year) }

getReportingsAndOccurrences(reportingsOfYear)
.sortedWith(compareByDescending { it.reporting.validationDate ?: it.reporting.creationDate })
.map { reportingAndOccurrences ->
enrichWithInfractionAndControlUnit(reportingAndOccurrences, controlUnits)
}
}
}
logger.info("TIME_RECORD - 'archivedYearsToReportings' took $archivedYearsToReportingsTimeTaken")

val infractionSuspicionsSummary = getInfractionSuspicionsSummary(reportings.filter { it.isArchived })
val (infractionSuspicionsSummary, infractionSuspicionsSummaryTimeTaken) = measureTimedValue { getInfractionSuspicionsSummary(reportings.filter { it.isArchived }) }
logger.info("TIME_RECORD - 'infractionSuspicionsSummary' took $infractionSuspicionsSummaryTimeTaken")
val numberOfInfractionSuspicions = infractionSuspicionsSummary.sumOf { it.numberOfOccurrences }
val numberOfObservation =
reportings
Expand Down Expand Up @@ -93,7 +104,7 @@ class GetVesselReportings(
.groupBy { (it.value as AlertType).type }
.map { (type, reportings) ->
ReportingTitleAndNumberOfOccurrences(
title = type.alertName,
title = "${type.alertName} (NATINF ${reportings[0].value.natinfCode})",
numberOfOccurrences = reportings.size,
)
}
Expand All @@ -113,7 +124,7 @@ class GetVesselReportings(
}

return@map ReportingTitleAndNumberOfOccurrences(
title = infraction?.infraction ?: "NATINF $natinfCode",
title = infraction?.infraction?.let {"$it (NATINF $natinfCode)"} ?: "NATINF $natinfCode",
numberOfOccurrences = reportings.size,
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -413,14 +413,14 @@ class GetVesselReportingsUTests {
val infractionSuspicionsSummary = result.summary.infractionSuspicionsSummary
assertThat(result.summary.infractionSuspicionsSummary).hasSize(4)
assertThat(infractionSuspicionsSummary[0].numberOfOccurrences).isEqualTo(2)
assertThat(infractionSuspicionsSummary[0].title).isEqualTo("12 milles - Pêche sans droits historiques")
assertThat(infractionSuspicionsSummary[0].title).isEqualTo("12 milles - Pêche sans droits historiques (NATINF 2610)")
assertThat(infractionSuspicionsSummary[1].numberOfOccurrences).isEqualTo(1)
assertThat(infractionSuspicionsSummary[1].title).isEqualTo("Non-emission de message \"FAR\" en 48h")
assertThat(infractionSuspicionsSummary[1].title).isEqualTo("Non-emission de message \"FAR\" en 48h (NATINF 27689)")
assertThat(infractionSuspicionsSummary[2].numberOfOccurrences).isEqualTo(1)
assertThat(
infractionSuspicionsSummary[2].title,
).isEqualTo(
"Peche maritime non autorisee dans les eaux maritimes ou salees francaises par un navire de pays tiers a l'union europeenne",
"Peche maritime non autorisee dans les eaux maritimes ou salees francaises par un navire de pays tiers a l'union europeenne (NATINF 7059)",
)
assertThat(infractionSuspicionsSummary[3].numberOfOccurrences).isEqualTo(1)
assertThat(infractionSuspicionsSummary[3].title).isEqualTo("NATINF 123456")
Expand Down
5 changes: 1 addition & 4 deletions frontend/cypress/e2e/vessel_sidebar/reporting.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,17 +141,14 @@ context('Vessel sidebar reporting tab', () => {
// Then
// Summary
cy.get('[data-cy="vessel-reporting-summary"]').contains('Résumé des derniers signalements (6 dernières années)')
cy.get('[data-cy="vessel-reporting-summary"]').contains('Signalements "3 milles - Chaluts"')
cy.get('[data-cy="vessel-reporting-summary"]').contains('Signalements "3 milles - Chaluts (NATINF 7059)"')

// Dates occurrences of an alert
cy.get('*[data-cy="vessel-sidebar-reporting-tab-archive-year"]').eq(0).click()
cy.get('[data-cy="reporting-card"]').should('not.contain', '2è alerte le')
cy.get('[data-cy="reporting-card"]').should('not.contain', '1ère alerte le')
cy.clickLink('Voir les dates des autres alertes')
cy.get('[data-cy="reporting-card"]').should('contain', '2è alerte le')
cy.get('[data-cy="reporting-card"]').should('contain', '1ère alerte le')
cy.clickLink('Masquer les dates des autres alertes')
cy.get('[data-cy="reporting-card"]').should('not.contain', '2è alerte le')
cy.get('[data-cy="reporting-card"]').should('not.contain', '1ère alerte le')

cy.get('*[data-cy^="vessel-search-selected-vessel-close-title"]', { timeout: 10000 }).click()
Expand Down
Loading
Loading