From 3d524226a1be7c8ce1822c1536fd0da6657cc3a9 Mon Sep 17 00:00:00 2001 From: Pontoporeia Date: Mon, 8 Jun 2026 18:05:43 +0200 Subject: [PATCH] =?UTF-8?q?formulaire:=20correctifs=20identifiant/ann?= =?UTF-8?q?=C3=A9e,=20contact,=20fichiers=20optionnels?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Identifiant: mise à jour automatique quand l'année change en back-office (updateThesis + ThesisEditController) - Contact: hint enrichi (1 seul contact, formatage Instagram/Mastodon) - Fichiers: TFE rendu optionnel pour Site web/Performance/Installation (note d'intention reste obligatoire) --- .phpunit.result.cache | 2 +- TODO.md | 4 +++ .../assets/js/app/file-upload-filepond.js | 26 +++++++------- app/src/Controllers/ThesisEditController.php | 10 ++++++ app/src/Database.php | 15 ++++++-- app/src/FilepondHandler.php | 20 +++++------ app/storage/logs/error-2026-06-08.log | 36 +++++++++++++++++++ .../partials/form/fichiers-fragment.php | 12 ++++--- .../partials/form/fieldset-files.php | 2 +- .../partials/form/fieldset-tfe-info.php | 2 +- nginx/xamxam.conf | 22 ++++++------ 11 files changed, 107 insertions(+), 44 deletions(-) create mode 100644 app/storage/logs/error-2026-06-08.log diff --git a/.phpunit.result.cache b/.phpunit.result.cache index 01fbdde..ec78b6c 100644 --- a/.phpunit.result.cache +++ b/.phpunit.result.cache @@ -1 +1 @@ -{"version":2,"defects":{"CryptoTest::testEncryptDecryptEmptyString":7,"CryptoTest::testDecryptWithTamperedCiphertextReturnsEmpty":7,"EmailObfuscatorTest::testEmailTextReplacesBareEmail":7,"SystemControllerHelpersTest::testHumanBytesOneMB":7,"SystemControllerHelpersTest::testHumanBytesOneGB":7,"CryptoTest::testEncryptEmptyStringProducesCiphertext":7,"DatabaseExtendedTest::testFindOrCreateAuthorCreatesNew":7,"DatabaseExtendedTest::testFindOrCreateAuthorIdempotent":7,"DatabaseExtendedTest::testFindOrCreateAuthorWithEmail":7,"DatabaseExtendedTest::testFindOrCreateAuthorRejectsCSVArtefacts":7,"DatabaseExtendedTest::testDeduplicateLanguagesMergesCaseInsensitiveDupes":7,"RateLimitExtendedTest::testGetRemainingDecrements":7,"RateLimitExtendedTest::testGetRemainingAtLimit":7,"RateLimitExtendedTest::testGetRemainingReturnsZeroAfterExhaustion":7,"RateLimitExtendedTest::testGetResetTimePositiveAfterHits":7,"ThesisCreateValidationTest::testDuplicateTagsAreDeduplicated":8},"times":{"CryptoTest::testEncryptDecryptRoundTrip":0.035,"CryptoTest::testEncryptDecryptWithUnicode":0.002,"CryptoTest::testEncryptDecryptMultiline":0.002,"CryptoTest::testDifferentPlaintextsProduceDifferentCiphertexts":0.002,"CryptoTest::testSamePlaintextProducesDifferentCiphertexts":0.002,"CryptoTest::testIsEncryptedRecognizesEncryptedValue":0.01,"CryptoTest::testIsEncryptedRejectsPlaintext":0.003,"CryptoTest::testIsEncryptedReturnsFalseForEmptyString":0.003,"CryptoTest::testIsEncryptedRejectsInvalidBase64":0.002,"CryptoTest::testEncryptDecryptEmptyString":0.008,"CryptoTest::testDecryptEmptyStringReturnsEmpty":0.002,"CryptoTest::testDecryptInvalidBase64ReturnsInputGracefully":0.002,"CryptoTest::testDecryptTooShortBlobReturnsInputGracefully":0.002,"CryptoTest::testDecryptWithTamperedCiphertextReturnsEmpty":0.002,"CryptoTest::testDecryptValidBlobTamperedTagReturnsEmpty":0.005,"EmailObfuscatorTest::testEncodeContainsNoAtSign":0.015,"EmailObfuscatorTest::testEncodeOutputIsNumericEntities":0.002,"EmailObfuscatorTest::testEmailReturnsObfuscatedAddress":0.002,"EmailObfuscatorTest::testMailtoBuildsCorrectHrefStructure":0.007,"EmailObfuscatorTest::testEmailTextReplacesBareEmail":0.003,"EmailObfuscatorTest::testEmailTextReplacesMultipleEmails":0.004,"EmailObfuscatorTest::testMailtoInTextReplacesMailtoLinks":0.002,"EmailObfuscatorTest::testObfuscateHtmlReplacesAnchorTag":0.003,"EmailObfuscatorTest::testObfuscateHtmlKeepsNonMailtoLinksUnchanged":0.002,"EmailObfuscatorTest::testObfuscateHtmlPreservesCustomLinkText":0.002,"EmailObfuscatorTest::testEmptyStringReturnsEmpty":0.001,"EmailObfuscatorTest::testStringWithNoEmailsIsUnchanged":0.001,"EmailObfuscatorTest::testAlreadyObfuscatedContentIsNotDoubleEncoded":0.002,"EmailObfuscatorTest::testMultipleEmailsInOneString":0.002,"EmailObfuscatorTest::testEmailWithPlusSign":0.011,"StudentEmailTest::testBuildHtmlReturnsNonEmptyString":0.053,"StudentEmailTest::testBuildHtmlContainsKeyFields":0.006,"StudentEmailTest::testBuildHtmlEscapesSpecialCharacters":0.006,"StudentEmailTest::testBuildHtmlHandlesMissingOptionalFields":0.008,"StudentEmailTest::testBuildHtmlHandlesNullFieldsGracefully":0.003,"StudentEmailTest::testBuildHtmlHandlesEmptyArray":0.004,"StudentEmailTest::testBuildHtmlContainsLabelFields":0.005,"SystemControllerHelpersTest::testHumanBytesZero":0.219,"SystemControllerHelpersTest::testHumanBytesBelowOneKB":0.004,"SystemControllerHelpersTest::testHumanBytesOneKB":0.003,"SystemControllerHelpersTest::testHumanBytesOneMB":0.003,"SystemControllerHelpersTest::testHumanBytesOneGB":0.004,"SystemControllerHelpersTest::testHumanBytes1523MB":0.003,"SystemControllerHelpersTest::testHumanBytes2500GB":0.003,"SystemControllerHelpersTest::testDiskColorBelowWarning":0.005,"SystemControllerHelpersTest::testDiskColorWarning":0.005,"SystemControllerHelpersTest::testDiskColorCritical":0.005,"SystemControllerHelpersTest::testLogLineClassCrit":0.003,"SystemControllerHelpersTest::testLogLineClassError":0.003,"SystemControllerHelpersTest::testLogLineClassWarn":0.003,"SystemControllerHelpersTest::testLogLineClassNotice":0.009,"SystemControllerHelpersTest::testLogLineClassHttp500":0.003,"SystemControllerHelpersTest::testLogLineClassHttp300":0.002,"SystemControllerHelpersTest::testLogLineClassDefault":0.003,"SystemControllerHelpersTest::testNginxLineClassComment":0.003,"SystemControllerHelpersTest::testNginxLineClassBlock":0.004,"SystemControllerHelpersTest::testNginxLineClassDirective":0.003,"SystemControllerHelpersTest::testStatusLabelActive":0.004,"SystemControllerHelpersTest::testStatusLabelInactive":0.003,"SystemControllerHelpersTest::testStatusLabelFailed":0.003,"SystemControllerHelpersTest::testStatusLabelWarn":0.004,"SystemControllerHelpersTest::testStatusLabelUnknown":0.003,"SystemControllerHelpersTest::testStatusClassOk":0.005,"SystemControllerHelpersTest::testStatusClassWarn":0.003,"SystemControllerHelpersTest::testStatusClassError":0.009,"SystemControllerHelpersTest::testStatusClassUnknown":0.004,"TfeControllerOgTest::testBuildOgTagsReturnsAllRequiredKeys":0.003,"TfeControllerOgTest::testBuildOgTagsTitleIncludesAuthors":0.006,"TfeControllerOgTest::testBuildOgTagsImageEmptyWhenNoFiles":0.003,"TfeControllerOgTest::testBuildOgTagsImageFromCover":0.003,"TfeControllerOgTest::testBuildOgTagsImageFallbackToFirstImage":0.007,"TfeControllerOgTest::testBuildOgTagsUrlIncludesThesisId":0.004,"TfeControllerOgTest::testBuildOgTagsPublishedTimeFormatted":0.003,"TfeControllerOgTest::testBuildOgTagsPublishedTimeEmptyWhenNoYear":0.007,"TfeControllerOgTest::testBuildMetaDescriptionTruncatesLongSynopsis":0.007,"TfeControllerOgTest::testBuildMetaDescriptionKeepsShortSynopsis":0.011,"TfeControllerOgTest::testBuildMetaDescriptionEmptySynopsisReturnsDefault":0.004,"TfeControllerOgTest::testBuildMetaDescriptionStripsHtmlTags":0.004,"CryptoTest::testEncryptEmptyStringProducesCiphertext":0.003,"DatabaseExtendedTest::testEscapeLikeStringViaSearchConditions":0.003,"DatabaseExtendedTest::testBuildSearchConditionsEmptyParams":0.003,"DatabaseExtendedTest::testBuildSearchConditionsWithQuery":0.002,"DatabaseExtendedTest::testBuildSearchConditionsWithYear":0.002,"DatabaseExtendedTest::testBuildSearchConditionsWithAllFilters":0.002,"DatabaseExtendedTest::testFindDuplicateThesisExactMatch":0.003,"DatabaseExtendedTest::testFindDuplicateThesisMissesDifferentTitle":0.003,"DatabaseExtendedTest::testFindDuplicateThesisMissesDifferentYear":0.008,"DatabaseExtendedTest::testFindDuplicateThesisEmptyAuthorNamesReturnsNull":0.004,"DatabaseExtendedTest::testFindDuplicateThesisEmptyTable":0.004,"DatabaseExtendedTest::testFindDuplicateThesisNearDuplicateByLevenshtein":0.003,"DatabaseExtendedTest::testGenerateThesisIdentifierFirstInYear":0.002,"DatabaseExtendedTest::testGenerateThesisIdentifierIncrementsCorrectly":0.002,"DatabaseExtendedTest::testGenerateThesisIdentifierUsesMaxNotCount":0.002,"DatabaseExtendedTest::testGetCoverPathsForThesesReturnsPaths":0.002,"DatabaseExtendedTest::testGetCoverPathsForThesesReturnsEmptyForUnknownIds":0.009,"DatabaseExtendedTest::testGetCoverPathsForThesesEmptyInputReturnsEmpty":0.005,"DatabaseExtendedTest::testGetCoverPathsForThesesMultipleTheses":0.01,"DatabaseExtendedTest::testFindOrCreateAuthorCreatesNew":0.002,"DatabaseExtendedTest::testFindOrCreateAuthorIdempotent":0.002,"DatabaseExtendedTest::testFindOrCreateAuthorWithEmail":0.007,"DatabaseExtendedTest::testFindOrCreateAuthorRejectsCSVArtefacts":0.003,"DatabaseExtendedTest::testDeduplicateLanguagesMergesCaseInsensitiveDupes":0.003,"DatabaseExtendedTest::testRenameLanguageUpdatesName":0.053,"DatabaseExtendedTest::testMergeLanguageReassignsTheses":0.003,"DatabaseExtendedTest::testRenameTagUpdatesName":0.008,"DatabaseExtendedTest::testMergeTagReassignsTheses":0.003,"RateLimitExtendedTest::testCheckKeyCountsPerKey":0.061,"RateLimitExtendedTest::testCheckKeyDoesNotAffectDefaultCheck":0.004,"RateLimitExtendedTest::testGetRemainingDecrements":0,"RateLimitExtendedTest::testGetRemainingAtLimit":0,"RateLimitExtendedTest::testGetRemainingUsesClientIdentifier":0.001,"RateLimitExtendedTest::testCheckUsesConsistentIdentifier":0,"RateLimitExtendedTest::testGetRemainingReturnsZeroAfterExhaustion":0.003,"RateLimitExtendedTest::testGetResetTimeReturnsZeroWhenNoData":0.007,"RateLimitExtendedTest::testGetResetTimePositiveAfterHits":0.003,"RateLimitExtendedTest::testCleanupRemovesOldFiles":0.003,"ShareLinkExtendedTest::testListActiveReturnsOnlyActiveLinks":0.372,"ShareLinkExtendedTest::testListArchivedReturnsOnlyArchivedLinks":0.295,"ShareLinkExtendedTest::testFindBySlugHit":0.302,"ShareLinkExtendedTest::testFindBySlugMiss":0.002,"ShareLinkExtendedTest::testSetPasswordAndDecryptRoundTrip":0.3,"ShareLinkExtendedTest::testGetDecryptedPasswordOnNonexistentId":0.002,"ShareLinkExtendedTest::testUpdateChangesNameAndExpiration":0.323,"ShareLinkExtendedTest::testUpdateOnlyNameLeavesExpirationUnchanged":0.334,"ShareLinkExtendedTest::testUpdateClearsExpiration":0.326,"ShareLinkExtendedTest::testCreateWithLockedYear":0.312,"ShareLinkExtendedTest::testCreateWithInvalidLockedYearRejected":0.309,"ShareLinkExtendedTest::testUpdateLockedYear":0.33,"ShareLinkExtendedTest::testUpdateClearLockedYear":0.31,"ShareLinkExtendedTest::testIncrementUsage":0.316,"ShareLinkExtendedTest::testCreateDefaultsToTfeWhenInvalidObjet":0.332,"ShareLinkExtendedTest::testCreateAcceptsValidObjet":0.322,"RateLimitExtendedTest::testGetRemainingStartsAtMax":0.002,"RateLimitExtendedTest::testCheckDecrementsRemainingForSameIp":0.003,"RateLimitExtendedTest::testCheckAndCheckKeyAreIndependent":0.002,"RateLimitExtendedTest::testMultipleChecksFromSameClient":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusTitle":1.349,"AutofocusFieldForErrorTest::testCreateAutofocusAuthors":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusSynopsis":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusYear":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusOrientation":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusAP":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusFinality":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusLanguages":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusPromoteur":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusLecteurInterne":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusLecteurExterne":0.001,"AutofocusFieldForErrorTest::testCreateAutofocusFormats":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusLicense":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusUrl":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusTags":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusUnknownErrorReturnsNull":0.007,"AutofocusFieldForErrorTest::testEditAutofocusTitle":0.215,"AutofocusFieldForErrorTest::testEditAutofocusYear":0.003,"AutofocusFieldForErrorTest::testEditAutofocusSynopsis":0.006,"AutofocusFieldForErrorTest::testEditAutofocusAuthors":0.003,"AutofocusFieldForErrorTest::testEditAutofocusUnknownErrorReturnsNull":0.003,"AutofocusFieldForErrorTest::testCreateDoesNotLeakEditFieldNames":0.004,"ThesisCreateValidationTest::testValidSubmissionReturnsCleanedData":0.011,"ThesisCreateValidationTest::testMissingTitleThrowsException":0.006,"ThesisCreateValidationTest::testMissingAuthorsThrowsException":0.006,"ThesisCreateValidationTest::testMissingSynopsisThrowsException":0.004,"ThesisCreateValidationTest::testMissingOrientationInNonAdminModeThrowsException":0.014,"ThesisCreateValidationTest::testMissingAPProgramInNonAdminModeThrowsException":0.013,"ThesisCreateValidationTest::testMissingFinalityInNonAdminModeThrowsException":0.006,"ThesisCreateValidationTest::testInvalidYearFormatRejected":0.006,"ThesisCreateValidationTest::testYearZeroRejected":0.005,"ThesisCreateValidationTest::testYearBefore2000Rejected":0.005,"ThesisCreateValidationTest::testFarFutureYearRejected":0.006,"ThesisCreateValidationTest::testCurrentYearAccepted":0.005,"ThesisCreateValidationTest::testMalformedUrlRejected":0.003,"ThesisCreateValidationTest::testValidUrlAccepted":0.002,"ThesisCreateValidationTest::testDuplicateTagsAreDeduplicated":0.005,"ThesisCreateValidationTest::testMaxTenKeywordsEnforced":0.004,"ThesisCreateValidationTest::testXssPayloadStrippedFromTitle":0.007,"ThesisCreateValidationTest::testHtmlInSynopsisStripped":0.005,"ThesisCreateValidationTest::testMultipleAuthorsAreSorted":0.007,"ThesisCreateValidationTest::testMissingPromoteurInNonAdminModeThrowsException":0.003,"ThesisCreateValidationTest::testMissingLecteurInterneInNonAdminModeThrowsException":0.003,"ThesisCreateValidationTest::testMissingLanguagesInNonAdminModeThrowsException":0.004,"ThesisCreateValidationTest::testMissingFormatsInNonAdminModeThrowsException":0.003,"ThesisCreateValidationTest::testMissingLicenseWithLibreAccessThrowsException":0.009,"ThesisEditValidationTest::testLoadReturnsDataForKnownId":0.007,"ThesisEditValidationTest::testLoadThrowsOnUnknownId":0.005,"ThesisEditValidationTest::testLoadThrowsOnInvalidId":0.002,"ThesisEditValidationTest::testLoadThrowsOnNegativeId":0.002,"ThesisEditValidationTest::testCollectJuryMembersEmptyInput":0.002,"ThesisEditValidationTest::testCollectJuryMembersSinglePromoteur":0.002,"ThesisEditValidationTest::testCollectJuryMembersPromoteurUlb":0.002,"ThesisEditValidationTest::testCollectJuryMembersLecteurs":0.002,"ThesisEditValidationTest::testCollectJuryMembersDeduplicatesEmptyStrings":0.003,"ThesisEditValidationTest::testCollectJuryMembersScalarPromoteurAccepted":0.008,"ThesisEditValidationTest::testHandleWebsiteUrlStoresValidUrl":0.005,"ThesisEditValidationTest::testHandleWebsiteUrlSkipsInvalidUrl":0.003,"ThesisEditValidationTest::testHandleWebsiteUrlSkipsEmptyUrl":0.003,"ThesisEditValidationTest::testHandleWebsiteUrlNormalisesHttp":0.003,"ErrorHandlerTest::testFkThesesTableMentionsAllPossibleFields":0.794,"ErrorHandlerTest::testFkApPrograms":0.002,"ErrorHandlerTest::testFkFinalityTypes":0.001,"ErrorHandlerTest::testFkThesisLanguages":0.001,"ErrorHandlerTest::testFkThesisFormats":0.003,"ErrorHandlerTest::testFkThesisTags":0.005,"ErrorHandlerTest::testFkThesisSupervisors":0.002,"ErrorHandlerTest::testFkAccessTypes":0.002,"ErrorHandlerTest::testFkLicenseTypes":0.002,"ErrorHandlerTest::testFkAuthors":0.002,"ErrorHandlerTest::testFkQuotedTableName":0.002,"ErrorHandlerTest::testFkQuotedLanguages":0.002,"ErrorHandlerTest::testFkQuotedFormatTypes":0.001,"ErrorHandlerTest::testFkReferencesTags":0.001,"ErrorHandlerTest::testFkReferencesOrientations":0.001,"ErrorHandlerTest::testFkUnknownTableGenericFallback":0.001,"ErrorHandlerTest::testFkEmptyMessageGenericFallback":0.002,"ErrorHandlerTest::testUniqueConstraint":0.002,"ErrorHandlerTest::testNotNullConstraint":0.003,"ErrorHandlerTest::testGenericPdoError":0.004,"ErrorHandlerTest::testDuplicateThesisExceptionPassesThrough":0.009,"ErrorHandlerTest::testValidationExceptionPassesThrough":0.003,"ErrorHandlerTest::testGenericExceptionPassesThrough":0.002,"ErrorHandlerTest::testTypeErrorReturnsGeneric":0.002,"ErrorHandlerTest::testLogWithContext":0.024,"ErrorHandlerTest::testLogWithNullValues":0.003,"ErrorHandlerTest::testLogWithEmptyExtra":0.002,"ErrorHandlerTest::testFkQuotedColumnNames":0.002,"ErrorHandlerTest::testFkUpdateStatement":0.002,"ErrorHandlerTest::testFkWithReferencesAndInsert":0.002,"PureLogicTest::testSplitJuryByRoleAllRoles":0.064,"PureLogicTest::testSplitJuryByRoleEmptyNameSkipped":0.004,"PureLogicTest::testSplitJuryByRoleEmptyJury":0.002,"PureLogicTest::testCollectCaptionPathsVttByMime":0.002,"PureLogicTest::testCollectCaptionPathsVttByExtension":0.002,"PureLogicTest::testCollectCaptionPathsNoVttReturnsEmpty":0.002,"PureLogicTest::testDetectFileTypeByMime":0.002,"PureLogicTest::testDetectFileTypeByExtensionFallback":0.002,"SearchControllerTest::testHandleSearchReturnsCoverMapKey":0.058,"SearchControllerTest::testCoverMapContainsKnownThesis":0.007}} \ No newline at end of file +{"version":2,"defects":{"CryptoTest::testEncryptDecryptEmptyString":7,"CryptoTest::testDecryptWithTamperedCiphertextReturnsEmpty":7,"EmailObfuscatorTest::testEmailTextReplacesBareEmail":7,"SystemControllerHelpersTest::testHumanBytesOneMB":7,"SystemControllerHelpersTest::testHumanBytesOneGB":7,"CryptoTest::testEncryptEmptyStringProducesCiphertext":7,"DatabaseExtendedTest::testFindOrCreateAuthorCreatesNew":7,"DatabaseExtendedTest::testFindOrCreateAuthorIdempotent":7,"DatabaseExtendedTest::testFindOrCreateAuthorWithEmail":7,"DatabaseExtendedTest::testFindOrCreateAuthorRejectsCSVArtefacts":7,"DatabaseExtendedTest::testDeduplicateLanguagesMergesCaseInsensitiveDupes":7,"RateLimitExtendedTest::testGetRemainingDecrements":7,"RateLimitExtendedTest::testGetRemainingAtLimit":7,"RateLimitExtendedTest::testGetRemainingReturnsZeroAfterExhaustion":7,"RateLimitExtendedTest::testGetResetTimePositiveAfterHits":7,"ThesisCreateValidationTest::testDuplicateTagsAreDeduplicated":8},"times":{"CryptoTest::testEncryptDecryptRoundTrip":0,"CryptoTest::testEncryptDecryptWithUnicode":0,"CryptoTest::testEncryptDecryptMultiline":0,"CryptoTest::testDifferentPlaintextsProduceDifferentCiphertexts":0,"CryptoTest::testSamePlaintextProducesDifferentCiphertexts":0,"CryptoTest::testIsEncryptedRecognizesEncryptedValue":0.001,"CryptoTest::testIsEncryptedRejectsPlaintext":0,"CryptoTest::testIsEncryptedReturnsFalseForEmptyString":0,"CryptoTest::testIsEncryptedRejectsInvalidBase64":0,"CryptoTest::testEncryptDecryptEmptyString":0.008,"CryptoTest::testDecryptEmptyStringReturnsEmpty":0,"CryptoTest::testDecryptInvalidBase64ReturnsInputGracefully":0,"CryptoTest::testDecryptTooShortBlobReturnsInputGracefully":0,"CryptoTest::testDecryptWithTamperedCiphertextReturnsEmpty":0,"CryptoTest::testDecryptValidBlobTamperedTagReturnsEmpty":0,"EmailObfuscatorTest::testEncodeContainsNoAtSign":0,"EmailObfuscatorTest::testEncodeOutputIsNumericEntities":0,"EmailObfuscatorTest::testEmailReturnsObfuscatedAddress":0,"EmailObfuscatorTest::testMailtoBuildsCorrectHrefStructure":0,"EmailObfuscatorTest::testEmailTextReplacesBareEmail":0,"EmailObfuscatorTest::testEmailTextReplacesMultipleEmails":0,"EmailObfuscatorTest::testMailtoInTextReplacesMailtoLinks":0,"EmailObfuscatorTest::testObfuscateHtmlReplacesAnchorTag":0,"EmailObfuscatorTest::testObfuscateHtmlKeepsNonMailtoLinksUnchanged":0,"EmailObfuscatorTest::testObfuscateHtmlPreservesCustomLinkText":0,"EmailObfuscatorTest::testEmptyStringReturnsEmpty":0,"EmailObfuscatorTest::testStringWithNoEmailsIsUnchanged":0,"EmailObfuscatorTest::testAlreadyObfuscatedContentIsNotDoubleEncoded":0,"EmailObfuscatorTest::testMultipleEmailsInOneString":0,"EmailObfuscatorTest::testEmailWithPlusSign":0,"StudentEmailTest::testBuildHtmlReturnsNonEmptyString":0,"StudentEmailTest::testBuildHtmlContainsKeyFields":0,"StudentEmailTest::testBuildHtmlEscapesSpecialCharacters":0,"StudentEmailTest::testBuildHtmlHandlesMissingOptionalFields":0,"StudentEmailTest::testBuildHtmlHandlesNullFieldsGracefully":0,"StudentEmailTest::testBuildHtmlHandlesEmptyArray":0,"StudentEmailTest::testBuildHtmlContainsLabelFields":0,"SystemControllerHelpersTest::testHumanBytesZero":0,"SystemControllerHelpersTest::testHumanBytesBelowOneKB":0,"SystemControllerHelpersTest::testHumanBytesOneKB":0,"SystemControllerHelpersTest::testHumanBytesOneMB":0,"SystemControllerHelpersTest::testHumanBytesOneGB":0,"SystemControllerHelpersTest::testHumanBytes1523MB":0,"SystemControllerHelpersTest::testHumanBytes2500GB":0,"SystemControllerHelpersTest::testDiskColorBelowWarning":0,"SystemControllerHelpersTest::testDiskColorWarning":0,"SystemControllerHelpersTest::testDiskColorCritical":0,"SystemControllerHelpersTest::testLogLineClassCrit":0,"SystemControllerHelpersTest::testLogLineClassError":0,"SystemControllerHelpersTest::testLogLineClassWarn":0,"SystemControllerHelpersTest::testLogLineClassNotice":0,"SystemControllerHelpersTest::testLogLineClassHttp500":0,"SystemControllerHelpersTest::testLogLineClassHttp300":0,"SystemControllerHelpersTest::testLogLineClassDefault":0,"SystemControllerHelpersTest::testNginxLineClassComment":0.003,"SystemControllerHelpersTest::testNginxLineClassBlock":0.004,"SystemControllerHelpersTest::testNginxLineClassDirective":0.003,"SystemControllerHelpersTest::testStatusLabelActive":0,"SystemControllerHelpersTest::testStatusLabelInactive":0,"SystemControllerHelpersTest::testStatusLabelFailed":0,"SystemControllerHelpersTest::testStatusLabelWarn":0,"SystemControllerHelpersTest::testStatusLabelUnknown":0,"SystemControllerHelpersTest::testStatusClassOk":0,"SystemControllerHelpersTest::testStatusClassWarn":0,"SystemControllerHelpersTest::testStatusClassError":0,"SystemControllerHelpersTest::testStatusClassUnknown":0,"TfeControllerOgTest::testBuildOgTagsReturnsAllRequiredKeys":0,"TfeControllerOgTest::testBuildOgTagsTitleIncludesAuthors":0,"TfeControllerOgTest::testBuildOgTagsImageEmptyWhenNoFiles":0,"TfeControllerOgTest::testBuildOgTagsImageFromCover":0,"TfeControllerOgTest::testBuildOgTagsImageFallbackToFirstImage":0,"TfeControllerOgTest::testBuildOgTagsUrlIncludesThesisId":0,"TfeControllerOgTest::testBuildOgTagsPublishedTimeFormatted":0,"TfeControllerOgTest::testBuildOgTagsPublishedTimeEmptyWhenNoYear":0,"TfeControllerOgTest::testBuildMetaDescriptionTruncatesLongSynopsis":0.003,"TfeControllerOgTest::testBuildMetaDescriptionKeepsShortSynopsis":0,"TfeControllerOgTest::testBuildMetaDescriptionEmptySynopsisReturnsDefault":0,"TfeControllerOgTest::testBuildMetaDescriptionStripsHtmlTags":0,"CryptoTest::testEncryptEmptyStringProducesCiphertext":0,"DatabaseExtendedTest::testEscapeLikeStringViaSearchConditions":0,"DatabaseExtendedTest::testBuildSearchConditionsEmptyParams":0,"DatabaseExtendedTest::testBuildSearchConditionsWithQuery":0,"DatabaseExtendedTest::testBuildSearchConditionsWithYear":0,"DatabaseExtendedTest::testBuildSearchConditionsWithAllFilters":0,"DatabaseExtendedTest::testFindDuplicateThesisExactMatch":0,"DatabaseExtendedTest::testFindDuplicateThesisMissesDifferentTitle":0,"DatabaseExtendedTest::testFindDuplicateThesisMissesDifferentYear":0,"DatabaseExtendedTest::testFindDuplicateThesisEmptyAuthorNamesReturnsNull":0,"DatabaseExtendedTest::testFindDuplicateThesisEmptyTable":0,"DatabaseExtendedTest::testFindDuplicateThesisNearDuplicateByLevenshtein":0,"DatabaseExtendedTest::testGenerateThesisIdentifierFirstInYear":0,"DatabaseExtendedTest::testGenerateThesisIdentifierIncrementsCorrectly":0,"DatabaseExtendedTest::testGenerateThesisIdentifierUsesMaxNotCount":0,"DatabaseExtendedTest::testGetCoverPathsForThesesReturnsPaths":0,"DatabaseExtendedTest::testGetCoverPathsForThesesReturnsEmptyForUnknownIds":0,"DatabaseExtendedTest::testGetCoverPathsForThesesEmptyInputReturnsEmpty":0,"DatabaseExtendedTest::testGetCoverPathsForThesesMultipleTheses":0,"DatabaseExtendedTest::testFindOrCreateAuthorCreatesNew":0,"DatabaseExtendedTest::testFindOrCreateAuthorIdempotent":0,"DatabaseExtendedTest::testFindOrCreateAuthorWithEmail":0,"DatabaseExtendedTest::testFindOrCreateAuthorRejectsCSVArtefacts":0,"DatabaseExtendedTest::testDeduplicateLanguagesMergesCaseInsensitiveDupes":0,"DatabaseExtendedTest::testRenameLanguageUpdatesName":0.002,"DatabaseExtendedTest::testMergeLanguageReassignsTheses":0,"DatabaseExtendedTest::testRenameTagUpdatesName":0,"DatabaseExtendedTest::testMergeTagReassignsTheses":0,"RateLimitExtendedTest::testCheckKeyCountsPerKey":0,"RateLimitExtendedTest::testCheckKeyDoesNotAffectDefaultCheck":0,"RateLimitExtendedTest::testGetRemainingDecrements":0,"RateLimitExtendedTest::testGetRemainingAtLimit":0,"RateLimitExtendedTest::testGetRemainingUsesClientIdentifier":0.001,"RateLimitExtendedTest::testCheckUsesConsistentIdentifier":0,"RateLimitExtendedTest::testGetRemainingReturnsZeroAfterExhaustion":0,"RateLimitExtendedTest::testGetResetTimeReturnsZeroWhenNoData":0,"RateLimitExtendedTest::testGetResetTimePositiveAfterHits":0,"RateLimitExtendedTest::testCleanupRemovesOldFiles":0,"ShareLinkExtendedTest::testListActiveReturnsOnlyActiveLinks":0.176,"ShareLinkExtendedTest::testListArchivedReturnsOnlyArchivedLinks":0.175,"ShareLinkExtendedTest::testFindBySlugHit":0.175,"ShareLinkExtendedTest::testFindBySlugMiss":0,"ShareLinkExtendedTest::testSetPasswordAndDecryptRoundTrip":0.175,"ShareLinkExtendedTest::testGetDecryptedPasswordOnNonexistentId":0,"ShareLinkExtendedTest::testUpdateChangesNameAndExpiration":0.175,"ShareLinkExtendedTest::testUpdateOnlyNameLeavesExpirationUnchanged":0.175,"ShareLinkExtendedTest::testUpdateClearsExpiration":0.174,"ShareLinkExtendedTest::testCreateWithLockedYear":0.173,"ShareLinkExtendedTest::testCreateWithInvalidLockedYearRejected":0.174,"ShareLinkExtendedTest::testUpdateLockedYear":0.174,"ShareLinkExtendedTest::testUpdateClearLockedYear":0.174,"ShareLinkExtendedTest::testIncrementUsage":0.175,"ShareLinkExtendedTest::testCreateDefaultsToTfeWhenInvalidObjet":0.174,"ShareLinkExtendedTest::testCreateAcceptsValidObjet":0.173,"RateLimitExtendedTest::testGetRemainingStartsAtMax":0,"RateLimitExtendedTest::testCheckDecrementsRemainingForSameIp":0,"RateLimitExtendedTest::testCheckAndCheckKeyAreIndependent":0,"RateLimitExtendedTest::testMultipleChecksFromSameClient":0,"AutofocusFieldForErrorTest::testCreateAutofocusTitle":0.002,"AutofocusFieldForErrorTest::testCreateAutofocusAuthors":0,"AutofocusFieldForErrorTest::testCreateAutofocusSynopsis":0,"AutofocusFieldForErrorTest::testCreateAutofocusYear":0,"AutofocusFieldForErrorTest::testCreateAutofocusOrientation":0,"AutofocusFieldForErrorTest::testCreateAutofocusAP":0,"AutofocusFieldForErrorTest::testCreateAutofocusFinality":0,"AutofocusFieldForErrorTest::testCreateAutofocusLanguages":0,"AutofocusFieldForErrorTest::testCreateAutofocusPromoteur":0,"AutofocusFieldForErrorTest::testCreateAutofocusLecteurInterne":0,"AutofocusFieldForErrorTest::testCreateAutofocusLecteurExterne":0,"AutofocusFieldForErrorTest::testCreateAutofocusFormats":0,"AutofocusFieldForErrorTest::testCreateAutofocusLicense":0,"AutofocusFieldForErrorTest::testCreateAutofocusUrl":0,"AutofocusFieldForErrorTest::testCreateAutofocusTags":0,"AutofocusFieldForErrorTest::testCreateAutofocusUnknownErrorReturnsNull":0,"AutofocusFieldForErrorTest::testEditAutofocusTitle":0.001,"AutofocusFieldForErrorTest::testEditAutofocusYear":0,"AutofocusFieldForErrorTest::testEditAutofocusSynopsis":0,"AutofocusFieldForErrorTest::testEditAutofocusAuthors":0,"AutofocusFieldForErrorTest::testEditAutofocusUnknownErrorReturnsNull":0,"AutofocusFieldForErrorTest::testCreateDoesNotLeakEditFieldNames":0,"ThesisCreateValidationTest::testValidSubmissionReturnsCleanedData":0,"ThesisCreateValidationTest::testMissingTitleThrowsException":0,"ThesisCreateValidationTest::testMissingAuthorsThrowsException":0,"ThesisCreateValidationTest::testMissingSynopsisThrowsException":0,"ThesisCreateValidationTest::testMissingOrientationInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testMissingAPProgramInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testMissingFinalityInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testInvalidYearFormatRejected":0,"ThesisCreateValidationTest::testYearZeroRejected":0,"ThesisCreateValidationTest::testYearBefore2000Rejected":0,"ThesisCreateValidationTest::testFarFutureYearRejected":0,"ThesisCreateValidationTest::testCurrentYearAccepted":0,"ThesisCreateValidationTest::testMalformedUrlRejected":0,"ThesisCreateValidationTest::testValidUrlAccepted":0,"ThesisCreateValidationTest::testDuplicateTagsAreDeduplicated":0,"ThesisCreateValidationTest::testMaxTenKeywordsEnforced":0,"ThesisCreateValidationTest::testXssPayloadStrippedFromTitle":0,"ThesisCreateValidationTest::testHtmlInSynopsisStripped":0,"ThesisCreateValidationTest::testMultipleAuthorsAreSorted":0,"ThesisCreateValidationTest::testMissingPromoteurInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testMissingLecteurInterneInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testMissingLanguagesInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testMissingFormatsInNonAdminModeThrowsException":0,"ThesisCreateValidationTest::testMissingLicenseWithLibreAccessThrowsException":0,"ThesisEditValidationTest::testLoadReturnsDataForKnownId":0.001,"ThesisEditValidationTest::testLoadThrowsOnUnknownId":0.001,"ThesisEditValidationTest::testLoadThrowsOnInvalidId":0,"ThesisEditValidationTest::testLoadThrowsOnNegativeId":0,"ThesisEditValidationTest::testCollectJuryMembersEmptyInput":0,"ThesisEditValidationTest::testCollectJuryMembersSinglePromoteur":0,"ThesisEditValidationTest::testCollectJuryMembersPromoteurUlb":0,"ThesisEditValidationTest::testCollectJuryMembersLecteurs":0,"ThesisEditValidationTest::testCollectJuryMembersDeduplicatesEmptyStrings":0,"ThesisEditValidationTest::testCollectJuryMembersScalarPromoteurAccepted":0,"ThesisEditValidationTest::testHandleWebsiteUrlStoresValidUrl":0,"ThesisEditValidationTest::testHandleWebsiteUrlSkipsInvalidUrl":0,"ThesisEditValidationTest::testHandleWebsiteUrlSkipsEmptyUrl":0,"ThesisEditValidationTest::testHandleWebsiteUrlNormalisesHttp":0,"ErrorHandlerTest::testFkThesesTableMentionsAllPossibleFields":0,"ErrorHandlerTest::testFkApPrograms":0,"ErrorHandlerTest::testFkFinalityTypes":0,"ErrorHandlerTest::testFkThesisLanguages":0,"ErrorHandlerTest::testFkThesisFormats":0,"ErrorHandlerTest::testFkThesisTags":0,"ErrorHandlerTest::testFkThesisSupervisors":0,"ErrorHandlerTest::testFkAccessTypes":0,"ErrorHandlerTest::testFkLicenseTypes":0,"ErrorHandlerTest::testFkAuthors":0,"ErrorHandlerTest::testFkQuotedTableName":0,"ErrorHandlerTest::testFkQuotedLanguages":0,"ErrorHandlerTest::testFkQuotedFormatTypes":0,"ErrorHandlerTest::testFkReferencesTags":0,"ErrorHandlerTest::testFkReferencesOrientations":0,"ErrorHandlerTest::testFkUnknownTableGenericFallback":0,"ErrorHandlerTest::testFkEmptyMessageGenericFallback":0,"ErrorHandlerTest::testUniqueConstraint":0,"ErrorHandlerTest::testNotNullConstraint":0,"ErrorHandlerTest::testGenericPdoError":0,"ErrorHandlerTest::testDuplicateThesisExceptionPassesThrough":0,"ErrorHandlerTest::testValidationExceptionPassesThrough":0,"ErrorHandlerTest::testGenericExceptionPassesThrough":0,"ErrorHandlerTest::testTypeErrorReturnsGeneric":0,"ErrorHandlerTest::testLogWithContext":0,"ErrorHandlerTest::testLogWithNullValues":0,"ErrorHandlerTest::testLogWithEmptyExtra":0,"ErrorHandlerTest::testFkQuotedColumnNames":0,"ErrorHandlerTest::testFkUpdateStatement":0,"ErrorHandlerTest::testFkWithReferencesAndInsert":0,"PureLogicTest::testSplitJuryByRoleAllRoles":0,"PureLogicTest::testSplitJuryByRoleEmptyNameSkipped":0,"PureLogicTest::testSplitJuryByRoleEmptyJury":0,"PureLogicTest::testCollectCaptionPathsVttByMime":0,"PureLogicTest::testCollectCaptionPathsVttByExtension":0,"PureLogicTest::testCollectCaptionPathsNoVttReturnsEmpty":0,"PureLogicTest::testDetectFileTypeByMime":0,"PureLogicTest::testDetectFileTypeByExtensionFallback":0,"SearchControllerTest::testHandleSearchReturnsCoverMapKey":0.002,"SearchControllerTest::testCoverMapContainsKnownThesis":0.001}} \ No newline at end of file diff --git a/TODO.md b/TODO.md index 5e45e48..3c69bc1 100644 --- a/TODO.md +++ b/TODO.md @@ -6,3 +6,7 @@ - [x] Commit + jj new - [x] Ajouter l'affichage de la finalité sur la page publique TFE (tfe.php) - [x] Fix "ATELIERS PLURIDISCIPLINAIRES" mid-word break in repertoire column headers +- [x] Mise à jour auto de l'identifiant quand l'année change en back-office +- [x] Améliorer les hints du champ contact dans le formulaire étudiant +- [x] Rendre le fichier TFE optionnel pour Site web / Performance / Installation (note d'intention reste obligatoire) +- [x] Augmenter les limites d'upload : vidéo/audio 8 GB, images/archives 1 GB, nginx 8 GB diff --git a/app/public/assets/js/app/file-upload-filepond.js b/app/public/assets/js/app/file-upload-filepond.js index 7978c16..33a32be 100644 --- a/app/public/assets/js/app/file-upload-filepond.js +++ b/app/public/assets/js/app/file-upload-filepond.js @@ -47,24 +47,24 @@ labelFileTypeNotAllowed: "Format non accepté", fileValidateTypeLabelExpectedTypes: "PDF, Images, Vidéos, Audio, VTT, Archives", - maxFileSize: "500MB", + maxFileSize: "1GB", labelMaxFileSizeExceeded: "Fichier trop volumineux", labelMaxFileSize: "Taille max: {filesize}", allowMultiple: true, // Per-extension size limits: certain types get higher caps. perExtensionMaxSize: { pdf: "100MB", - mp4: "2GB", - webm: "2GB", - ogv: "2GB", - mov: "2GB", - mp3: "2GB", - ogg: "2GB", - oga: "2GB", - wav: "2GB", - flac: "2GB", - aac: "2GB", - m4a: "2GB", + mp4: "8GB", + webm: "8GB", + ogv: "8GB", + mov: "8GB", + mp3: "8GB", + ogg: "8GB", + oga: "8GB", + wav: "8GB", + flac: "8GB", + aac: "8GB", + m4a: "8GB", }, }, annexe: { @@ -76,7 +76,7 @@ ], labelFileTypeNotAllowed: "Format non accepté", fileValidateTypeLabelExpectedTypes: "PDF, ZIP, TAR, GZ", - maxFileSize: "500MB", + maxFileSize: "1GB", labelMaxFileSizeExceeded: "Fichier trop volumineux", labelMaxFileSize: "Taille max: {filesize}", allowMultiple: true, diff --git a/app/src/Controllers/ThesisEditController.php b/app/src/Controllers/ThesisEditController.php index fa5be1c..ba60861 100644 --- a/app/src/Controllers/ThesisEditController.php +++ b/app/src/Controllers/ThesisEditController.php @@ -217,6 +217,16 @@ class ThesisEditController 'cc2r' => !empty($post['cc2r']), 'license_custom' => trim($post['license_custom'] ?? ''), ]; + // Regenerate identifier if year changed + $oldThesis = $this->db->getThesis($thesisId); + $oldYear = (int)($oldThesis['year'] ?? 0); + $newYear = $meta['year']; + if ($newYear !== $oldYear && $newYear >= 2000) { + $newIdentifier = $this->db->generateThesisIdentifier($newYear); + $meta['identifier'] = $newIdentifier; + error_log('[ThesisEdit] Year changed ' . $oldYear . ' → ' . $newYear . ', new identifier: ' . $newIdentifier); + } + $this->db->updateThesis($thesisId, $meta); error_log('[ThesisEdit] Step 1 OK — thesis_id=' . $thesisId); diff --git a/app/src/Database.php b/app/src/Database.php index 638fea1..3594edf 100644 --- a/app/src/Database.php +++ b/app/src/Database.php @@ -2122,8 +2122,16 @@ class Database $this->fetchRow('theses', $thesisId) ); - $stmt = $this->pdo->prepare(' + $identifierCol = ''; + $params = []; + if (array_key_exists('identifier', $data)) { + $identifierCol = 'identifier = ?,'; + $params[] = $data['identifier']; + } + + $stmt = $this->pdo->prepare(" UPDATE theses SET + $identifierCol title = ?, subtitle = ?, year = ?, @@ -2144,7 +2152,7 @@ class Database cc2r = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? - '); + "); $orientation = ($data['orientation_id'] ?? null) ? (int)$data['orientation_id'] : null; $ap = ($data['ap_program_id'] ?? null) ? (int)$data['ap_program_id'] : null; $finality = ($data['finality_id'] ?? null) ? (int)$data['finality_id'] : null; @@ -2153,7 +2161,7 @@ class Database error_log("[DB:updateThesis] thesis_id=$thesisId orientation=$orientation ap=$ap finality=$finality license=$license access=$access"); - $stmt->execute([ + $params = array_merge($params, [ $data['title'], !empty($data['subtitle']) ? $data['subtitle'] : null, (int)$data['year'], @@ -2174,6 +2182,7 @@ class Database !empty($data['cc2r']) ? 1 : 0, $thesisId, ]); + $stmt->execute($params); } /** diff --git a/app/src/FilepondHandler.php b/app/src/FilepondHandler.php index fc4b174..06ca7f5 100644 --- a/app/src/FilepondHandler.php +++ b/app/src/FilepondHandler.php @@ -52,19 +52,19 @@ class FilepondHandler ]; public const QUEUE_SIZE_LIMITS = [ - 'cover' => 20 * 1024 * 1024, // 20 MB - 'note_intention' => 100 * 1024 * 1024, // 100 MB - 'tfe' => 500 * 1024 * 1024, // 500 MB - 'video' => 500 * 1024 * 1024, // 500 MB - 'audio' => 500 * 1024 * 1024, // 500 MB - 'annexe' => 500 * 1024 * 1024, // 500 MB - 'peertube_video' => 500 * 1024 * 1024, // 500 MB - 'peertube_audio' => 500 * 1024 * 1024, // 500 MB + 'cover' => 20 * 1024 * 1024, // 20 MB + 'note_intention' => 100 * 1024 * 1024, // 100 MB + 'tfe' => 1024 * 1024 * 1024, // 1 GB (default for non-AV, non-PDF) + 'video' => 8 * 1024 * 1024 * 1024, // 8 GB + 'audio' => 8 * 1024 * 1024 * 1024, // 8 GB + 'annexe' => 1024 * 1024 * 1024, // 1 GB + 'peertube_video' => 8 * 1024 * 1024 * 1024, // 8 GB + 'peertube_audio' => 8 * 1024 * 1024 * 1024, // 8 GB ]; public const AV_EXTENSIONS = ['mp4', 'webm', 'ogv', 'mov', 'mp3', 'ogg', 'oga', 'wav', 'flac', 'aac', 'm4a']; - public const MAX_PDF_SIZE = 100 * 1024 * 1024; // 100 MB - public const MAX_AV_SIZE = 2 * 1024 * 1024 * 1024; // 2 GB + public const MAX_PDF_SIZE = 100 * 1024 * 1024; // 100 MB + public const MAX_AV_SIZE = 8 * 1024 * 1024 * 1024; // 8 GB // ── Log prefix for distinguishing admin vs partage ─────────────────────── diff --git a/app/storage/logs/error-2026-06-08.log b/app/storage/logs/error-2026-06-08.log new file mode 100644 index 0000000..b90ed7b --- /dev/null +++ b/app/storage/logs/error-2026-06-08.log @@ -0,0 +1,36 @@ +{"timestamp":"2026-06-08T16:11:04+00:00","ip":"unknown","user_agent":"","context":"test_context","exception":"Exception","message":"test message","trace":"#0 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(1667): ErrorHandlerTest->testLogWithContext() +#1 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(519): PHPUnit\\Framework\\TestCase->runTest() +#2 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestRunner/TestRunner.php(87): PHPUnit\\Framework\\TestCase->runBare() +#3 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(365): PHPUnit\\Framework\\TestRunner->run() +#4 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestCase->run() +#5 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run() +#6 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run() +#7 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run() +#8 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/Application.php(211): PHPUnit\\TextUI\\TestRunner->run() +#9 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/phpunit(104): PHPUnit\\TextUI\\Application->run() +#10 /home/padlock/repos/xamxam/vendor/bin/phpunit(122): include('...') +#11 {main}","extra":{"thesis_id":42,"slug":"20250101-TEST1234"}} +{"timestamp":"2026-06-08T16:11:04+00:00","ip":"unknown","user_agent":"","context":"test_null","exception":"PDOException","message":"test","trace":"#0 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(1667): ErrorHandlerTest->testLogWithNullValues() +#1 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(519): PHPUnit\\Framework\\TestCase->runTest() +#2 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestRunner/TestRunner.php(87): PHPUnit\\Framework\\TestCase->runBare() +#3 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(365): PHPUnit\\Framework\\TestRunner->run() +#4 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestCase->run() +#5 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run() +#6 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run() +#7 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run() +#8 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/Application.php(211): PHPUnit\\TextUI\\TestRunner->run() +#9 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/phpunit(104): PHPUnit\\TextUI\\Application->run() +#10 /home/padlock/repos/xamxam/vendor/bin/phpunit(122): include('...') +#11 {main}","extra":{"id":null,"name":"foo"}} +{"timestamp":"2026-06-08T16:11:04+00:00","ip":"unknown","user_agent":"","context":"test_empty","exception":"RuntimeException","message":"bare","trace":"#0 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(1667): ErrorHandlerTest->testLogWithEmptyExtra() +#1 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(519): PHPUnit\\Framework\\TestCase->runTest() +#2 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestRunner/TestRunner.php(87): PHPUnit\\Framework\\TestCase->runBare() +#3 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestCase.php(365): PHPUnit\\Framework\\TestRunner->run() +#4 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestCase->run() +#5 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run() +#6 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/Framework/TestSuite.php(369): PHPUnit\\Framework\\TestSuite->run() +#7 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/TestRunner.php(64): PHPUnit\\Framework\\TestSuite->run() +#8 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/src/TextUI/Application.php(211): PHPUnit\\TextUI\\TestRunner->run() +#9 /home/padlock/repos/xamxam/vendor/phpunit/phpunit/phpunit(104): PHPUnit\\TextUI\\Application->run() +#10 /home/padlock/repos/xamxam/vendor/bin/phpunit(122): include('...') +#11 {main}"} diff --git a/app/templates/partials/form/fichiers-fragment.php b/app/templates/partials/form/fichiers-fragment.php index 0b81cfb..96a9eac 100644 --- a/app/templates/partials/form/fichiers-fragment.php +++ b/app/templates/partials/form/fichiers-fragment.php @@ -36,6 +36,10 @@ $selectedFormats = isset($_POST['formats']) && is_array($_POST['formats']) $adminMode = ($_POST['admin_mode'] ?? '0') === '1'; $editMode = ($_POST['edit_mode'] ?? '0') === '1'; +// TFE file is optional when format is Site web (3), Performance (4) or Installation (6) +$noTfeFileFormats = [3, 4, 6]; +$tfeFileOptional = !empty(array_intersect($selectedFormats, $noTfeFileFormats)); + $websiteUrl = htmlspecialchars($_POST['website_url'] ?? ''); $websiteLabel = htmlspecialchars($_POST['website_label'] ?? ''); ?> @@ -126,20 +130,20 @@ $websiteLabel = htmlspecialchars($_POST['website_label'] ?? '');
- +
+ data-existing-files=''> Glissez pour réordonner.

- PDF (max 100 MB) · Images (max 500 MB) · Vidéo & Audio (max 2 GB) · VTT · Archives (max 500 MB). + PDF (max 100 MB) · Images (max 1 GB) · Vidéo & Audio (max 8 GB) · VTT · Archives (max 1 GB).
→ PDFs trop lourds ? https://bentopdf.com/

Vidéos et audio hébergés sur PeerTube. @@ -172,7 +176,7 @@ $websiteLabel = htmlspecialchars($_POST['website_label'] ?? ''); class="tfe-file-picker" data-queue-type="annexe" data-existing-files=''> - PDF ou archives ZIP/TAR. Max 500 MB. Glissez pour réordonner. + PDF ou archives ZIP/TAR. Max 1 GB. Glissez pour réordonner.
diff --git a/app/templates/partials/form/fieldset-tfe-info.php b/app/templates/partials/form/fieldset-tfe-info.php index 46a1c41..8c82784 100644 --- a/app/templates/partials/form/fieldset-tfe-info.php +++ b/app/templates/partials/form/fieldset-tfe-info.php @@ -61,7 +61,7 @@ $adminMode = $adminMode ?? false; 'email']; - $hint = 'Ce contact sera visible publiquement sur la fiche du TFE.'; + $hint = 'Un seul contact. Indiquez l\'URL complète pour un site (https://…), l\'adresse mail, le nom d\'utilisateur avec @ pour Instagram (@pseudo), ou l\'adresse complète pour Mastodon (@pseudo@instance). Ce contact sera visible publiquement sur la fiche du TFE.'; include APP_ROOT . '/templates/partials/form/text-field.php'; ?> diff --git a/nginx/xamxam.conf b/nginx/xamxam.conf index c3512fb..61e04e9 100644 --- a/nginx/xamxam.conf +++ b/nginx/xamxam.conf @@ -49,8 +49,8 @@ server { # server_tokens off; # Max upload size (for thesis files — can include video) - client_max_body_size 1024M; - client_body_timeout 300s; + client_max_body_size 8192M; + client_body_timeout 600s; # Logging access_log /var/log/nginx/xamxam_access.log; @@ -140,11 +140,11 @@ server { fastcgi_pass unix:/var/run/php/php8.4-fpm.sock; # Security parameters (must be <= client_max_body_size) - fastcgi_param PHP_VALUE "upload_max_filesize=1024M \n post_max_size=1024M"; + fastcgi_param PHP_VALUE "upload_max_filesize=8192M \n post_max_size=8192M"; # Timeouts - fastcgi_read_timeout 300; - fastcgi_send_timeout 300; + fastcgi_read_timeout 600; + fastcgi_send_timeout 600; } # Additional security headers for admin @@ -160,9 +160,9 @@ server { location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/var/run/php/php8.4-fpm.sock; - fastcgi_param PHP_VALUE "upload_max_filesize=1024M \n post_max_size=1024M"; - fastcgi_read_timeout 300; - fastcgi_send_timeout 300; + fastcgi_param PHP_VALUE "upload_max_filesize=8192M \n post_max_size=8192M"; + fastcgi_read_timeout 600; + fastcgi_send_timeout 600; } try_files $uri /index.php$is_args$args; } @@ -188,11 +188,11 @@ server { fastcgi_pass unix:/var/run/php/php8.4-fpm.sock; # Security parameters (must be <= client_max_body_size) - fastcgi_param PHP_VALUE "upload_max_filesize=1024M \n post_max_size=1024M"; + fastcgi_param PHP_VALUE "upload_max_filesize=8192M \n post_max_size=8192M"; # Timeouts - fastcgi_read_timeout 300; - fastcgi_send_timeout 300; + fastcgi_read_timeout 600; + fastcgi_send_timeout 600; } # All other clean URLs — fall through to front controller