diff --git a/Dockerfile b/Dockerfile index e4553cab2507bae33a77e5db6dac9519f8926578..3fa7ae87d1bdf57c0f45eef8e65a30040af53f5b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,22 +1,22 @@ -FROM nextcloud:29.0.16-fpm AS nextcloud +FROM nextcloud:30.0.13-fpm AS nextcloud ARG BASE_DIR="/usr/src/nextcloud" ARG TMP_PATCH_DIR="/tmp/build_patches" -ARG THEME_HELPER_JOB_ID="1245676" +ARG THEME_HELPER_JOB_ID="1273671" ARG NOTES_VERSION="4.11.0" -ARG CONTACTS_JOB_ID="1156314" -ARG CALENDAR_JOB_ID="1242275" -ARG EMAIL_RECOVERY_JOB_ID="1245694" -ARG EA_JOB_ID="1241536" -ARG LAUNCHER_JOB_ID="1235119" +ARG CONTACTS_JOB_ID="1273569" +ARG CALENDAR_JOB_ID="1273554" +ARG EMAIL_RECOVERY_JOB_ID="1273659" +ARG EA_JOB_ID="1273772" +ARG LAUNCHER_JOB_ID="1273647" ARG GOOGLE_INTEGRATION_VERSION="3.2.0" -ARG DASHBOARD_JOB_ID="1235127" +ARG DASHBOARD_JOB_ID="1273623" ARG SNAPPY_VERSION="2.37.2" ARG SNAPPY_THEME_VERSION="4.0.4" -ARG USER_MIGRATION_JOB_ID="1239694" +ARG USER_MIGRATION_JOB_ID="1273698" ARG MEMORIES_VERSION="7.5.2" ARG DROP_ACCOUNT_VERSION="2.7.1" -RUN sed -i 's/29,0,16,1/29,0,16,4/' ${BASE_DIR}/version.php +RUN sed -i 's/30,0,13,1/30,0,13,8/' ${BASE_DIR}/version.php COPY custom_entrypoint.sh / RUN chmod +x /custom_entrypoint.sh RUN mkdir -p /var/www/skeleton/Documents && mkdir -p /var/www/skeleton/Images @@ -240,7 +240,7 @@ RUN sed -i 's/$this->getAvatarImage($user)/null/' ${BASE_DIR}/apps/dav/lib/CardD # RUN cd ${BASE_DIR}/dist && sed -i 's/resetPassword:!1/resetPassword:!1||Z.showResetPassword==="1"/' core-login.js # add attr about how many notifications to notif icon -RUN sed -i 's/attrs:{id:"notifications",/attrs:{id:"notifications","data-has-notifications":0!==t.notifications.length,/' ${BASE_DIR}/apps/notifications/js/notifications-src_NotificationsApp_vue.js +RUN sed -i 's/attrs:{id:"notifications",/attrs:{id:"notifications","data-has-notifications":0!==t.notifications.length,/' ${BASE_DIR}/apps/notifications/js/NotificationsApp-atbzHwwu.chunk.mjs # Rename Memories to Gallery RUN sed -i 's/Memories<\/name>/Gallery<\/name>/g' ${BASE_DIR}/custom_apps/memories/appinfo/info.xml @@ -249,14 +249,14 @@ RUN cd ${BASE_DIR}/custom_apps/memories/js && sed -i 's/Memories Settings/Galler # autocomplete leak tweak apps frontend with sed, disable group suggestion -RUN cd ${BASE_DIR}/custom_apps/contacts && sed -i 's/"GROUP","INDIVIDUAL"/"INDIVIDUAL"/g' js/contacts-main.js +RUN cd ${BASE_DIR}/custom_apps/contacts && sed -i 's/\["INDIVIDUAL"\]/\[\]/g' js/contacts-main.mjs RUN cd ${BASE_DIR}/custom_apps/calendar && sed -i 's/"GROUP","INDIVIDUAL"/"INDIVIDUAL"/g' js/calendar-main.js RUN cd ${BASE_DIR}/custom_apps/calendar && sed -i 's/{name:\[a,"displayname"\]},//' js/calendar-main.js RUN cd ${BASE_DIR}/custom_apps/notes && sed -i 's/OCA\\Notes\\Migration\\EditorHint<\/step>//g' appinfo/info.xml RUN cd ${BASE_DIR}/apps/theming && sed -i 's/OCA\\Theming\\Migration\\MigrateUserConfig<\/step>//g' appinfo/info.xml # sharing search by email -RUN cd ${BASE_DIR}/custom_apps/contacts && sed -i 's/kM.principalPropertySearchByDisplayname(t);/kM.principalPropertySearch(\[{name:\["http:\/\/sabredav.org\/ns","email-address"\]\}],t,"anyof");/g' js/contacts-main.js +#RUN cd ${BASE_DIR}/custom_apps/contacts && sed -i 's/kM.principalPropertySearchByDisplayname(t);/kM.principalPropertySearch(\[{name:\["http:\/\/sabredav.org\/ns","email-address"\]\}],t,"anyof");/g' js/contacts-main.js # Remove colored background from email template logo RUN sed -i 's/$this->header, \[$this->themingDefaults->getDefaultColorPrimary()/$this->header, \["none"/' ${BASE_DIR}/lib/private/Mail/EMailTemplate.php @@ -269,7 +269,7 @@ RUN sed -i 's/$this->changeAvatar/\/\/ $this->changeAvatar/' ${BASE_DIR}/custom_ RUN sed -i '/OCA\\DAV\\Migration\\CalDAVRemoveEmptyValue<\/step>/d' ${BASE_DIR}/apps/dav/appinfo/info.xml # Hide `Play sound when a call started (requires Nextcloud Talk)` checkbox from notification setting -RUN sed -i 's/attrs:{checked:e\.config\.sound_talk}/staticClass:"notification_talk",attrs:{checked:e\.config\.sound_talk}/g' ${BASE_DIR}/apps/notifications/js/notifications-settings.js +RUN sed -i 's/attrs:{checked:r\.config\.sound_talk}/staticClass:"notification_talk",attrs:{checked:r\.config\.sound_talk}/g' ${BASE_DIR}/apps/notifications/js/notifications-settings.mjs # Hide `Navigation bar settings` from theming RUN sed -i 's/{attrs:{name:t.t("theming","Navigation bar settings")}}/{staticClass:"navigation-bar-settings",attrs:{name:t.t("theming","Navigation bar settings")}}/g' ${BASE_DIR}/dist/theming-personal-theming.js diff --git a/patches/002-login-without-domain.patch b/patches/002-login-without-domain.patch index 45e02cb9273376eae389d5b87389c8466e35f486..5021b6d20bb8965735ca6a1abdefbfc6b05fee20 100644 --- a/patches/002-login-without-domain.patch +++ b/patches/002-login-without-domain.patch @@ -9,10 +9,10 @@ only the admin user (also configured in env var) will not have his login appende diff --git ./core/Controller/LoginController.php ./core/Controller/LoginController-new.php --- ./core/Controller/LoginController.php 2024-04-26 15:08:54.979407062 +0530 +++ ./core/Controller/LoginController-new.php 2024-04-26 15:16:48.582366408 +0530 -@@ -340,6 +340,26 @@ - $this->l10n->t('Unsupported email length (>255)') +@@ -315,6 +315,27 @@ ); } + + $user = mb_strtolower($user, 'UTF-8'); + $actualUser = $user; + $legacyDomain = $this->config->getSystemValue('legacy_domain', ''); @@ -33,10 +33,11 @@ diff --git ./core/Controller/LoginController.php ./core/Controller/LoginControll + if (!$this->userManager->userExists($user)) { + $user = $user . $legacyDomainSuffix; + } - ++ $data = new LoginData( $this->request, -@@ -353,7 +373,7 @@ + $user, +@@ -327,7 +348,7 @@ if (!$result->isSuccess()) { return $this->createLoginFailedResponse( $data->getUsername(), @@ -45,14 +46,14 @@ diff --git ./core/Controller/LoginController.php ./core/Controller/LoginControll $redirect_url, $result->getErrorMessage() ); + --- ./core/Controller/WebAuthnController.php 2023-04-21 15:18:58.813220092 +0530 +++ ./core/Controller/WebAuthnController-new.php 2023-04-21 15:24:40.036538414 +0530 -@@ -69,6 +69,27 @@ +@@ -48,6 +48,27 @@ $this->logger->debug('Converting login name to UID'); $uid = $loginName; -+ -+ $uid = trim($uid); ++ $uid = trim($uid); + $uid = mb_strtolower($uid, 'UTF-8'); + $legacyDomain = \OC::$server->getConfig()->getSystemValue('legacy_domain', ''); + $legacyDomainSuffix = !empty($legacyDomain) ? '@' . $legacyDomain : ''; @@ -72,13 +73,14 @@ diff --git ./core/Controller/LoginController.php ./core/Controller/LoginControll + if (!\OC::$server->get(\OCP\IUserManager::class)->userExists($uid)) { + $uid = $uid . $legacyDomainSuffix; + } ++ Util::emitHook( '\OCA\Files_Sharing\API\Server2Server', 'preLoginNameUsedAsUserName', --- ./lib/private/User/Session.php 2023-04-21 15:27:00.417034490 +0530 +++ ./lib/private/User/Session-new.php 2023-04-21 15:28:18.309111435 +0530 -@@ -413,6 +413,10 @@ +@@ -383,6 +383,10 @@ $remoteAddress = $request->getRemoteAddress(); $currentDelay = $throttler->sleepDelayOrThrowOnMax($remoteAddress, 'login'); @@ -88,4 +90,4 @@ diff --git ./core/Controller/LoginController.php ./core/Controller/LoginControll + if ($this->manager instanceof PublicEmitter) { $this->manager->emit('\OC\User', 'preLogin', [$user, $password]); - } + } \ No newline at end of file diff --git a/patches/003-contact-search-removal.patch b/patches/003-contact-search-removal.patch index 26b84267c06018b5fe248f76eb24b51e049114f0..aef513aa0fa8c8cd328a7b840706b3e13aa700ef 100644 --- a/patches/003-contact-search-removal.patch +++ b/patches/003-contact-search-removal.patch @@ -7,7 +7,7 @@ This patch removes the top right icon enabling the global user search function a diff --git layout.user.php layout.user.php-new --- ./core/templates/layout.user.php 2023-03-28 14:54:05.873566570 +0530 +++ ./core/templates/layout.user-new.php 2023-03-28 14:54:35.044218831 +0530 -@@ -70,7 +70,6 @@ +@@ -76,7 +76,6 @@
diff --git a/patches/004-contact-search-controller-removal.patch b/patches/004-contact-search-controller-removal.patch index 996d751e6f53c471b94cfee61a42c0b65e90d4dc..f8e49e4b80ddbe716ab296595773b9d21d29a162 100644 --- a/patches/004-contact-search-controller-removal.patch +++ b/patches/004-contact-search-controller-removal.patch @@ -7,8 +7,8 @@ This patch removes some results from the contact menu controller, not to leak us diff --git ContactsMenuController.php ContactsMenuController-new.php --- ./core/Controller/ContactsMenuController.php 2023-02-01 21:40:07.515628276 +0530 +++ ./core/Controller/ContactsMenuController-new.php 2023-02-01 21:39:07.398140201 +0530 -@@ -50,7 +50,7 @@ - */ +@@ -32,7 +32,7 @@ + #[NoAdminRequired] #[FrontpageRoute(verb: 'POST', url: '/contactsmenu/contacts')] public function index(?string $filter = null): array { - return $this->manager->getEntries($this->userSession->getUser(), $filter); diff --git a/patches/005-autocomplete-user-leak-core.patch b/patches/005-autocomplete-user-leak-core.patch index fb1d9fbde3f245f18378d90ee35778de9275501f..b8d92820bb441e51dacd3bcf101bf1461b36a845 100644 --- a/patches/005-autocomplete-user-leak-core.patch +++ b/patches/005-autocomplete-user-leak-core.patch @@ -14,7 +14,7 @@ this filtering works in conjunction with the autocomplete feature disabled in ne diff --git lib/private/Collaboration/Collaborators/UserPlugin.php lib/private/Collaboration/Collaborators/UserPlugin-new.php --- lib/private/Collaboration/Collaborators/UserPlugin.php 2025-02-13 19:30:40 +++ lib/private/Collaboration/Collaborators/UserPlugin-new.php 2025-03-07 12:48:50 -@@ -175,8 +175,8 @@ +@@ -150,8 +150,8 @@ if ( $this->shareeEnumerationFullMatch && $lowerSearch !== '' && (strtolower($uid) === $lowerSearch || @@ -29,7 +29,7 @@ diff --git lib/private/Collaboration/Collaborators/UserPlugin.php lib/private/Co diff --git lib/private/Collaboration/Collaborators/MailPlugin.php lib/private/Collaboration/Collaborators/MailPlugin-new.php --- lib/private/Collaboration/Collaborators/MailPlugin.php 2025-02-13 19:30:40 +++ lib/private/Collaboration/Collaborators/MailPlugin-new.php 2025-03-07 12:55:25 -@@ -39,6 +39,7 @@ +@@ -19,6 +19,7 @@ use OCP\IUserSession; use OCP\Mail\IMailer; use OCP\Share\IShare; @@ -37,7 +37,7 @@ diff --git lib/private/Collaboration/Collaborators/MailPlugin.php lib/private/Co class MailPlugin implements ISearchPlugin { protected bool $shareWithGroupOnly; -@@ -61,8 +62,10 @@ +@@ -42,8 +43,10 @@ private KnownUserService $knownUserService, private IUserSession $userSession, private IMailer $mailer, @@ -48,7 +48,7 @@ diff --git lib/private/Collaboration/Collaborators/MailPlugin.php lib/private/Co $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; $this->shareWithGroupOnly = $this->config->getAppValue('core', 'shareapi_only_share_with_group_members', 'no') === 'yes'; $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; -@@ -221,27 +224,61 @@ +@@ -204,27 +207,61 @@ if ($exactEmailMatch) { $searchResult->markExactIdMatch($emailType); } diff --git a/patches/006-recovery-email-changes.patch b/patches/006-recovery-email-changes.patch index bf9301798365b5dbfc863fb2f5aab0fd6a0fabd0..80d37255f6b4b552baddd1026d4ea1fb11a5cda7 100644 --- a/patches/006-recovery-email-changes.patch +++ b/patches/006-recovery-email-changes.patch @@ -1,9 +1,10 @@ --- ./core/Controller/LostController.php 2023-05-05 18:38:07.080445742 +0530 +++ ./core/Controller/LostController-new.php 2023-05-05 18:48:27.385043088 +0530 -@@ -151,8 +151,23 @@ - */ +@@ -126,7 +126,24 @@ protected function checkPasswordResetToken(string $token, string $userId): void { try { + $user = $this->userManager->get($userId); +- $this->verificationToken->check($token, $user, 'lostpassword', $user ? $user->getEMailAddress() : '', true); + $legacyDomain = $this->config->getSystemValue('legacy_domain', ''); + $legacyDomainSuffix = !empty($legacyDomain) ? '@' . $legacyDomain : ''; + $mainDomain = $this->config->getSystemValue('main_domain', ''); @@ -18,14 +19,14 @@ + if(!$this->userManager->userExists($userId)) { + $userId = $userId . $legacyDomainSuffix; + } - $user = $this->userManager->get($userId); -- $this->verificationToken->check($token, $user, 'lostpassword', $user ? $user->getEMailAddress() : '', true); ++ $user = $this->userManager->get($userId); + $recoveryEmail = $this->config->getUserValue($userId, 'email-recovery', 'recovery-email', ''); + $this->verificationToken->check($token, $user, 'lostpassword', $user ? $recoveryEmail : '', true); ++ } catch (InvalidTokenException $e) { $error = $e->getCode() === InvalidTokenException::TOKEN_EXPIRED ? $this->l10n->t('Could not reset password because the token is expired') -@@ -266,9 +281,22 @@ +@@ -236,9 +253,22 @@ * @throws \OCP\PreConditionNotMetException */ protected function sendEmail(string $input): void { @@ -49,3 +50,4 @@ if (empty($email)) { throw new ResetPasswordException('Could not send reset e-mail since there is no email for username ' . $input); } + diff --git a/patches/007-remove-dev-notice.patch b/patches/007-remove-dev-notice.patch index 92e776485b7a568bafc84b2b768d6463c148d51f..a1ef8a3e8f84e11e3fdc1359cc6e2c00a1e98975 100644 --- a/patches/007-remove-dev-notice.patch +++ b/patches/007-remove-dev-notice.patch @@ -7,7 +7,7 @@ This patch removes the development notice portion in personal info settings diff --git ./apps/settings/lib/Settings/Personal/ServerDevNotice.php ./apps/settings/lib/Settings/Personal/ServerDevNotice-new.php --- ./apps/settings/lib/Settings/Personal/ServerDevNotice.php 2022-03-23 12:22:57.000000000 +0100 +++ ./apps/settings/lib/Settings/Personal/ServerDevNotice.php-new 2022-03-23 12:23:25.000000000 +0100 -@@ -100,11 +100,7 @@ +@@ -81,11 +81,7 @@ * @return string|null the section ID, e.g. 'sharing' */ public function getSection(): ?string { @@ -18,5 +18,5 @@ diff --git ./apps/settings/lib/Settings/Personal/ServerDevNotice.php ./apps/sett - return 'personal-info'; + return null; } - + /** diff --git a/patches/009-help-links.patch b/patches/009-help-links.patch index 2ea989a77bc0860e8f8d0cc28e5bde91832d366e..874325a09137a49100f3978b1029cf91a7b6839a 100644 --- a/patches/009-help-links.patch +++ b/patches/009-help-links.patch @@ -7,7 +7,7 @@ help links are shown --- ./apps/settings/lib/Controller/HelpController.php 2025-03-07 11:04:18 +++ ./apps/settings/lib/Controller/HelpController-new.php 2025-03-07 11:04:21 -@@ -123,6 +123,7 @@ +@@ -103,6 +103,7 @@ 'urlAdminDocs' => $urlAdminDocs, 'mode' => $mode, 'pageTitle' => $pageTitle, @@ -18,7 +18,7 @@ help links are shown --- ./apps/settings/templates/help.php 2025-03-13 21:19:20 +++ ./apps/settings/templates/help-new.php 2025-03-26 13:04:36 -@@ -5,85 +5,48 @@ +@@ -9,84 +9,47 @@
-- -+ -\ No newline at end of file + --- ./apps/settings/css/help.css 2021-08-20 14:16:57.951439620 +0530 +++ ./apps/settings/css/help-new.css 2021-08-20 17:02:43.549016337 +0530 -@@ -50,4 +50,12 @@ - - .help-content__body > .button { +.help-content__body > .button { margin: 20px; +} +#content #app-navigation { @@ -132,5 +128,4 @@ help links are shown + +#app-navigation:not(.vue) > ul > li > a { + padding: 0 12px 0 44px; - } - + } \ No newline at end of file diff --git a/patches/010-disable-app-store-upgrade.patch b/patches/010-disable-app-store-upgrade.patch index 59e4f0db537ac4d80588e58324d14bab8d179337..07ab975af8b837c0761e9a716286e4d20c05d26d 100644 --- a/patches/010-disable-app-store-upgrade.patch +++ b/patches/010-disable-app-store-upgrade.patch @@ -6,17 +6,18 @@ This patch disables checking the app store for app updates during "occ upgrade" --- ./lib/private/Updater.php 2021-11-16 12:12:35.631823438 +0530 +++ ./lib/private/Updater-new.php 2021-11-16 12:14:28.445155684 +0530 -@@ -272,11 +272,11 @@ +@@ -240,11 +240,11 @@ $appManager = \OC::$server->getAppManager(); // upgrade appstore apps - $this->upgradeAppStoreApps($appManager->getInstalledApps()); -+ /*$this->upgradeAppStoreApps($appManager->getInstalledApps()); ++ /* $this->upgradeAppStoreApps($appManager->getInstalledApps()); $autoDisabledApps = $appManager->getAutoDisabledApps(); if (!empty($autoDisabledApps)) { $this->upgradeAppStoreApps(array_keys($autoDisabledApps), $autoDisabledApps); - } -+ }*/ ++ } */ // install new shipped apps on upgrade $errors = Installer::installShippedApps(true); + diff --git a/patches/011-privacy-settings.patch b/patches/011-privacy-settings.patch index 3593bc39cae5a29b70e9107569f6894909c9f5e9..940d8eacc6a84e09b7fdcbda6a8cbc5162350bf0 100644 --- a/patches/011-privacy-settings.patch +++ b/patches/011-privacy-settings.patch @@ -6,7 +6,7 @@ This patch removes certain unnecessary sections from the "privacy" section in pe --- ./apps/privacy/lib/Settings/MissionSettings.php 2021-09-07 17:38:08.650902445 +0530 +++ ./apps/privacy/lib/Settings/MissionSettings-new.php 2021-09-07 17:40:30.078256502 +0530 -@@ -52,7 +52,7 @@ +@@ -36,7 +36,7 @@ return null; } @@ -18,7 +18,7 @@ This patch removes certain unnecessary sections from the "privacy" section in pe --- ./apps/privacy/lib/Settings/UserDataManifestoSettings.php 2021-09-07 17:38:06.284224253 +0530 +++ ./apps/privacy/lib/Settings/UserDataManifestoSettings-new.php 2021-09-07 17:40:42.288315736 +0530 -@@ -45,7 +45,7 @@ +@@ -29,7 +29,7 @@ return null; } @@ -30,7 +30,7 @@ This patch removes certain unnecessary sections from the "privacy" section in pe --- ./apps/privacy/lib/Controller/PersonalController.php 2024-08-01 12:57:29 +0530 +++ ./apps/privacy/lib/Controller/PersonalController-new.php 2024-08-01 12:57:03 +0530 -@@ -103,7 +103,7 @@ +@@ -87,7 +87,7 @@ 'internal' => false, ]; } @@ -39,4 +39,4 @@ This patch removes certain unnecessary sections from the "privacy" section in pe return new JSONResponse($uids, Http::STATUS_OK); } } - +\ No newline at end of file diff --git a/patches/013-revert-token-password-update.patch b/patches/013-revert-token-password-update.patch index e63ccfc6e24013c4c15f412569025d62c1df9340..32af56388fbda6560d537d8be6c45c665241a78a 100644 --- a/patches/013-revert-token-password-update.patch +++ b/patches/013-revert-token-password-update.patch @@ -7,11 +7,11 @@ This patch reverts to only update when there are expired tokens. --- ./lib/private/Authentication/Token/PublicKeyTokenProvider.php 2024-07-25 17:51:37 +0530 +++ ./lib/private/Authentication/Token/PublicKeyTokenProvider-new.php 2024-07-25 17:53:16 +0530 -@@ -517,6 +517,11 @@ +@@ -504,6 +504,11 @@ } public function updatePasswords(string $uid, string $password) { -+ if (!$this->mapper->hasExpiredTokens($uid)) { ++ if (!$this->mapper->hasExpiredTokens($uid)) { + //Nothing to do here + return; + } @@ -19,3 +19,4 @@ This patch reverts to only update when there are expired tokens. // prevent setting an empty pw as result of pw-less-login if ($password === '' || !$this->config->getSystemValueBool('auth.storeCryptedPassword', true)) { return; + diff --git a/patches/014-add-mail-usage.patch b/patches/014-add-mail-usage.patch index 081afa3269f8512c715ded135ae8651b7a361656..4418b3e15bc2307765220dfab542671e00c3ccc0 100644 --- a/patches/014-add-mail-usage.patch +++ b/patches/014-add-mail-usage.patch @@ -1,6 +1,6 @@ --- lib/private/legacy/OC_Helper.php 2025-05-25 16:00:00.880495300 +0530 +++ lib/private/legacy/OC_Helper-new.php 2025-05-25 16:02:00.970495300 +0530 -@@ -542,6 +542,12 @@ +@@ -512,6 +512,12 @@ } try { $free = $sourceStorage->free_space($rootInfo->getInternalPath()); @@ -13,10 +13,10 @@ if (is_bool($free)) { $free = 0.0; } -@@ -577,7 +583,6 @@ +@@ -547,7 +553,6 @@ */ $isRemoteShare = $storage->instanceOfStorage(\OCA\Files_Sharing\External\Storage::class); - $ownerId = $storage->getOwner($path); $hasOwnerId = $ownerId !== false && $ownerId !== null; - $ownerDisplayName = ''; + $ownerDisplayName = ''; \ No newline at end of file diff --git a/patches/015-email-mail-template.patch b/patches/015-email-mail-template.patch index d568956f9b6db80c09ae2ba93eddb809215b198a..3b0a77b862d6ea16f5cb230265d87bb38b5b1c66 100644 --- a/patches/015-email-mail-template.patch +++ b/patches/015-email-mail-template.patch @@ -7,26 +7,25 @@ This patch helps in indentifying that For a recurring event, the invitee knows w --- ./apps/dav/lib/CalDAV/Schedule/IMipPlugin.php 2024-03-18 11:18:20 +++ ./apps/dav/lib/CalDAV/Schedule/IMipPlugin-new.php 2024-03-11 11:18:22 -@@ -171,7 +171,29 @@ +@@ -149,7 +149,30 @@ /** @var VEvent $oldVevent */ $oldVevent = !empty($modified['old']) && is_array($modified['old']) ? array_pop($modified['old']) : null; $isModified = isset($oldVevent); -- + $recurrenceId = $vEvent->{'RECURRENCE-ID'}; + if (isset($recurrenceId) && $modified['sentOld'] === 1 && !empty($oldVevent)) { + $dateTime = $recurrenceId->getValue(); + $recurrenceArray = explode('T', $dateTime); -+ + + $oldVEventStart = $oldVevent->DTSTART; + $oldStartDateTime = $oldVEventStart->getValue(); + $startDateTimeArray = explode('T', $oldStartDateTime); + $finalStartTime = $recurrenceArray[0] . 'T' . $startDateTimeArray[1]; -+ ++ + $timeZoneId = (string) $recurrenceId['TZID']; + $oldVevent->DTSTART->setDateTime( + new \DateTime($finalStartTime, new \DateTimeZone($timeZoneId)) + ); -+ ++ + $oldVEventEnd = $oldVevent->DTEND; + $oldEndDateTime = $oldVEventEnd->getValue(); + $endDateTimeArray = explode('T', $oldEndDateTime); @@ -35,64 +34,64 @@ This patch helps in indentifying that For a recurring event, the invitee knows w + new \DateTime($finalEndTime, new \DateTimeZone($timeZoneId)) + ); + } ++ // No changed events after all - this shouldn't happen if there is significant change yet here we are // The scheduling status is debatable - if(empty($vEvent)) { -@@ -238,6 +260,13 @@ + if (empty($vEvent)) { +@@ -217,12 +240,35 @@ $data['invitee_name'] = ($senderName ?: $sender); $fromEMail = Util::getDefaultEmailAddress('invitations-noreply'); -+ //if sender name is empty sometimes in case of email client ++ // if sender name is empty sometimes in case of email client + if ($senderName === null || empty(trim($senderName))) { + $users = $this->userManager->getByEmail($sender); + if (count($users) === 1) { + $senderName = $users[0]->getDisplayName(); + } + } ++ $fromName = $this->imipService->getFrom($senderName, $this->defaults->getName()); - $message = $this->mailer->createMessage() -@@ -258,7 +287,22 @@ $template = $this->mailer->createEMailTemplate('dav.calendarInvite.' . $method, $data); $template->addHeader(); - $this->imipService->addSubjectAndHeading($template, $method, $data['invitee_name'], $data['meeting_title'], $isModified, $replyingAttendee); + $l10n = \OC::$server->getL10N('dav'); -+ if ( count($vEvent)>1) { ++ if (count($vEvent) > 1) { + $this->imipService->addSubjectAndHeadingUpdated($template, $method, $data['invitee_name'], $data['meeting_title'], $isModified, $replyingAttendee); + } else { + $this->imipService->addSubjectAndHeading($template, $method, $data['invitee_name'], $data['meeting_title'], $isModified, $replyingAttendee); + } + if ($method === self::METHOD_CANCEL) { -+ $template->addHeadingBanner('#FFC2B9','#7D1000',$l10n->t('The invitation has been cancelled')); ++ $template->addHeadingBanner('#FFC2B9', '#7D1000', $l10n->t('The invitation has been cancelled')); + } -+ if ($method !== self::METHOD_CANCEL && $method !== self::METHOD_REPLY && count($vEvent)>1) { -+ $template->addHeadingBanner('#EFFFDB','#293618',$l10n->t('This recurring event has been updated, please review the information below:')); ++ if ($method !== self::METHOD_CANCEL && $method !== self::METHOD_REPLY && count($vEvent) > 1) { ++ $template->addHeadingBanner('#EFFFDB', '#293618', $l10n->t('This recurring event has been updated, please review the information below:')); + } + $sequence = $vEvent->SEQUENCE ? $vEvent->SEQUENCE->getValue() : NULL; -+ if (($sequence && $method !== self::METHOD_CANCEL && $method !== self::METHOD_REPLY && ($sequence > 2)) || isset($vEvent->{'RECURRENCE-ID'})) { -+ $template->addHeadingBanner('#EFFFDB','#293618',$l10n->t('This event has been updated, please review the information below:')); ++ if (($sequence && $method !== self::METHOD_CANCEL && $method !== self::METHOD_REPLY && ($sequence > 2)) || isset($vEvent->{'RECURRENCE-ID'})) { ++ $template->addHeadingBanner('#EFFFDB', '#293618', $l10n->t('This event has been updated, please review the information below:')); + } $this->imipService->addBulletList($template, $vEvent, $data); // Only add response buttons to invitation requests: Fix Issue #11230 -@@ -291,7 +335,6 @@ +@@ -255,7 +301,6 @@ || in_array(strtolower($recipientDomain), $invitationLinkRecipients)) { $token = $this->imipService->createInvitationToken($iTipMessage, $vEvent, $lastOccurrence); $this->imipService->addResponseButtons($template, $token); - $this->imipService->addMoreOptionsButton($template, $token); } - } - + } + --- ./apps/dav/lib/CalDAV/Schedule/IMipService.php 2024-03-18 11:40:39 +++ ./apps/dav/lib/CalDAV/Schedule/IMipService-new.php 2024-03-18 13:47:17 -@@ -170,10 +170,30 @@ +@@ -163,7 +163,31 @@ $oldUrl = self::readPropertyWithDefault($oldVEvent, 'URL', $defaultVal); $data['meeting_url_html'] = !empty($oldUrl) && $oldUrl !== $data['meeting_url'] ? sprintf('%1$s', $oldUrl) : $data['meeting_url']; -- $data['meeting_when_html'] = -+ if(isset($vEvent->RRULE)){ -+ $RRule= (string) $vEvent->RRULE->getValue(); +- $data['meeting_when_html'] = $oldMeetingWhen !== $data['meeting_when'] ? sprintf("%s
%s", $oldMeetingWhen, $data['meeting_when']) : $data['meeting_when']; ++ if (isset($vEvent->RRULE)) { ++ $RRule = (string) $vEvent->RRULE->getValue(); + if (strpos($RRule, 'FREQ=DAILY') !== false) { + $timeTitle = $this->l10n->t('Repeats daily:'); + } @@ -100,29 +99,30 @@ This patch helps in indentifying that For a recurring event, the invitee knows w + $timeTitle = $this->l10n->t('Repeats weekly:'); + } + if (strpos($RRule, 'FREQ=MONTHLY') !== false) { -+ $timeTitle = $this->l10n->t('Repeats monthly:'); ++ $timeTitle = $this->l10n->t('Repeats monthly:'); + } + if (strpos($RRule, 'FREQ=YEARLY') !== false) { + $timeTitle = $this->l10n->t('Repeats yearly:'); + } + $data['meeting_when_html'] = - ($oldMeetingWhen !== $data['meeting_when'] && $oldMeetingWhen !== null) -- ? sprintf("%s
%s", $oldMeetingWhen, $data['meeting_when']) -+ ? sprintf("%s
%s %s", $oldMeetingWhen,$timeTitle, $data['meeting_when']) -+ : $data['meeting_when']; ++ ($oldMeetingWhen !== $data['meeting_when'] && $oldMeetingWhen !== null) ++ ? sprintf("%s
%s %s", $oldMeetingWhen, $timeTitle, $data['meeting_when']) ++ : $data['meeting_when']; + } else { + $data['meeting_when_html'] = -+ ($oldMeetingWhen !== $data['meeting_when'] && $oldMeetingWhen !== null) -+ ? sprintf("%s
%s %s", $oldMeetingWhen, $this->l10n->t('Time:'),$data['meeting_when']) - : $data['meeting_when']; ++ ($oldMeetingWhen !== $data['meeting_when'] && $oldMeetingWhen !== null) ++ ? sprintf("%s
%s %s", $oldMeetingWhen, $this->l10n->t('Time:'), $data['meeting_when']) ++ : $data['meeting_when']; + } ++ + } + // generate occurring next string + if ($eventReaderCurrent->recurs()) { +@@ -967,6 +991,51 @@ } - return $data; - } -@@ -446,6 +466,51 @@ } - /** ++ /** + * @param IEMailTemplate $template + * @param string $method + * @param string $sender @@ -130,7 +130,7 @@ This patch helps in indentifying that For a recurring event, the invitee knows w + * @param string|null $partstat + */ + public function addSubjectAndHeadingUpdated(IEMailTemplate $template, -+ string $method, string $sender, string $summary, bool $isModified, ?Property $replyingAttendee = null): void { ++ string $method, string $sender, string $summary, bool $isModified, ?Property $replyingAttendee = null): void { + if ($method === IMipPlugin::METHOD_CANCEL) { + // TRANSLATORS Subject for email, when an invitation is cancelled. Ex: "Cancelled: {{Event Name}}" + $template->setSubject($this->l10n->t('Cancelled: %1$s', [$summary])); @@ -167,51 +167,26 @@ This patch helps in indentifying that For a recurring event, the invitee knows w + } + } + -+ /** + /** * @param string $path * @return string - */ -@@ -539,12 +604,36 @@ - $data['meeting_title_html'] ?? $data['meeting_title'], $this->l10n->t('Title:'), - $this->getAbsoluteImagePath('caldav/title.png'), $data['meeting_title'], '', IMipPlugin::IMIP_INDENT); - if ($data['meeting_when'] !== '') { -- $template->addBodyListItem($data['meeting_when_html'] ?? $data['meeting_when'], $this->l10n->t('Time:'), -+ if(isset($vevent->RRULE)){ -+ $RRule=(string) $vevent->RRULE->getValue(); -+ if (strpos($RRule, 'FREQ=DAILY') !== false) { -+ $timeTitle = $this->l10n->t('Repeats daily:'); -+ } -+ if (strpos($RRule, 'FREQ=WEEKLY') !== false) { -+ $timeTitle = $this->l10n->t('Repeats weekly:'); -+ } -+ if (strpos($RRule, 'FREQ=MONTHLY') !== false) { -+ $timeTitle = $this->l10n->t('Repeats monthly:'); -+ } -+ if (strpos($RRule, 'FREQ=YEARLY') !== false) { -+ $timeTitle = $this->l10n->t('Repeats yearly:'); -+ } -+ $template->addBodyListItem($data['meeting_when_html'] ?? $data['meeting_when'], $timeTitle, -+ $this->getAbsoluteImagePath('caldav/time.png'), $data['meeting_when'], '', IMipPlugin::IMIP_INDENT); -+ } else { -+ $template->addBodyListItem($data['meeting_when_html'] ?? $data['meeting_when'], $this->l10n->t('Time:'), +@@ -1065,8 +1134,13 @@ $this->getAbsoluteImagePath('caldav/time.png'), $data['meeting_when'], '', IMipPlugin::IMIP_INDENT); -+ } } if ($data['meeting_location'] !== '') { - $template->addBodyListItem($data['meeting_location_html'] ?? $data['meeting_location'], $this->l10n->t('Location:'), - $this->getAbsoluteImagePath('caldav/location.png'), $data['meeting_location'], '', IMipPlugin::IMIP_INDENT); -+ if(filter_var(trim($data['meeting_location']), FILTER_VALIDATE_URL)) { ++ if(filter_var(trim($data['meeting_location']), FILTER_VALIDATE_URL)) { + $template->addBodyListItem($data['meeting_location_html'] ?? $data['meeting_location'], $this->l10n->t('Location:'), + $this->getAbsoluteImagePath('caldav/videocall.png'), $data['meeting_location'], '', IMipPlugin::IMIP_INDENT); -+ + } else { + $template->addBodyListItem($data['meeting_location_html'] ?? $data['meeting_location'], $this->l10n->t('Location:'), + $this->getAbsoluteImagePath('caldav/location.png'), $data['meeting_location'], '', IMipPlugin::IMIP_INDENT); -+ } ++ } } if ($data['meeting_url'] !== '') { $template->addBodyListItem($data['meeting_url_html'] ?? $data['meeting_url'], $this->l10n->t('Link:'), -@@ -642,7 +731,7 @@ +@@ -1143,7 +1217,7 @@ * @param $token */ public function addResponseButtons(IEMailTemplate $template, $token) { @@ -220,7 +195,7 @@ This patch helps in indentifying that For a recurring event, the invitee knows w $this->l10n->t('Accept'), $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.accept', [ 'token' => $token, -@@ -650,22 +739,12 @@ +@@ -1151,20 +1225,10 @@ $this->l10n->t('Decline'), $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.decline', [ 'token' => $token, @@ -229,8 +204,8 @@ This patch helps in indentifying that For a recurring event, the invitee knows w + $this->l10n->t('MayBe'), + $this->urlGenerator->getAbsoluteUrl('apps/calendar/invitation/tentative/'.$token) ); - } - +- } +- - public function addMoreOptionsButton(IEMailTemplate $template, $token) { - $moreOptionsURL = $this->urlGenerator->linkToRouteAbsolute('dav.invitation_response.options', [ - 'token' => $token, @@ -241,37 +216,34 @@ This patch helps in indentifying that For a recurring event, the invitee knows w - $text = $this->l10n->t('More options at %s', [$moreOptionsURL]); - - $template->addBodyText($html, $text); -- } -- + } + public function getReplyingAttendee(Message $iTipMessage): ?Property { - /** @var VEvent $vevent */ - $vevent = $iTipMessage->message->VEVENT; + --- ./apps/dav/lib/CalDAV/EventComparisonService.php 2024-05-06 12:46:29 +++ ./apps/dav/lib/CalDAV/EventComparisonService-new.php 2024-05-06 12:47:11 -@@ -94,11 +94,10 @@ - unset($newEventComponents[$k]); +@@ -78,8 +78,9 @@ } } -- + + $sentOld = 0; - if(empty($old)) { + if (empty($old)) { - return ['old' => null, 'new' => $newEventComponents]; + return ['old' => null, 'new' => $newEventComponents, 'sentOld' => $sentOld]; } -- + $oldEventComponents = $old->getComponents(); - if(is_array($oldEventComponents) && !empty($oldEventComponents)) { - foreach ($oldEventComponents as $k => $event) { -@@ -107,11 +106,15 @@ +@@ -90,11 +91,16 @@ continue; } - if($this->removeIfUnchanged($event, $newEventComponents)) { + if ($this->removeIfUnchanged($event, $newEventComponents)) { - unset($oldEventComponents[$k]); -+ if($k!=1){ -+ unset($oldEventComponents[$k]); -+ } else { ++ if($k!=1){ ++ unset($oldEventComponents[$k]); ++ } else { + $sentOld = 1; + } ++ } } } @@ -280,3 +252,4 @@ This patch helps in indentifying that For a recurring event, the invitee knows w + return ['old' => array_values($oldEventComponents), 'new' => array_values($newEventComponents), 'sentOld' => $sentOld]; } } +\ No newline at end of file diff --git a/patches/016-login-screen.patch b/patches/016-login-screen.patch index d8a1dacd417988b1c68ed22f16e091bbb2125a90..d7d7b98af69044bcd7a358fdd9ef4d765aa7e3ab 100644 --- a/patches/016-login-screen.patch +++ b/patches/016-login-screen.patch @@ -1,6 +1,6 @@ ---- ./core/templates/layout.guest.php 2024-03-15 19:20:21 -+++ ./core/templates/layout.guest-new.php 2024-03-15 19:24:49 -@@ -22,6 +22,7 @@ +--- layout.guest.php 2025-07-24 10:37:50 ++++ layout.guest-new.php 2025-07-24 10:58:20 +@@ -32,6 +32,7 @@ @@ -8,67 +8,66 @@ -@@ -32,12 +33,37 @@ - $initialState) { ?> - - --
--
-+
" > -+ +@@ -42,10 +43,38 @@ + +
+
++
" > ++ +