Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion apps/dav/appinfo/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*
* @author Georg Ehrke <[email protected]>
* @author Roeland Jago Douma <[email protected]>
* @author Richard Steinmetz <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
Expand All @@ -28,7 +29,9 @@
['name' => 'invitation_response#accept', 'url' => '/invitation/accept/{token}', 'verb' => 'GET'],
['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' => 'invitation_response#processMoreOptionsResult', 'url' => '/invitation/moreOptions/{token}', 'verb' => 'POST'],
['name' => 'availability_settings#updateAbsence', 'url' => '/settings/absence', 'verb' => 'POST'],
['name' => 'availability_settings#clearAbsence', 'url' => '/settings/absence', 'verb' => 'DELETE'],
],
'ocs' => [
['name' => 'direct#getUrl', 'url' => '/api/v1/direct', 'verb' => 'POST'],
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
'OCA\\DAV\\Connector\\Sabre\\SharesPlugin' => $baseDir . '/../lib/Connector/Sabre/SharesPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\TagList' => $baseDir . '/../lib/Connector/Sabre/TagList.php',
'OCA\\DAV\\Connector\\Sabre\\TagsPlugin' => $baseDir . '/../lib/Connector/Sabre/TagsPlugin.php',
'OCA\\DAV\\Controller\\AvailabilitySettingsController' => $baseDir . '/../lib/Controller/AvailabilitySettingsController.php',
'OCA\\DAV\\Controller\\BirthdayCalendarController' => $baseDir . '/../lib/Controller/BirthdayCalendarController.php',
'OCA\\DAV\\Controller\\DirectController' => $baseDir . '/../lib/Controller/DirectController.php',
'OCA\\DAV\\Controller\\InvitationResponseController' => $baseDir . '/../lib/Controller/InvitationResponseController.php',
Expand Down
1 change: 1 addition & 0 deletions apps/dav/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class ComposerStaticInitDAV
'OCA\\DAV\\Connector\\Sabre\\SharesPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/SharesPlugin.php',
'OCA\\DAV\\Connector\\Sabre\\TagList' => __DIR__ . '/..' . '/../lib/Connector/Sabre/TagList.php',
'OCA\\DAV\\Connector\\Sabre\\TagsPlugin' => __DIR__ . '/..' . '/../lib/Connector/Sabre/TagsPlugin.php',
'OCA\\DAV\\Controller\\AvailabilitySettingsController' => __DIR__ . '/..' . '/../lib/Controller/AvailabilitySettingsController.php',
'OCA\\DAV\\Controller\\BirthdayCalendarController' => __DIR__ . '/..' . '/../lib/Controller/BirthdayCalendarController.php',
'OCA\\DAV\\Controller\\DirectController' => __DIR__ . '/..' . '/../lib/Controller/DirectController.php',
'OCA\\DAV\\Controller\\InvitationResponseController' => __DIR__ . '/..' . '/../lib/Controller/InvitationResponseController.php',
Expand Down
94 changes: 94 additions & 0 deletions apps/dav/lib/Controller/AvailabilitySettingsController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<?php

declare(strict_types=1);

/**
* @copyright Copyright (c) 2023 Richard Steinmetz <[email protected]>
*
* @author Richard Steinmetz <[email protected]>
*
* @license AGPL-3.0-or-later
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/

namespace OCA\DAV\Controller;

use DateTimeImmutable;
use OCA\DAV\AppInfo\Application;
use OCA\DAV\Service\AbsenceService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\Attribute\NoAdminRequired;
use OCP\AppFramework\Http\JSONResponse;
use OCP\AppFramework\Http\Response;
use OCP\IRequest;

class AvailabilitySettingsController extends Controller {
public function __construct(
IRequest $request,
private ?string $userId,
private AbsenceService $absenceService,
) {
parent::__construct(Application::APP_ID, $request);
}

/**
* @throws \OCP\DB\Exception
* @throws \Exception
*/
#[NoAdminRequired]
public function updateAbsence(
string $firstDay,
string $lastDay,
string $status,
string $message,
): Response {
$userId = $this->userId;
if ($userId === null) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}

$parsedFirstDay = new DateTimeImmutable($firstDay);
$parsedLastDay = new DateTimeImmutable($lastDay);
if ($parsedFirstDay->getTimestamp() >= $parsedLastDay->getTimestamp()) {
throw new \Exception('First day is on or after last day');
}

$absence = $this->absenceService->createOrUpdateAbsence(
$userId,
$firstDay,
$lastDay,
$status,
$message,
);
return new JSONResponse($absence);
}

/**
* @throws \OCP\DB\Exception
*/
#[NoAdminRequired]
public function clearAbsence(): Response {
$userId = $this->userId;
if ($userId === null) {
return new JSONResponse([], Http::STATUS_FORBIDDEN);
}

$this->absenceService->clearAbsence($userId);
return new JSONResponse([]);
}

}
27 changes: 26 additions & 1 deletion apps/dav/lib/Settings/AvailabilitySettings.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
* @copyright 2021 Christoph Wurst <[email protected]>
*
* @author 2021 Christoph Wurst <[email protected]>
* @author Richard Steinmetz <[email protected]>
*
* @license GNU AGPL version 3 or any later version
*
Expand All @@ -26,10 +27,13 @@
namespace OCA\DAV\Settings;

use OCA\DAV\AppInfo\Application;
use OCA\DAV\Db\AbsenceMapper;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\AppFramework\Http\TemplateResponse;
use OCP\AppFramework\Services\IInitialState;
use OCP\IConfig;
use OCP\Settings\ISettings;
use Psr\Log\LoggerInterface;

class AvailabilitySettings implements ISettings {
protected IConfig $config;
Expand All @@ -38,7 +42,9 @@ class AvailabilitySettings implements ISettings {

public function __construct(IConfig $config,
IInitialState $initialState,
?string $userId) {
?string $userId,
private LoggerInterface $logger,
private AbsenceMapper $absenceMapper) {
$this->config = $config;
$this->initialState = $initialState;
$this->userId = $userId;
Expand All @@ -54,6 +60,25 @@ public function getForm(): TemplateResponse {
'no'
)
);
$hideAbsenceSettings = $this->config->getAppValue(
Application::APP_ID,
'hide_absence_settings',
'yes',
) === 'yes';
$this->initialState->provideInitialState('hide_absence_settings', $hideAbsenceSettings);
if (!$hideAbsenceSettings) {
try {
$absence = $this->absenceMapper->findByUserId($this->userId);

Check notice

Code scanning / Psalm

PossiblyNullArgument

Argument 1 of OCA\DAV\Db\AbsenceMapper::findByUserId cannot be null, possibly null value provided
$this->initialState->provideInitialState('absence', $absence);
} catch (DoesNotExistException) {
// The user has not yet set up an absence period.
// Logging this error is not necessary.
} catch (\OCP\DB\Exception $e) {
$this->logger->error("Could not find absence data for user $this->userId: " . $e->getMessage(), [
'exception' => $e,
]);
}
}

return new TemplateResponse(Application::APP_ID, 'settings-personal-availability');
}
Expand Down
160 changes: 160 additions & 0 deletions apps/dav/src/components/AbsenceForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
<!--
- @copyright Copyright (c) 2023 Richard Steinmetz <[email protected]>
-
- @author Richard Steinmetz <[email protected]>
-
- @license AGPL-3.0-or-later
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-->

<template>
<div class="absence">
<div class="absence__dates">
<NcDateTimePickerNative id="absence-first-day"
v-model="firstDay"
:label="$t('dav', 'First day')"
class="absence__dates__picker" />
<NcDateTimePickerNative id="absence-last-day"
v-model="lastDay"
:label="$t('dav', 'Last day (inclusive)')"
class="absence__dates__picker" />
</div>
<NcTextField :value.sync="status" :label="$t('dav', 'Short absence status')" />
<NcTextArea :value.sync="message" :label="$t('dav', 'Long absence Message')" />

<div class="absence__buttons">
<NcButton :disabled="loading || !valid"
type="primary"
@click="saveForm">
{{ $t('dav', 'Save') }}
</NcButton>
<NcButton :disabled="loading || !valid"
type="error"
@click="clearAbsence">
{{ $t('dav', 'Disable absence') }}
</NcButton>
</div>
</div>
</template>

<script>
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
import NcTextField from '@nextcloud/vue/dist/Components/NcTextField.js'
import NcTextArea from '@nextcloud/vue/dist/Components/NcTextArea.js'
import NcDateTimePickerNative from '@nextcloud/vue/dist/Components/NcDateTimePickerNative.js'
import { generateUrl } from '@nextcloud/router'
import axios from '@nextcloud/axios'
import { formatDateAsYMD } from '../utils/date.js'
import { loadState } from '@nextcloud/initial-state'
import { showError } from '@nextcloud/dialogs'
export default {
name: 'AbsenceForm',
components: {
NcButton,
NcTextField,
NcTextArea,
NcDateTimePickerNative,
},
data() {
const { firstDay, lastDay, status, message } = loadState('dav', 'absence', {})
return {
loading: false,
status: status ?? '',
message: message ?? '',
firstDay: firstDay ? new Date(firstDay) : new Date(),
lastDay: lastDay ? new Date(lastDay) : null,
}
},
computed: {
/**
* @return {boolean}
*/
valid() {
return !!this.firstDay
&& !!this.lastDay
&& !!this.status
&& this.lastDay > this.firstDay
},
},
methods: {
resetForm() {
this.status = ''
this.message = ''
this.firstDay = new Date()
this.lastDay = null
},
async saveForm() {
if (!this.valid) {
return
}
this.loading = true
try {
await axios.post(generateUrl('/apps/dav/settings/absence'), {
firstDay: formatDateAsYMD(this.firstDay),
lastDay: formatDateAsYMD(this.lastDay),
status: this.status,
message: this.message,
})
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should show success after this?

} catch (error) {
showError(this.$t('dav', 'Failed to save your absence settings'))
} finally {
this.loading = false
}
},
async clearAbsence() {
this.loading = true
try {
await axios.delete(generateUrl('/apps/dav/settings/absence'))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should show success after this?

this.resetForm()
} catch (error) {
showError(this.$t('dav', 'Failed to clear your absence settings'))
} finally {
this.loading = false
}
},
},
}
</script>
<style lang="scss" scoped>
.absence {
display: flex;
flex-direction: column;
gap: 5px;
&__dates {
display: flex;
gap: 10px;
width: 100%;
&__picker {
flex: 1 auto;
::v-deep .native-datetime-picker--input {
margin-bottom: 0;
}
}
}
&__buttons {
display: flex;
gap: 5px;
}
}
</style>
Loading