mirror of
https://github.com/nextcloud/server.git
synced 2026-03-21 10:00:33 -04:00
feat: add example contact on first login
Signed-off-by: Hamza Mahjoubi <hamzamahjoubi221@gmail.com>
This commit is contained in:
parent
c85b8aa36c
commit
099d9fb9be
132 changed files with 4310 additions and 162 deletions
|
|
@ -167,6 +167,10 @@ Files: apps/dav/tests/unit/test_fixtures/caldav-search-limit-timerange-1.ics app
|
|||
Copyright: 2023 Nextcloud GmbH and Nextcloud contributors
|
||||
License: AGPL-3.0-or-later
|
||||
|
||||
Files: apps/dav/lib/ExampleContentFiles/exampleContact.vcf
|
||||
Copyright: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
License: AGPL-3.0-or-later
|
||||
|
||||
Files: composer.json composer.lock .github/CODEOWNERS __tests__/tsconfig.json tsconfig.json build/integration/composer.* vendor-bin/*/composer.json vendor-bin/*/composer.lock apps/*/composer/composer.json apps/*/composer/composer.lock apps/*/composer/composer/installed.json
|
||||
Copyright: 2011-2016 ownCloud, Inc., 2016-2024 Nextcloud GmbH and Nextcloud contributors
|
||||
License: AGPL-3.0-only OR AGPL-3.0-or-later
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
|
||||
<settings>
|
||||
<admin>OCA\DAV\Settings\CalDAVSettings</admin>
|
||||
<admin>OCA\DAV\Settings\ExampleContentSettings</admin>
|
||||
<personal>OCA\DAV\Settings\AvailabilitySettings</personal>
|
||||
</settings>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ return [
|
|||
['name' => 'invitation_response#decline', 'url' => '/invitation/decline/{token}', 'verb' => 'GET'],
|
||||
['name' => 'invitation_response#options', 'url' => '/invitation/moreOptions/{token}', 'verb' => 'GET'],
|
||||
['name' => 'invitation_response#processMoreOptionsResult', 'url' => '/invitation/moreOptions/{token}', 'verb' => 'POST'],
|
||||
['name' => 'example_content#setDefaultContact', 'url' => '/api/defaultcontact/contact', 'verb' => 'PUT'],
|
||||
['name' => 'example_content#setEnableDefaultContact', 'url' => '/api/defaultcontact/config', 'verb' => 'PUT'],
|
||||
],
|
||||
'ocs' => [
|
||||
['name' => 'direct#getUrl', 'url' => '/api/v1/direct', 'verb' => 'POST'],
|
||||
|
|
|
|||
|
|
@ -221,6 +221,7 @@ return array(
|
|||
'OCA\\DAV\\Connector\\Sabre\\ZipFolderPlugin' => $baseDir . '/../lib/Connector/Sabre/ZipFolderPlugin.php',
|
||||
'OCA\\DAV\\Controller\\BirthdayCalendarController' => $baseDir . '/../lib/Controller/BirthdayCalendarController.php',
|
||||
'OCA\\DAV\\Controller\\DirectController' => $baseDir . '/../lib/Controller/DirectController.php',
|
||||
'OCA\\DAV\\Controller\\ExampleContentController' => $baseDir . '/../lib/Controller/ExampleContentController.php',
|
||||
'OCA\\DAV\\Controller\\InvitationResponseController' => $baseDir . '/../lib/Controller/InvitationResponseController.php',
|
||||
'OCA\\DAV\\Controller\\OutOfOfficeController' => $baseDir . '/../lib/Controller/OutOfOfficeController.php',
|
||||
'OCA\\DAV\\Controller\\UpcomingEventsController' => $baseDir . '/../lib/Controller/UpcomingEventsController.php',
|
||||
|
|
@ -355,9 +356,11 @@ return array(
|
|||
'OCA\\DAV\\Server' => $baseDir . '/../lib/Server.php',
|
||||
'OCA\\DAV\\ServerFactory' => $baseDir . '/../lib/ServerFactory.php',
|
||||
'OCA\\DAV\\Service\\AbsenceService' => $baseDir . '/../lib/Service/AbsenceService.php',
|
||||
'OCA\\DAV\\Service\\DefaultContactService' => $baseDir . '/../lib/Service/DefaultContactService.php',
|
||||
'OCA\\DAV\\Settings\\Admin\\SystemAddressBookSettings' => $baseDir . '/../lib/Settings/Admin/SystemAddressBookSettings.php',
|
||||
'OCA\\DAV\\Settings\\AvailabilitySettings' => $baseDir . '/../lib/Settings/AvailabilitySettings.php',
|
||||
'OCA\\DAV\\Settings\\CalDAVSettings' => $baseDir . '/../lib/Settings/CalDAVSettings.php',
|
||||
'OCA\\DAV\\Settings\\ExampleContentSettings' => $baseDir . '/../lib/Settings/ExampleContentSettings.php',
|
||||
'OCA\\DAV\\SetupChecks\\NeedsSystemAddressBookSync' => $baseDir . '/../lib/SetupChecks/NeedsSystemAddressBookSync.php',
|
||||
'OCA\\DAV\\SetupChecks\\WebdavEndpoint' => $baseDir . '/../lib/SetupChecks/WebdavEndpoint.php',
|
||||
'OCA\\DAV\\Storage\\PublicOwnerWrapper' => $baseDir . '/../lib/Storage/PublicOwnerWrapper.php',
|
||||
|
|
|
|||
|
|
@ -236,6 +236,7 @@ class ComposerStaticInitDAV
|
|||
'OCA\\DAV\\Connector\\Sabre\\ZipFolderPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/ZipFolderPlugin.php',
|
||||
'OCA\\DAV\\Controller\\BirthdayCalendarController' => __DIR__ . '/..' . '/../lib/Controller/BirthdayCalendarController.php',
|
||||
'OCA\\DAV\\Controller\\DirectController' => __DIR__ . '/..' . '/../lib/Controller/DirectController.php',
|
||||
'OCA\\DAV\\Controller\\ExampleContentController' => __DIR__ . '/..' . '/../lib/Controller/ExampleContentController.php',
|
||||
'OCA\\DAV\\Controller\\InvitationResponseController' => __DIR__ . '/..' . '/../lib/Controller/InvitationResponseController.php',
|
||||
'OCA\\DAV\\Controller\\OutOfOfficeController' => __DIR__ . '/..' . '/../lib/Controller/OutOfOfficeController.php',
|
||||
'OCA\\DAV\\Controller\\UpcomingEventsController' => __DIR__ . '/..' . '/../lib/Controller/UpcomingEventsController.php',
|
||||
|
|
@ -370,9 +371,11 @@ class ComposerStaticInitDAV
|
|||
'OCA\\DAV\\Server' => __DIR__ . '/..' . '/../lib/Server.php',
|
||||
'OCA\\DAV\\ServerFactory' => __DIR__ . '/..' . '/../lib/ServerFactory.php',
|
||||
'OCA\\DAV\\Service\\AbsenceService' => __DIR__ . '/..' . '/../lib/Service/AbsenceService.php',
|
||||
'OCA\\DAV\\Service\\DefaultContactService' => __DIR__ . '/..' . '/../lib/Service/DefaultContactService.php',
|
||||
'OCA\\DAV\\Settings\\Admin\\SystemAddressBookSettings' => __DIR__ . '/..' . '/../lib/Settings/Admin/SystemAddressBookSettings.php',
|
||||
'OCA\\DAV\\Settings\\AvailabilitySettings' => __DIR__ . '/..' . '/../lib/Settings/AvailabilitySettings.php',
|
||||
'OCA\\DAV\\Settings\\CalDAVSettings' => __DIR__ . '/..' . '/../lib/Settings/CalDAVSettings.php',
|
||||
'OCA\\DAV\\Settings\\ExampleContentSettings' => __DIR__ . '/..' . '/../lib/Settings/ExampleContentSettings.php',
|
||||
'OCA\\DAV\\SetupChecks\\NeedsSystemAddressBookSync' => __DIR__ . '/..' . '/../lib/SetupChecks/NeedsSystemAddressBookSync.php',
|
||||
'OCA\\DAV\\SetupChecks\\WebdavEndpoint' => __DIR__ . '/..' . '/../lib/SetupChecks/WebdavEndpoint.php',
|
||||
'OCA\\DAV\\Storage\\PublicOwnerWrapper' => __DIR__ . '/..' . '/../lib/Storage/PublicOwnerWrapper.php',
|
||||
|
|
|
|||
86
apps/dav/lib/Controller/ExampleContentController.php
Normal file
86
apps/dav/lib/Controller/ExampleContentController.php
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\Controller;
|
||||
|
||||
use OCA\DAV\AppInfo\Application;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\ApiController;
|
||||
use OCP\AppFramework\Http;
|
||||
use OCP\AppFramework\Http\JSONResponse;
|
||||
use OCP\Files\AppData\IAppDataFactory;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\IConfig;
|
||||
use OCP\IRequest;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ExampleContentController extends ApiController {
|
||||
private IAppData $appData;
|
||||
public function __construct(
|
||||
IRequest $request,
|
||||
private IConfig $config,
|
||||
private IAppDataFactory $appDataFactory,
|
||||
private IAppManager $appManager,
|
||||
private LoggerInterface $logger,
|
||||
) {
|
||||
parent::__construct(Application::APP_ID, $request);
|
||||
$this->appData = $this->appDataFactory->get('dav');
|
||||
}
|
||||
|
||||
public function setEnableDefaultContact($allow) {
|
||||
if ($allow === 'yes' && !$this->defaultContactExists()) {
|
||||
try {
|
||||
$this->setCard();
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Could not create default contact', ['exception' => $e]);
|
||||
return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR);
|
||||
}
|
||||
}
|
||||
$this->config->setAppValue(Application::APP_ID, 'enableDefaultContact', $allow);
|
||||
return new JSONResponse([], Http::STATUS_OK);
|
||||
}
|
||||
|
||||
public function setDefaultContact(?string $contactData = null) {
|
||||
if (!$this->config->getAppValue(Application::APP_ID, 'enableDefaultContact', 'no')) {
|
||||
return new JSONResponse([], Http::STATUS_FORBIDDEN);
|
||||
}
|
||||
$this->setCard($contactData);
|
||||
return new JSONResponse([], Http::STATUS_OK);
|
||||
}
|
||||
|
||||
private function setCard(?string $cardData = null) {
|
||||
try {
|
||||
$folder = $this->appData->getFolder('defaultContact');
|
||||
} catch (NotFoundException $e) {
|
||||
$folder = $this->appData->newFolder('defaultContact');
|
||||
}
|
||||
|
||||
if (is_null($cardData)) {
|
||||
$cardData = file_get_contents(__DIR__ . '/../ExampleContentFiles/exampleContact.vcf');
|
||||
}
|
||||
|
||||
if (!$cardData) {
|
||||
throw new \Exception('Could not read exampleContact.vcf');
|
||||
}
|
||||
|
||||
$file = (!$folder->fileExists('defaultContact.vcf')) ? $folder->newFile('defaultContact.vcf') : $folder->getFile('defaultContact.vcf');
|
||||
$file->putContent($cardData);
|
||||
}
|
||||
|
||||
private function defaultContactExists(): bool {
|
||||
try {
|
||||
$folder = $this->appData->getFolder('defaultContact');
|
||||
} catch (NotFoundException $e) {
|
||||
return false;
|
||||
}
|
||||
return $folder->fileExists('defaultContact.vcf');
|
||||
}
|
||||
|
||||
}
|
||||
3555
apps/dav/lib/ExampleContentFiles/exampleContact.vcf
Normal file
3555
apps/dav/lib/ExampleContentFiles/exampleContact.vcf
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,7 @@ namespace OCA\DAV\Listener;
|
|||
use OCA\DAV\CalDAV\CalDavBackend;
|
||||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCA\DAV\CardDAV\SyncService;
|
||||
use OCA\DAV\Service\DefaultContactService;
|
||||
use OCP\Defaults;
|
||||
use OCP\EventDispatcher\Event;
|
||||
use OCP\EventDispatcher\IEventListener;
|
||||
|
|
@ -44,6 +45,7 @@ class UserEventsListener implements IEventListener {
|
|||
private CalDavBackend $calDav,
|
||||
private CardDavBackend $cardDav,
|
||||
private Defaults $themingDefaults,
|
||||
private DefaultContactService $defaultContactService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
|
@ -139,14 +141,18 @@ class UserEventsListener implements IEventListener {
|
|||
Server::get(LoggerInterface::class)->error($e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
$addressBookId = null;
|
||||
if ($this->cardDav->getAddressBooksForUserCount($principal) === 0) {
|
||||
try {
|
||||
$this->cardDav->createAddressBook($principal, CardDavBackend::PERSONAL_ADDRESSBOOK_URI, [
|
||||
$addressBookId = $this->cardDav->createAddressBook($principal, CardDavBackend::PERSONAL_ADDRESSBOOK_URI, [
|
||||
'{DAV:}displayname' => CardDavBackend::PERSONAL_ADDRESSBOOK_NAME,
|
||||
]);
|
||||
} catch (\Exception $e) {
|
||||
Server::get(LoggerInterface::class)->error($e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
}
|
||||
if ($addressBookId) {
|
||||
$this->defaultContactService->createDefaultContact($addressBookId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
70
apps/dav/lib/Service/DefaultContactService.php
Normal file
70
apps/dav/lib/Service/DefaultContactService.php
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\Service;
|
||||
|
||||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\Files\AppData\IAppDataFactory;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
|
||||
class DefaultContactService {
|
||||
public function __construct(
|
||||
private CardDavBackend $cardDav,
|
||||
private IAppManager $appManager,
|
||||
private IAppDataFactory $appDataFactory,
|
||||
private LoggerInterface $logger,
|
||||
) {
|
||||
}
|
||||
|
||||
public function createDefaultContact(int $addressBookId): void {
|
||||
$appData = $this->appDataFactory->get('dav');
|
||||
try {
|
||||
$folder = $appData->getFolder('defaultContact');
|
||||
$defaultContactFile = $folder->getFile('defaultContact.vcf');
|
||||
$data = $defaultContactFile->getContent();
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error('Couldn\'t get default contact file', ['exception' => $e]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure the UID is unique
|
||||
$newUid = Uuid::v4()->toRfc4122();
|
||||
$newRev = date('Ymd\THis\Z');
|
||||
$vcard = \Sabre\VObject\Reader::read($data, \Sabre\VObject\Reader::OPTION_FORGIVING);
|
||||
if ($vcard->UID) {
|
||||
$vcard->UID->setValue($newUid);
|
||||
} else {
|
||||
$vcard->add('UID', $newUid);
|
||||
}
|
||||
if ($vcard->REV) {
|
||||
$vcard->REV->setValue($newRev);
|
||||
} else {
|
||||
$vcard->add('REV', $newRev);
|
||||
}
|
||||
|
||||
// Level 3 means that the document is invalid
|
||||
// https://sabre.io/vobject/vcard/#validating-vcard
|
||||
$level3Warnings = array_filter($vcard->validate(), function ($warning) {
|
||||
return $warning['level'] === 3;
|
||||
});
|
||||
|
||||
if (!empty($level3Warnings)) {
|
||||
$this->logger->error('Default contact is invalid', ['warnings' => $level3Warnings]);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
$this->cardDav->createCard($addressBookId, 'default', $vcard->serialize(), false);
|
||||
} catch (\Exception $e) {
|
||||
$this->logger->error($e->getMessage(), ['exception' => $e]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
44
apps/dav/lib/Settings/ExampleContentSettings.php
Normal file
44
apps/dav/lib/Settings/ExampleContentSettings.php
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
namespace OCA\DAV\Settings;
|
||||
|
||||
use OCA\DAV\AppInfo\Application;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\AppFramework\Http\TemplateResponse;
|
||||
use OCP\AppFramework\Services\IInitialState;
|
||||
use OCP\IConfig;
|
||||
use OCP\Settings\ISettings;
|
||||
|
||||
class ExampleContentSettings implements ISettings {
|
||||
|
||||
public function __construct(
|
||||
private IConfig $config,
|
||||
private IInitialState $initialState,
|
||||
private IAppManager $appManager,
|
||||
) {
|
||||
}
|
||||
|
||||
public function getForm(): TemplateResponse {
|
||||
$enableDefaultContact = $this->config->getAppValue(Application::APP_ID, 'enableDefaultContact', 'no');
|
||||
$this->initialState->provideInitialState('enableDefaultContact', $enableDefaultContact);
|
||||
return new TemplateResponse(Application::APP_ID, 'settings-example-content');
|
||||
}
|
||||
public function getSection(): ?string {
|
||||
if (!$this->appManager->isEnabledForUser('contacts')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'groupware';
|
||||
}
|
||||
|
||||
public function getPriority(): int {
|
||||
return 10;
|
||||
}
|
||||
|
||||
}
|
||||
13
apps/dav/src/settings-example-content.js
Normal file
13
apps/dav/src/settings-example-content.js
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
import Vue from 'vue'
|
||||
import { translate } from '@nextcloud/l10n'
|
||||
import ExampleContactSettings from './views/ExampleContactSettings.vue'
|
||||
|
||||
Vue.prototype.$t = translate
|
||||
|
||||
const View = Vue.extend(ExampleContactSettings);
|
||||
|
||||
(new View({})).$mount('#settings-example-content')
|
||||
160
apps/dav/src/views/ExampleContactSettings.vue
Normal file
160
apps/dav/src/views/ExampleContactSettings.vue
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
<!--
|
||||
- SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
- SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
-->
|
||||
|
||||
<template>
|
||||
<NcSettingsSection id="exmaple-content"
|
||||
:name="$t('dav', 'Example Content')"
|
||||
class="example-content-setting"
|
||||
:description="$t('dav', 'Set example content to be created on new user first login.')">
|
||||
<div class="example-content-setting__contacts">
|
||||
<input id="enable-default-contact"
|
||||
v-model="enableDefaultContact"
|
||||
type="checkbox"
|
||||
class="checkbox"
|
||||
@change="updateEnableDefaultContact">
|
||||
<label for="enable-default-contact"> {{ $t('dav',"Default contact is added to the user's own address book on user's first login.") }} </label>
|
||||
<div v-if="enableDefaultContact" class="example-content-setting__contacts__buttons">
|
||||
<NcButton type="primary"
|
||||
class="example-content-setting__contacts__buttons__button"
|
||||
@click="toggleModal">
|
||||
<template #icon>
|
||||
<IconUpload :size="20" />
|
||||
</template>
|
||||
{{ $t('dav', 'Import contact') }}
|
||||
</NcButton>
|
||||
<NcButton type="secondary"
|
||||
class="example-content-setting__contacts__buttons__button"
|
||||
@click="resetContact">
|
||||
<template #icon>
|
||||
<IconRestore :size="20" />
|
||||
</template>
|
||||
{{ $t('dav', 'Reset to default contact') }}
|
||||
</NcButton>
|
||||
</div>
|
||||
</div>
|
||||
<NcDialog :open.sync="isModalOpen"
|
||||
:name="$t('dav', 'Import contacts')"
|
||||
:buttons="buttons">
|
||||
<div>
|
||||
<p>{{ $t('dav', 'Importing a new .vcf file will delete the existing default contact and replace it with the new one. Do you want to continue?') }}</p>
|
||||
</div>
|
||||
</NcDialog>
|
||||
<input id="example-contact-import"
|
||||
ref="exampleContactImportInput"
|
||||
:disabled="loading"
|
||||
type="file"
|
||||
accept=".vcf"
|
||||
class="hidden-visually"
|
||||
@change="processFile">
|
||||
</NcSettingsSection>
|
||||
</template>
|
||||
<script>
|
||||
import axios from '@nextcloud/axios'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import { loadState } from '@nextcloud/initial-state'
|
||||
import { NcDialog, NcButton, NcSettingsSection } from '@nextcloud/vue'
|
||||
import { showError, showSuccess } from '@nextcloud/dialogs'
|
||||
import IconUpload from 'vue-material-design-icons/Upload.vue'
|
||||
import IconRestore from 'vue-material-design-icons/Restore.vue'
|
||||
import IconCancel from '@mdi/svg/svg/cancel.svg?raw'
|
||||
import IconCheck from '@mdi/svg/svg/check.svg?raw'
|
||||
|
||||
const enableDefaultContact = loadState('dav', 'enableDefaultContact') === 'yes'
|
||||
|
||||
export default {
|
||||
name: 'ExampleContactSettings',
|
||||
components: {
|
||||
NcDialog,
|
||||
NcButton,
|
||||
NcSettingsSection,
|
||||
IconUpload,
|
||||
IconRestore,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
enableDefaultContact,
|
||||
isModalOpen: false,
|
||||
loading: false,
|
||||
buttons: [
|
||||
{
|
||||
label: this.$t('dav', 'Cancel'),
|
||||
icon: IconCancel,
|
||||
callback: () => { this.isModalOpen = false },
|
||||
},
|
||||
{
|
||||
label: this.$t('dav', 'Import'),
|
||||
type: 'primary',
|
||||
icon: IconCheck,
|
||||
callback: () => { this.clickImportInput() },
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateEnableDefaultContact() {
|
||||
axios.put(generateUrl('apps/dav/api/defaultcontact/config'), {
|
||||
allow: this.enableDefaultContact ? 'yes' : 'no',
|
||||
}).catch(() => {
|
||||
this.enableDefaultContact = !this.enableDefaultContact
|
||||
showError(this.$t('dav', 'Error while saving settings'))
|
||||
})
|
||||
},
|
||||
toggleModal() {
|
||||
this.isModalOpen = !this.isModalOpen
|
||||
},
|
||||
clickImportInput() {
|
||||
this.$refs.exampleContactImportInput.click()
|
||||
},
|
||||
resetContact() {
|
||||
this.loading = true
|
||||
axios.put(generateUrl('/apps/dav/api/defaultcontact/contact'))
|
||||
.then(() => {
|
||||
showSuccess(this.$t('dav', 'Contact reset successfully'))
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error importing contact:', error)
|
||||
showError(this.$t('dav', 'Error while resetting contact'))
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
processFile(event) {
|
||||
this.loading = true
|
||||
|
||||
const file = event.target.files[0]
|
||||
const reader = new FileReader()
|
||||
|
||||
reader.onload = async () => {
|
||||
this.isModalOpen = false
|
||||
try {
|
||||
await axios.put(generateUrl('/apps/dav/api/defaultcontact/contact'), { contactData: reader.result })
|
||||
showSuccess(this.$t('dav', 'Contact imported successfully'))
|
||||
} catch (error) {
|
||||
console.error('Error importing contact:', error)
|
||||
showError(this.$t('dav', 'Error while importing contact'))
|
||||
} finally {
|
||||
this.loading = false
|
||||
event.target.value = ''
|
||||
}
|
||||
}
|
||||
reader.readAsText(file)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.example-content-setting{
|
||||
&__contacts{
|
||||
&__buttons{
|
||||
margin-top: 1rem;
|
||||
display: flex;
|
||||
&__button{
|
||||
margin-inline-end: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
11
apps/dav/templates/settings-example-content.php
Normal file
11
apps/dav/templates/settings-example-content.php
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
script('dav', 'settings-example-content');
|
||||
|
||||
?>
|
||||
|
||||
<div id="settings-example-content"></div>
|
||||
|
|
@ -14,6 +14,7 @@ use OCA\DAV\CalDAV\CalDavBackend;
|
|||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCA\DAV\CardDAV\SyncService;
|
||||
use OCA\DAV\Listener\UserEventsListener;
|
||||
use OCA\DAV\Service\DefaultContactService;
|
||||
use OCP\Defaults;
|
||||
use OCP\IUser;
|
||||
use OCP\IUserManager;
|
||||
|
|
@ -27,6 +28,8 @@ class UserEventsListenerTest extends TestCase {
|
|||
private CardDavBackend&MockObject $cardDavBackend;
|
||||
private Defaults&MockObject $defaults;
|
||||
|
||||
private DefaultContactService&MockObject $defaultContactService;
|
||||
|
||||
private UserEventsListener $userEventsListener;
|
||||
|
||||
protected function setUp(): void {
|
||||
|
|
@ -36,12 +39,14 @@ class UserEventsListenerTest extends TestCase {
|
|||
$this->calDavBackend = $this->createMock(CalDavBackend::class);
|
||||
$this->cardDavBackend = $this->createMock(CardDavBackend::class);
|
||||
$this->defaults = $this->createMock(Defaults::class);
|
||||
$this->defaultContactService = $this->createMock(DefaultContactService::class);
|
||||
$this->userEventsListener = new UserEventsListener(
|
||||
$this->userManager,
|
||||
$this->syncService,
|
||||
$this->calDavBackend,
|
||||
$this->cardDavBackend,
|
||||
$this->defaults,
|
||||
$this->defaultContactService,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
148
apps/dav/tests/unit/Service/DefaultContactServiceTest.php
Normal file
148
apps/dav/tests/unit/Service/DefaultContactServiceTest.php
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Nextcloud GmbH and Nextcloud contributors
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
||||
namespace OCA\DAV\Tests\Unit\Service;
|
||||
|
||||
use OCA\DAV\CardDAV\CardDavBackend;
|
||||
use OCA\DAV\Service\DefaultContactService;
|
||||
use OCP\App\IAppManager;
|
||||
use OCP\Files\AppData\IAppDataFactory;
|
||||
use OCP\Files\IAppData;
|
||||
use OCP\Files\NotFoundException;
|
||||
use OCP\Files\SimpleFS\ISimpleFile;
|
||||
use OCP\Files\SimpleFS\ISimpleFolder;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Uid\Uuid;
|
||||
use Test\TestCase;
|
||||
|
||||
class DefaultContactServiceTest extends TestCase {
|
||||
private DefaultContactService $service;
|
||||
private MockObject|CardDavBackend $cardDav;
|
||||
private MockObject|IAppManager $appManager;
|
||||
private MockObject|IAppDataFactory $appDataFactory;
|
||||
private MockObject|LoggerInterface $logger;
|
||||
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->cardDav = $this->createMock(CardDavBackend::class);
|
||||
$this->appManager = $this->createMock(IAppManager::class);
|
||||
$this->appDataFactory = $this->createMock(IAppDataFactory::class);
|
||||
$this->logger = $this->createMock(LoggerInterface::class);
|
||||
|
||||
$this->service = new DefaultContactService(
|
||||
$this->cardDav,
|
||||
$this->appManager,
|
||||
$this->appDataFactory,
|
||||
$this->logger
|
||||
);
|
||||
}
|
||||
|
||||
public function testCreateDefaultContactWithInvalidCard(): void {
|
||||
// Invalid vCard missing required FN property
|
||||
$vcardContent = "BEGIN:VCARD\nVERSION:3.0\nEND:VCARD";
|
||||
|
||||
$appData = $this->createMock(IAppData::class);
|
||||
$folder = $this->createMock(ISimpleFolder::class);
|
||||
$file = $this->createMock(ISimpleFile::class);
|
||||
$file->method('getContent')->willReturn($vcardContent);
|
||||
$folder->method('getFile')->willReturn($file);
|
||||
$appData->method('getFolder')->willReturn($folder);
|
||||
$this->appDataFactory->method('get')->willReturn($appData);
|
||||
|
||||
$this->logger->expects($this->once())
|
||||
->method('error')
|
||||
->with('Default contact is invalid', $this->anything());
|
||||
|
||||
$this->cardDav->expects($this->never())
|
||||
->method('createCard');
|
||||
|
||||
$this->service->createDefaultContact(123);
|
||||
}
|
||||
|
||||
public function testUidAndRevAreUpdated(): void {
|
||||
$originalUid = 'original-uid';
|
||||
$originalRev = '20200101T000000Z';
|
||||
$vcardContent = "BEGIN:VCARD\nVERSION:3.0\nFN:Test User\nUID:$originalUid\nREV:$originalRev\nEND:VCARD";
|
||||
|
||||
$appData = $this->createMock(IAppData::class);
|
||||
$folder = $this->createMock(ISimpleFolder::class);
|
||||
$file = $this->createMock(ISimpleFile::class);
|
||||
$file->method('getContent')->willReturn($vcardContent);
|
||||
$folder->method('getFile')->willReturn($file);
|
||||
$appData->method('getFolder')->willReturn($folder);
|
||||
$this->appDataFactory->method('get')->willReturn($appData);
|
||||
|
||||
$capturedCardData = null;
|
||||
$this->cardDav->expects($this->once())
|
||||
->method('createCard')
|
||||
->with(
|
||||
$this->anything(),
|
||||
$this->anything(),
|
||||
$this->callback(function ($cardData) use (&$capturedCardData) {
|
||||
$capturedCardData = $cardData;
|
||||
return true;
|
||||
}),
|
||||
$this->anything()
|
||||
)->willReturn(null);
|
||||
|
||||
$this->service->createDefaultContact(123);
|
||||
|
||||
$vcard = \Sabre\VObject\Reader::read($capturedCardData);
|
||||
$this->assertNotEquals($originalUid, $vcard->UID->getValue());
|
||||
$this->assertTrue(Uuid::isValid($vcard->UID->getValue()));
|
||||
$this->assertNotEquals($originalRev, $vcard->REV->getValue());
|
||||
}
|
||||
|
||||
public function testDefaultContactFileDoesNotExist(): void {
|
||||
$appData = $this->createMock(IAppData::class);
|
||||
$appData->method('getFolder')->willThrowException(new NotFoundException());
|
||||
$this->appDataFactory->method('get')->willReturn($appData);
|
||||
|
||||
$this->cardDav->expects($this->never())
|
||||
->method('createCard');
|
||||
|
||||
$this->service->createDefaultContact(123);
|
||||
}
|
||||
|
||||
public function testUidAndRevAreAddedIfMissing(): void {
|
||||
$vcardContent = "BEGIN:VCARD\nVERSION:3.0\nFN:Test User\nEND:VCARD";
|
||||
|
||||
$appData = $this->createMock(IAppData::class);
|
||||
$folder = $this->createMock(ISimpleFolder::class);
|
||||
$file = $this->createMock(ISimpleFile::class);
|
||||
$file->method('getContent')->willReturn($vcardContent);
|
||||
$folder->method('getFile')->willReturn($file);
|
||||
$appData->method('getFolder')->willReturn($folder);
|
||||
$this->appDataFactory->method('get')->willReturn($appData);
|
||||
|
||||
$capturedCardData = 'new-card-data';
|
||||
|
||||
$this->cardDav
|
||||
->expects($this->once())
|
||||
->method('createCard')
|
||||
->with(
|
||||
$this->anything(),
|
||||
$this->anything(),
|
||||
$this->callback(function ($cardData) use (&$capturedCardData) {
|
||||
$capturedCardData = $cardData;
|
||||
return true;
|
||||
}),
|
||||
$this->anything()
|
||||
);
|
||||
|
||||
$this->service->createDefaultContact(123);
|
||||
$vcard = \Sabre\VObject\Reader::read($capturedCardData);
|
||||
|
||||
$this->assertNotNull($vcard->REV);
|
||||
$this->assertNotNull($vcard->UID);
|
||||
$this->assertTrue(Uuid::isValid($vcard->UID->getValue()));
|
||||
}
|
||||
}
|
||||
4
dist/2441-2441.js
vendored
4
dist/2441-2441.js
vendored
|
|
@ -1,2 +1,2 @@
|
|||
"use strict";(self.webpackChunknextcloud=self.webpackChunknextcloud||[]).push([[2441],{82441:(e,c,l)=>{l.d(c,{FilePickerVue:()=>n});const n=(0,l(85471).$V)((()=>Promise.all([l.e(4208),l.e(8289),l.e(6146)]).then(l.bind(l,26146))))}}]);
|
||||
//# sourceMappingURL=2441-2441.js.map?v=44b85e4901c485417f88
|
||||
"use strict";(self.webpackChunknextcloud=self.webpackChunknextcloud||[]).push([[2441],{82441:(e,c,l)=>{l.d(c,{FilePickerVue:()=>n});const n=(0,l(85471).$V)((()=>Promise.all([l.e(4208),l.e(9904)]).then(l.bind(l,26146))))}}]);
|
||||
//# sourceMappingURL=2441-2441.js.map?v=abb0f9caea1b27348963
|
||||
2
dist/2441-2441.js.map
vendored
2
dist/2441-2441.js.map
vendored
|
|
@ -1 +1 @@
|
|||
{"version":3,"file":"2441-2441.js?v=44b85e4901c485417f88","mappings":"oIACA,MAAMA,GAAgB,E,SAAA,KAAqB,IAAM,oE","sources":["webpack:///nextcloud/node_modules/@nextcloud/dialogs/dist/chunks/index-Ly0obkwS.mjs"],"sourcesContent":["import { defineAsyncComponent } from \"vue\";\nconst FilePickerVue = defineAsyncComponent(() => import(\"./FilePicker-CSmrMOEO.mjs\"));\nexport {\n FilePickerVue\n};\n"],"names":["FilePickerVue"],"sourceRoot":""}
|
||||
{"version":3,"file":"2441-2441.js?v=abb0f9caea1b27348963","mappings":"oIACA,MAAMA,GAAgB,E,SAAA,KAAqB,IAAM,0D","sources":["webpack:///nextcloud/node_modules/@nextcloud/dialogs/dist/chunks/index-Ly0obkwS.mjs"],"sourcesContent":["import { defineAsyncComponent } from \"vue\";\nconst FilePickerVue = defineAsyncComponent(() => import(\"./FilePicker-CSmrMOEO.mjs\"));\nexport {\n FilePickerVue\n};\n"],"names":["FilePickerVue"],"sourceRoot":""}
|
||||
2
dist/6146-6146.js
vendored
2
dist/6146-6146.js
vendored
File diff suppressed because one or more lines are too long
1
dist/6146-6146.js.map
vendored
1
dist/6146-6146.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/6146-6146.js.map.license
vendored
1
dist/6146-6146.js.map.license
vendored
|
|
@ -1 +0,0 @@
|
|||
6146-6146.js.license
|
||||
2
dist/8289-8289.js
vendored
2
dist/8289-8289.js
vendored
File diff suppressed because one or more lines are too long
1
dist/8289-8289.js.map
vendored
1
dist/8289-8289.js.map
vendored
File diff suppressed because one or more lines are too long
1
dist/8289-8289.js.map.license
vendored
1
dist/8289-8289.js.map.license
vendored
|
|
@ -1 +0,0 @@
|
|||
8289-8289.js.license
|
||||
2
dist/9904-9904.js
vendored
Normal file
2
dist/9904-9904.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/9904-9904.js.map
vendored
Normal file
1
dist/9904-9904.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/9904-9904.js.map.license
vendored
Symbolic link
1
dist/9904-9904.js.map.license
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
9904-9904.js.license
|
||||
4
dist/comments-comments-app.js
vendored
4
dist/comments-comments-app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/comments-comments-app.js.map
vendored
2
dist/comments-comments-app.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/comments-comments-tab.js
vendored
4
dist/comments-comments-tab.js
vendored
File diff suppressed because one or more lines are too long
2
dist/comments-comments-tab.js.map
vendored
2
dist/comments-comments-tab.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-common.js
vendored
4
dist/core-common.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-common.js.map
vendored
2
dist/core-common.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-legacy-unified-search.js
vendored
4
dist/core-legacy-unified-search.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-legacy-unified-search.js.map
vendored
2
dist/core-legacy-unified-search.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-login.js
vendored
4
dist/core-login.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-login.js.map
vendored
2
dist/core-login.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-main.js
vendored
4
dist/core-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-main.js.map
vendored
2
dist/core-main.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/core-public-page-menu.js
vendored
4
dist/core-public-page-menu.js
vendored
File diff suppressed because one or more lines are too long
2
dist/core-public-page-menu.js.map
vendored
2
dist/core-public-page-menu.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/dav-settings-example-content.js
vendored
Normal file
2
dist/dav-settings-example-content.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -11,10 +11,12 @@ SPDX-FileCopyrightText: xiemengxiong
|
|||
SPDX-FileCopyrightText: xiaokai <kexiaokai@gmail.com>
|
||||
SPDX-FileCopyrightText: rhysd <lin90162@yahoo.co.jp>
|
||||
SPDX-FileCopyrightText: inline-style-parser developers
|
||||
SPDX-FileCopyrightText: inherits developers
|
||||
SPDX-FileCopyrightText: escape-html developers
|
||||
SPDX-FileCopyrightText: debounce developers
|
||||
SPDX-FileCopyrightText: atomiks
|
||||
SPDX-FileCopyrightText: Victor Felder <victor@draft.li> (https://draft.li)
|
||||
SPDX-FileCopyrightText: Varun A P
|
||||
SPDX-FileCopyrightText: Tobias Koppers @sokra
|
||||
SPDX-FileCopyrightText: Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)
|
||||
SPDX-FileCopyrightText: Thorsten Lünborg
|
||||
|
|
@ -23,6 +25,7 @@ SPDX-FileCopyrightText: Stefan Thomas <justmoon@members.fsf.org> (http://www.jus
|
|||
SPDX-FileCopyrightText: Sindre Sorhus
|
||||
SPDX-FileCopyrightText: Roman Shtylman <shtylman@gmail.com>
|
||||
SPDX-FileCopyrightText: Roeland Jago Douma
|
||||
SPDX-FileCopyrightText: Rob Cresswell <robcresswell@pm.me>
|
||||
SPDX-FileCopyrightText: Richie Bendall
|
||||
SPDX-FileCopyrightText: Philipp Kewisch
|
||||
SPDX-FileCopyrightText: Paul Vorbach <paul@vorba.ch> (http://paul.vorba.ch)
|
||||
|
|
@ -32,6 +35,7 @@ SPDX-FileCopyrightText: Nextcloud GmbH and Nextcloud contributors
|
|||
SPDX-FileCopyrightText: Matt Zabriskie
|
||||
SPDX-FileCopyrightText: Mark <mark@remarkablemark.org>
|
||||
SPDX-FileCopyrightText: Mapbox
|
||||
SPDX-FileCopyrightText: Joyent
|
||||
SPDX-FileCopyrightText: John Molakvoæ (skjnldsv) <skjnldsv@protonmail.com>
|
||||
SPDX-FileCopyrightText: Jeff Sagal <sagalbot@gmail.com>
|
||||
SPDX-FileCopyrightText: Jacob Clevenger<https://github.com/wheatjs>
|
||||
|
|
@ -46,9 +50,11 @@ SPDX-FileCopyrightText: Dr.-Ing. Mario Heiderich, Cure53 <mario@cure53.de> (http
|
|||
SPDX-FileCopyrightText: David Clark
|
||||
SPDX-FileCopyrightText: Christoph Wurst
|
||||
SPDX-FileCopyrightText: Borys Serebrov
|
||||
SPDX-FileCopyrightText: Austin Andrews
|
||||
SPDX-FileCopyrightText: Antoni Andre <antoniandre.web@gmail.com>
|
||||
SPDX-FileCopyrightText: Anthony Fu <https://github.com/antfu>
|
||||
SPDX-FileCopyrightText: Andrea Giammarchi
|
||||
SPDX-FileCopyrightText: @nextcloud/dialogs developers
|
||||
|
||||
|
||||
This file is generated from multiple sources. Included packages:
|
||||
|
|
@ -73,6 +79,9 @@ This file is generated from multiple sources. Included packages:
|
|||
- @mapbox/hast-util-table-cell-style
|
||||
- version: 0.2.1
|
||||
- license: BSD-2-Clause
|
||||
- @mdi/svg
|
||||
- version: 7.4.47
|
||||
- license: Apache-2.0
|
||||
- @nextcloud/auth
|
||||
- version: 2.4.0
|
||||
- license: GPL-3.0-or-later
|
||||
|
|
@ -85,6 +94,9 @@ This file is generated from multiple sources. Included packages:
|
|||
- @nextcloud/capabilities
|
||||
- version: 1.2.0
|
||||
- license: GPL-3.0-or-later
|
||||
- @nextcloud/dialogs
|
||||
- version: 6.1.1
|
||||
- license: AGPL-3.0-or-later
|
||||
- semver
|
||||
- version: 7.6.3
|
||||
- license: ISC
|
||||
|
|
@ -343,6 +355,15 @@ This file is generated from multiple sources. Included packages:
|
|||
- buffer
|
||||
- version: 6.0.3
|
||||
- license: MIT
|
||||
- inherits
|
||||
- version: 2.0.3
|
||||
- license: ISC
|
||||
- util
|
||||
- version: 0.10.4
|
||||
- license: MIT
|
||||
- path
|
||||
- version: 0.12.7
|
||||
- license: MIT
|
||||
- process
|
||||
- version: 0.11.10
|
||||
- license: MIT
|
||||
|
|
@ -385,6 +406,9 @@ This file is generated from multiple sources. Included packages:
|
|||
- tabbable
|
||||
- version: 6.2.0
|
||||
- license: MIT
|
||||
- toastify-js
|
||||
- version: 1.12.0
|
||||
- license: MIT
|
||||
- trim-lines
|
||||
- version: 3.0.1
|
||||
- license: MIT
|
||||
|
|
@ -424,6 +448,12 @@ This file is generated from multiple sources. Included packages:
|
|||
- vue-frag
|
||||
- version: 1.4.3
|
||||
- license: MIT
|
||||
- vue-loader
|
||||
- version: 15.11.1
|
||||
- license: MIT
|
||||
- vue-material-design-icons
|
||||
- version: 5.3.1
|
||||
- license: MIT
|
||||
- vue-router
|
||||
- version: 3.6.5
|
||||
- license: MIT
|
||||
|
|
@ -433,6 +463,12 @@ This file is generated from multiple sources. Included packages:
|
|||
- web-namespaces
|
||||
- version: 2.0.1
|
||||
- license: MIT
|
||||
- webpack
|
||||
- version: 5.94.0
|
||||
- license: MIT
|
||||
- zwitch
|
||||
- version: 2.0.4
|
||||
- license: MIT
|
||||
- nextcloud
|
||||
- version: 1.0.0
|
||||
- license: AGPL-3.0-or-later
|
||||
1
dist/dav-settings-example-content.js.map
vendored
Normal file
1
dist/dav-settings-example-content.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
1
dist/dav-settings-example-content.js.map.license
vendored
Symbolic link
1
dist/dav-settings-example-content.js.map.license
vendored
Symbolic link
|
|
@ -0,0 +1 @@
|
|||
dav-settings-example-content.js.license
|
||||
4
dist/dav-settings-personal-availability.js
vendored
4
dist/dav-settings-personal-availability.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/federatedfilesharing-external.js
vendored
4
dist/federatedfilesharing-external.js
vendored
File diff suppressed because one or more lines are too long
2
dist/federatedfilesharing-external.js.map
vendored
2
dist/federatedfilesharing-external.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/files-init.js
vendored
4
dist/files-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-init.js.map
vendored
2
dist/files-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-main.js
vendored
4
dist/files-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-main.js.map
vendored
2
dist/files-main.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-reference-files.js
vendored
4
dist/files-reference-files.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-reference-files.js.map
vendored
2
dist/files-reference-files.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-search.js
vendored
4
dist/files-search.js
vendored
|
|
@ -1,2 +1,2 @@
|
|||
(()=>{"use strict";var e,r,t,i={97986:(e,r,t)=>{var i=t(61338),o=t(85168),a=t(63814),n=t(53334);const l=(0,t(35947).YK)().setApp("files").detectUser().build();document.addEventListener("DOMContentLoaded",(function(){const e=window.OCA;e.UnifiedSearch&&(l.info("Initializing unified search plugin: folder search from files app"),e.UnifiedSearch.registerFilterAction({id:"in-folder",appId:"files",searchFrom:"files",label:(0,n.Tl)("files","In folder"),icon:(0,a.d0)("files","app.svg"),callback:function(){arguments.length>0&&void 0!==arguments[0]&&!arguments[0]?l.debug("Folder search callback was handled without showing the file picker, it might already be open"):(0,o.a1)("Pick plain text files").addMimeTypeFilter("httpd/unix-directory").allowDirectories(!0).addButton({label:"Pick",callback:e=>{l.info("Folder picked",{folder:e[0]});const r=e[0];(0,i.Ic)("nextcloud:unified-search:add-filter",{id:"in-folder",appId:"files",searchFrom:"files",payload:r,filterUpdateText:(0,n.Tl)("files","Search in folder: {folder}",{folder:r.basename}),filterParams:{path:r.path}})}}).build().pick()}}))}))}},o={};function a(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={id:e,loaded:!1,exports:{}};return i[e].call(t.exports,t,t.exports,a),t.loaded=!0,t.exports}a.m=i,e=[],a.O=(r,t,i,o)=>{if(!t){var n=1/0;for(s=0;s<e.length;s++){t=e[s][0],i=e[s][1],o=e[s][2];for(var l=!0,d=0;d<t.length;d++)(!1&o||n>=o)&&Object.keys(a.O).every((e=>a.O[e](t[d])))?t.splice(d--,1):(l=!1,o<n&&(n=o));if(l){e.splice(s--,1);var c=i();void 0!==c&&(r=c)}}return r}o=o||0;for(var s=e.length;s>0&&e[s-1][2]>o;s--)e[s]=e[s-1];e[s]=[t,i,o]},a.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return a.d(r,{a:r}),r},a.d=(e,r)=>{for(var t in r)a.o(r,t)&&!a.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((r,t)=>(a.f[t](e,r),r)),[])),a.u=e=>e+"-"+e+".js?v="+{2441:"44b85e4901c485417f88",5862:"142cd48ca8ec32e57725",6146:"5f2015343db7411125d5",8289:"8f098190dce9305dab1e"}[e],a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),a.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="nextcloud:",a.l=(e,i,o,n)=>{if(r[e])r[e].push(i);else{var l,d;if(void 0!==o)for(var c=document.getElementsByTagName("script"),s=0;s<c.length;s++){var f=c[s];if(f.getAttribute("src")==e||f.getAttribute("data-webpack")==t+o){l=f;break}}l||(d=!0,(l=document.createElement("script")).charset="utf-8",l.timeout=120,a.nc&&l.setAttribute("nonce",a.nc),l.setAttribute("data-webpack",t+o),l.src=e),r[e]=[i];var u=(t,i)=>{l.onerror=l.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],l.parentNode&&l.parentNode.removeChild(l),o&&o.forEach((e=>e(i))),t)return t(i)},p=setTimeout(u.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=u.bind(null,l.onerror),l.onload=u.bind(null,l.onload),d&&document.head.appendChild(l)}},a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),a.j=2277,(()=>{var e;a.g.importScripts&&(e=a.g.location+"");var r=a.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var i=t.length-1;i>-1&&(!e||!/^http(s?):/.test(e));)e=t[i--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),a.p=e})(),(()=>{a.b=document.baseURI||self.location.href;var e={2277:0};a.f.j=(r,t)=>{var i=a.o(e,r)?e[r]:void 0;if(0!==i)if(i)t.push(i[2]);else{var o=new Promise(((t,o)=>i=e[r]=[t,o]));t.push(i[2]=o);var n=a.p+a.u(r),l=new Error;a.l(n,(t=>{if(a.o(e,r)&&(0!==(i=e[r])&&(e[r]=void 0),i)){var o=t&&("load"===t.type?"missing":t.type),n=t&&t.target&&t.target.src;l.message="Loading chunk "+r+" failed.\n("+o+": "+n+")",l.name="ChunkLoadError",l.type=o,l.request=n,i[1](l)}}),"chunk-"+r,r)}},a.O.j=r=>0===e[r];var r=(r,t)=>{var i,o,n=t[0],l=t[1],d=t[2],c=0;if(n.some((r=>0!==e[r]))){for(i in l)a.o(l,i)&&(a.m[i]=l[i]);if(d)var s=d(a)}for(r&&r(t);c<n.length;c++)o=n[c],a.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return a.O(s)},t=self.webpackChunknextcloud=self.webpackChunknextcloud||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),a.nc=void 0;var n=a.O(void 0,[4208],(()=>a(97986)));n=a.O(n)})();
|
||||
//# sourceMappingURL=files-search.js.map?v=cf9e1d416f4a63412a17
|
||||
(()=>{"use strict";var e,r,t,i={97986:(e,r,t)=>{var i=t(61338),o=t(85168),a=t(63814),n=t(53334);const l=(0,t(35947).YK)().setApp("files").detectUser().build();document.addEventListener("DOMContentLoaded",(function(){const e=window.OCA;e.UnifiedSearch&&(l.info("Initializing unified search plugin: folder search from files app"),e.UnifiedSearch.registerFilterAction({id:"in-folder",appId:"files",searchFrom:"files",label:(0,n.Tl)("files","In folder"),icon:(0,a.d0)("files","app.svg"),callback:function(){arguments.length>0&&void 0!==arguments[0]&&!arguments[0]?l.debug("Folder search callback was handled without showing the file picker, it might already be open"):(0,o.a1)("Pick plain text files").addMimeTypeFilter("httpd/unix-directory").allowDirectories(!0).addButton({label:"Pick",callback:e=>{l.info("Folder picked",{folder:e[0]});const r=e[0];(0,i.Ic)("nextcloud:unified-search:add-filter",{id:"in-folder",appId:"files",searchFrom:"files",payload:r,filterUpdateText:(0,n.Tl)("files","Search in folder: {folder}",{folder:r.basename}),filterParams:{path:r.path}})}}).build().pick()}}))}))}},o={};function a(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={id:e,loaded:!1,exports:{}};return i[e].call(t.exports,t,t.exports,a),t.loaded=!0,t.exports}a.m=i,e=[],a.O=(r,t,i,o)=>{if(!t){var n=1/0;for(s=0;s<e.length;s++){t=e[s][0],i=e[s][1],o=e[s][2];for(var l=!0,d=0;d<t.length;d++)(!1&o||n>=o)&&Object.keys(a.O).every((e=>a.O[e](t[d])))?t.splice(d--,1):(l=!1,o<n&&(n=o));if(l){e.splice(s--,1);var c=i();void 0!==c&&(r=c)}}return r}o=o||0;for(var s=e.length;s>0&&e[s-1][2]>o;s--)e[s]=e[s-1];e[s]=[t,i,o]},a.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return a.d(r,{a:r}),r},a.d=(e,r)=>{for(var t in r)a.o(r,t)&&!a.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},a.f={},a.e=e=>Promise.all(Object.keys(a.f).reduce(((r,t)=>(a.f[t](e,r),r)),[])),a.u=e=>e+"-"+e+".js?v="+{2441:"abb0f9caea1b27348963",5862:"142cd48ca8ec32e57725",9904:"524c00bcce4222bb9815"}[e],a.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),a.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),r={},t="nextcloud:",a.l=(e,i,o,n)=>{if(r[e])r[e].push(i);else{var l,d;if(void 0!==o)for(var c=document.getElementsByTagName("script"),s=0;s<c.length;s++){var f=c[s];if(f.getAttribute("src")==e||f.getAttribute("data-webpack")==t+o){l=f;break}}l||(d=!0,(l=document.createElement("script")).charset="utf-8",l.timeout=120,a.nc&&l.setAttribute("nonce",a.nc),l.setAttribute("data-webpack",t+o),l.src=e),r[e]=[i];var u=(t,i)=>{l.onerror=l.onload=null,clearTimeout(p);var o=r[e];if(delete r[e],l.parentNode&&l.parentNode.removeChild(l),o&&o.forEach((e=>e(i))),t)return t(i)},p=setTimeout(u.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=u.bind(null,l.onerror),l.onload=u.bind(null,l.onload),d&&document.head.appendChild(l)}},a.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},a.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),a.j=2277,(()=>{var e;a.g.importScripts&&(e=a.g.location+"");var r=a.g.document;if(!e&&r&&(r.currentScript&&"SCRIPT"===r.currentScript.tagName.toUpperCase()&&(e=r.currentScript.src),!e)){var t=r.getElementsByTagName("script");if(t.length)for(var i=t.length-1;i>-1&&(!e||!/^http(s?):/.test(e));)e=t[i--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),a.p=e})(),(()=>{a.b=document.baseURI||self.location.href;var e={2277:0};a.f.j=(r,t)=>{var i=a.o(e,r)?e[r]:void 0;if(0!==i)if(i)t.push(i[2]);else{var o=new Promise(((t,o)=>i=e[r]=[t,o]));t.push(i[2]=o);var n=a.p+a.u(r),l=new Error;a.l(n,(t=>{if(a.o(e,r)&&(0!==(i=e[r])&&(e[r]=void 0),i)){var o=t&&("load"===t.type?"missing":t.type),n=t&&t.target&&t.target.src;l.message="Loading chunk "+r+" failed.\n("+o+": "+n+")",l.name="ChunkLoadError",l.type=o,l.request=n,i[1](l)}}),"chunk-"+r,r)}},a.O.j=r=>0===e[r];var r=(r,t)=>{var i,o,n=t[0],l=t[1],d=t[2],c=0;if(n.some((r=>0!==e[r]))){for(i in l)a.o(l,i)&&(a.m[i]=l[i]);if(d)var s=d(a)}for(r&&r(t);c<n.length;c++)o=n[c],a.o(e,o)&&e[o]&&e[o][0](),e[o]=0;return a.O(s)},t=self.webpackChunknextcloud=self.webpackChunknextcloud||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),a.nc=void 0;var n=a.O(void 0,[4208],(()=>a(97986)));n=a.O(n)})();
|
||||
//# sourceMappingURL=files-search.js.map?v=ac56153c5e375af6d5ff
|
||||
2
dist/files-search.js.map
vendored
2
dist/files-search.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-settings-personal.js
vendored
4
dist/files-settings-personal.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-settings-personal.js.map
vendored
2
dist/files-settings-personal.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files-sidebar.js
vendored
4
dist/files-sidebar.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files-sidebar.js.map
vendored
2
dist/files-sidebar.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_external-init.js
vendored
4
dist/files_external-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_external-init.js.map
vendored
2
dist/files_external-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_external-settings.js
vendored
4
dist/files_external-settings.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_external-settings.js.map
vendored
2
dist/files_external-settings.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_reminders-init.js
vendored
4
dist/files_reminders-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_reminders-init.js.map
vendored
2
dist/files_reminders-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-files_sharing_tab.js
vendored
4
dist/files_sharing-files_sharing_tab.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-files_sharing_tab.js.map
vendored
2
dist/files_sharing-files_sharing_tab.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-init-public.js
vendored
4
dist/files_sharing-init-public.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-init-public.js.map
vendored
2
dist/files_sharing-init-public.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-init.js
vendored
4
dist/files_sharing-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-init.js.map
vendored
2
dist/files_sharing-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-personal-settings.js
vendored
4
dist/files_sharing-personal-settings.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_sharing-personal-settings.js.map
vendored
2
dist/files_sharing-personal-settings.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_sharing-public-file-request.js
vendored
4
dist/files_sharing-public-file-request.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/files_trashbin-init.js
vendored
4
dist/files_trashbin-init.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_trashbin-init.js.map
vendored
2
dist/files_trashbin-init.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/files_versions-files_versions.js
vendored
4
dist/files_versions-files_versions.js
vendored
File diff suppressed because one or more lines are too long
2
dist/files_versions-files_versions.js.map
vendored
2
dist/files_versions-files_versions.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/profile-main.js
vendored
4
dist/profile-main.js
vendored
File diff suppressed because one or more lines are too long
2
dist/profile-main.js.map
vendored
2
dist/profile-main.js.map
vendored
File diff suppressed because one or more lines are too long
4
dist/settings-declarative-settings-forms.js
vendored
4
dist/settings-declarative-settings-forms.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/settings-users-3239.js
vendored
4
dist/settings-users-3239.js
vendored
File diff suppressed because one or more lines are too long
2
dist/settings-users-3239.js.map
vendored
2
dist/settings-users-3239.js.map
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/settings-vue-settings-admin-security.js
vendored
4
dist/settings-vue-settings-admin-security.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
4
dist/settings-vue-settings-admin-sharing.js
vendored
4
dist/settings-vue-settings-admin-sharing.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue