Skip to content

Commit

Permalink
fixup! feat: add example contact on first login
Browse files Browse the repository at this point in the history
Signed-off-by: Hamza Mahjoubi <[email protected]>
  • Loading branch information
hamza221 committed Jan 23, 2025
1 parent 3af4fc4 commit 76cd083
Show file tree
Hide file tree
Showing 22 changed files with 799 additions and 12 deletions.
1 change: 1 addition & 0 deletions apps/dav/appinfo/info.xml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

<settings>
<admin>OCA\DAV\Settings\CalDAVSettings</admin>
<admin>OCA\DAV\Settings\ExampleContentSettings</admin>
<personal>OCA\DAV\Settings\AvailabilitySettings</personal>
</settings>

Expand Down
2 changes: 2 additions & 0 deletions apps/dav/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
['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#set_default_contact', 'url' => '/api/defaultcontact/contact', 'verb' => 'PUT'],
['name' => 'example_content#set-app-config', 'url' => '/api/defaultcontact/config', 'verb' => 'PUT'],
],
'ocs' => [
['name' => 'direct#getUrl', 'url' => '/api/v1/direct', 'verb' => 'POST'],
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@
'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',
'OCA\\DAV\\Controller\\ExampleContentController' => $baseDir . '/..' . '/../lib/Controller/ExampleContentController.php',
'OCA\\DAV\\DAV\\CustomPropertiesBackend' => $baseDir . '/../lib/DAV/CustomPropertiesBackend.php',
'OCA\\DAV\\DAV\\GroupPrincipalBackend' => $baseDir . '/../lib/DAV/GroupPrincipalBackend.php',
'OCA\\DAV\\DAV\\PublicAuth' => $baseDir . '/../lib/DAV/PublicAuth.php',
Expand Down Expand Up @@ -360,6 +361,7 @@
'OCA\\DAV\\Service\\DefaultContactService' => $baseDir . '/../lib/Service/DefaultContactService.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',
Expand Down
2 changes: 2 additions & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class ComposerStaticInitDAV
'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',
'OCA\\DAV\\Controller\\ExampleContentController' => __DIR__ . '/..' . '/../lib/Controller/ExampleContentController.php',
'OCA\\DAV\\DAV\\CustomPropertiesBackend' => __DIR__ . '/..' . '/../lib/DAV/CustomPropertiesBackend.php',
'OCA\\DAV\\DAV\\GroupPrincipalBackend' => __DIR__ . '/..' . '/../lib/DAV/GroupPrincipalBackend.php',
'OCA\\DAV\\DAV\\PublicAuth' => __DIR__ . '/..' . '/../lib/DAV/PublicAuth.php',
Expand Down Expand Up @@ -375,6 +376,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Service\\DefaultContactService' => __DIR__ . '/..' . '/../lib/Service/DefaultContactService.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',
Expand Down
90 changes: 90 additions & 0 deletions apps/dav/lib/Controller/ExampleContentController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
/**
* SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\DAV\Controller;

use OCA\Contacts\AppInfo\Application;
use OCP\App\IAppManager;
use OCP\AppFramework\ApiController;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\JSONResponse;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IRequest;

class ExampleContentController extends ApiController {

public function __construct(
IRequest $request,
private IConfig $config,
private IAppData $appData,
private IAppManager $appManager,
) {
parent::__construct(Application::APP_ID, $request);
}


/**
* update appconfig (admin setting)
*
* @param string allow the value to set
*
* @return JSONResponse an empty JSONResponse with respective http status code
*/
public function setAppConfig($key, $allow) {
if ($allow === 'yes' && $key === 'enableDefaultContact' && !$this->defaultContactExists()) {
$this->setInitialDefaultContact();
}
$this->config->setAppValue(Application::APP_ID, $key, $allow);
return new JSONResponse([], Http::STATUS_OK);
}

public function setDefaultContact($contactData) {
if (!$this->config->getAppValue(Application::APP_ID, 'enableDefaultContact', 'yes')) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}
try {
$folder = $this->appData->getFolder('defaultContact');
} catch (NotFoundException $e) {
$folder = $this->appData->newFolder('defaultContact');
}
$file = (!$folder->fileExists('defaultContact.vcf')) ? $folder->newFile('defaultContact.vcf') : $folder->getFile('defaultContact.vcf');
$file->putContent($contactData);
return new JSONResponse([], Http::STATUS_OK);
}

private function setInitialDefaultContact() {
$cardData = 'BEGIN:VCARD' . PHP_EOL .
'VERSION:3.0' . PHP_EOL .
'PRODID:-//Nextcloud Contacts v' . $this->appManager->getAppVersion('contacts') . PHP_EOL .
'UID: janeDoe' . PHP_EOL .
'FN:Jane Doe' . PHP_EOL .
'ADR;TYPE=HOME:;;123 Street Street;City;State;;Country' . PHP_EOL .
'EMAIL;TYPE=WORK:[email protected]' . PHP_EOL .
'TEL;TYPE=HOME,VOICE:+999999999999' . PHP_EOL .
'TITLE:Manager' . PHP_EOL .
'ORG:Company' . PHP_EOL .
'BDAY;VALUE=DATE:20000101' . PHP_EOL .
'URL;VALUE=URI:https://example.com/' . PHP_EOL .
'REV;VALUE=DATE-AND-OR-TIME:20241227T144820Z' . PHP_EOL .
'END:VCARD';
$folder = $this->appData->getFolder('defaultContact');
$file = $folder->newFile('defaultContact.vcf');
$file->putContent($cardData);
}

private function defaultContactExists(): bool {
try {
$folder = $this->appData->getFolder('defaultContact');
} catch (NotFoundException $e) {
$this->appData->newFolder('defaultContact');
return false;
}
return $folder->fileExists('defaultContact.vcf');
}

}
65 changes: 65 additions & 0 deletions apps/dav/lib/Settings/ExampleContentSettings.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
<?php
/**
* SPDX-FileCopyrightText: 2017 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\IDelegatedSettings;

class ExampleContentSettings implements IDelegatedSettings {

private const defaults = [
'enableDefaultContact' => 'yes',
];

/**
* ExampleContentSettings constructor.
*
* @param IConfig $config
* @param IInitialState $initialState
*/
public function __construct(
private IConfig $config,
private IInitialState $initialState,
private IAppManager $appManager,
) {
}

public function getForm(): TemplateResponse {
$enableDefaultContact = $this->config->getAppValue(Application::APP_ID, 'enableDefaultContact', 'yes');
$this->initialState->provideInitialState(Application::APP_ID, 'enableDefaultContact', $enableDefaultContact);
return new TemplateResponse(Application::APP_ID, 'settings-example-content');
}

public function getSection(): ?string {
/* if (!$this->appManager->isEnabledForUser('contacts')) {
return null;
}*/

return 'groupware';
}

/**
* @return int
*/
public function getPriority() {
return 10;
}

public function getName(): ?string {
return 'Example Content';
}

public function getAuthorizedAppConfig(): array {
return [
'dav' => ['/(' . implode('|', array_keys(self::defaults)) . ')/']
];
}

}
13 changes: 13 additions & 0 deletions apps/dav/src/settings-example-content.js
Original file line number Diff line number Diff line change
@@ -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')
114 changes: 114 additions & 0 deletions apps/dav/src/views/ExampleContactSettings.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<!--
- 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')"
:description="$t('dav', 'Set example content to be created on new user first login.')">
<p>
<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>
<NcButton v-if="enableDefaultContact"
class="import-button"
type="primary"
@click="toggleModal">
<template #icon>
<IconUpload :size="20" />
</template>
{{ $t('contacts', 'Import contact') }}
</NcButton>
<NcDialog :open.sync="isModalOpen"
:name="$t('contacts', '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>
<input id="contact-import"
ref="contact-import-input"
:disabled="loading"
type="file"
class="hidden-visually"
@change="processFile">
</div>
</NcDialog>
</p>
</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 { showSuccess } from '@nextcloud/dialogs'
import IconUpload from 'vue-material-design-icons/Upload.vue'
import IconCancel from '@mdi/svg/svg/cancel.svg'
import IconCheck from '@mdi/svg/svg/check.svg'

export default {
name: 'ExampleContactSettings',
components: {
NcDialog,
NcButton,
NcSettingsSection,
IconUpload,
},
data() {
return {
enableDefaultContact: loadState('contacts', 'enableDefaultContact') === 'yes',
isModalOpen: false,
loading: false,
buttons: [
{
label: this.$t('contacts', 'Cancel'),
icon: IconCancel,
callback: () => { this.isModalOpen = false },
},
{
label: this.$t('contacts', 'Import'),
type: 'primary',
icon: IconCheck,
callback: () => { this.clickImportInput() },
},
],
}
},
methods: {
updateEnableDefaultContact() {
axios.put(generateUrl('apps/dav/api/defaultcontact/config/{key}', { key: 'enableDefaultContact' }), {
allow: this.enableDefaultContact ? 'yes' : 'no',
})
},
toggleModal() {
this.isModalOpen = !this.isModalOpen
},
clickImportInput() {
this.$refs['contact-import-input'].click()
},

processFile(event) {
this.loading = true

const file = event.target.files[0]
const reader = new FileReader()

reader.onload = () => {
this.isModalOpen = false
axios.put(generateUrl('/apps/dav/api/defaultcontact/contact'), { contactData: reader.result })
event.target.value = ''
}
reader.readAsText(file)
showSuccess(this.$t('dav', 'Contact imported successfully'))
},
},
}
</script>
<style lang="scss" scoped>
.import-button {
margin-top: 1rem;
}
</style>
11 changes: 11 additions & 0 deletions apps/dav/templates/settings-example-content.php
Original file line number Diff line number Diff line change
@@ -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>
Loading

0 comments on commit 76cd083

Please sign in to comment.