Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1ba022c0 authored by Anna Larch's avatar Anna Larch
Browse files

parent fe5b94d2

author Anna Larch <anna@nextcloud.com> 1635937467 +0100
committer Anna Larch <anna@nextcloud.com> 1637263905 +0100

parent fe5b94d2
author Anna Larch <anna@nextcloud.com> 1635937467 +0100
committer Anna Larch <anna@nextcloud.com> 1637263843 +0100

Add booking mechanism
parent fe5b94d2
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -15,7 +15,7 @@
* ☑️ Tasks! See tasks with a due date directly in the calendar
* 🙈 **We’re not reinventing the wheel!** Based on the great [c-dav library](https://github.com/nextcloud/cdav-library), [ical.js](https://github.com/mozilla-comm/ical.js) and [fullcalendar](https://github.com/fullcalendar/fullcalendar) libraries.
	]]></description>
	<version>2.4.0-RC.1</version>
	<version>3.0.0-alpha.1</version>
	<licence>agpl</licence>
	<author homepage="https://georg.coffee">Georg Ehrke</author>
	<author homepage="https://tcit.fr">Thomas Citharel</author>
@@ -36,6 +36,9 @@
	<dependencies>
		<nextcloud min-version="20" max-version="24" />
	</dependencies>
	<background-jobs>
		<job>OCA\Calendar\BackgroundJob\CleanupJob</job>
	</background-jobs>
	<repair-steps>
		<post-migration>
			<step>OCA\Calendar\RepairSteps\CurrentViewNameRepairStep</step>
+1 −0
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ return [
		['name' => 'appointment#show', 'url' => '/appointment/{token}', 'verb' => 'GET'],
		['name' => 'booking#getBookableSlots', 'url' => '/appointment/{appointmentConfigId}/slots', 'verb' => 'GET'],
		['name' => 'booking#bookSlot', 'url' => '/appointment/{appointmentConfigId}/book', 'verb' => 'POST'],
		['name' => 'booking#confirmBooking', 'url' => '/appointment/confirm/{token}', 'verb' => 'GET'],
		// Public views
		['name' => 'publicView#public_index_with_branding', 'url' => '/p/{token}', 'verb' => 'GET'],
		['name' => 'publicView#public_index_with_branding', 'url' => '/p/{token}/{view}/{timeRange}', 'verb' => 'GET', 'postfix' => 'publicview.timerange'],
+56 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

/**
 * Calendar App
 *
@@ -22,49 +23,34 @@ declare(strict_types=1);
 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
namespace OCA\Calendar\Service\Appointments;

use ChristophWurst\Nextcloud\Testing\TestCase;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\AppFramework\Bootstrap\RegistrationContext;
use OC\AppFramework\Bootstrap\ServiceRegistration;
use OC\Calendar\Manager;
use OCA\DAV\CalDAV\CalDavBackend;
use OCA\DAV\CalDAV\CalendarProvider;
use OCA\Calendar\Db\AppointmentConfigMapper;
use OCP\IConfig;
use OCP\IL10N;
use PHPUnit\Framework\MockObject\MockObject;
use Psr\Log\LoggerInterface;
namespace OCA\Calendar\BackgroundJob;

class BookingServiceTest extends TestCase {
use OCA\Calendar\Service\Appointments\BookingService;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\BackgroundJob\TimedJob;
use OCP\ILogger;
use Psr\Log\LoggerInterface;

	/** @var AppointmentConfigMapper|MockObject  */
	private $mapper;
class CleanUpJob extends TimedJob {
	/** @var ILogger */
	private $logger;

	/** @var BookingService */
	private $service;

	/** @var mixed|Manager|MockObject */
	private $manager;
	public function __construct(ITimeFactory $time,
								BookingService $service,
								LoggerInterface $logger) {
		parent::__construct($time);
		$this->setInterval(24*60*60);
		$this->service = $service;
		$this->logger = $logger;
	}


	protected function setUp(): void {
		parent::setUp();
		$backend = \OC::$server->get(CalDavBackend::class);
		$container = \OC::$server->get(\Psr\Container\ContainerInterface::class);
		$l10n = $this->createMock(IL10N::class);
		$conf = $this->createMock(IConfig::class);
		$logger = $this->createMock(LoggerInterface::class);
		$coordinator = $this->createConfiguredMock(Coordinator::class, [
			'getRegistrationContext' => $this->createConfiguredMock(RegistrationContext::class, [
				'getCalendarProviders' => [ new ServiceRegistration('calendar', CalendarProvider::class) ]
			])
		]);
		$this->manager = new Manager($coordinator, $container, $logger);
		$this->mapper = $this->createMock(AppointmentConfigMapper::class);
		$this->service = new BookingService(
			$this->manager,
			$this->mapper
		);
	protected function run($argument): void {
		$outdated = $this->service->deleteOutdated();
		$this->logger->info('Found and deleted ' . $outdated . ' outdated booking confirmations.');
	}
}
+23 −6
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ use OCA\Calendar\Service\Appointments\AppointmentConfigService;
use OCP\AppFramework\Controller;
use OCP\AppFramework\Http;
use OCP\IRequest;
use Psr\Log\LoggerInterface;

class AppointmentConfigController extends Controller {

@@ -42,13 +43,18 @@ class AppointmentConfigController extends Controller {
	/** @var string|null */
	private $userId;

	/** @var LoggerInterface */
	private $logger;

	public function __construct(string $appName,
								IRequest $request,
								AppointmentConfigService $appointmentService,
								LoggerInterface $logger,
								?string $userId) {
		parent::__construct($appName, $request);
		$this->appointmentConfigService = $appointmentService;
		$this->userId = $userId;
		$this->logger = $logger;
	}

	/**
@@ -56,12 +62,17 @@ class AppointmentConfigController extends Controller {
	 */
	public function index(): JsonResponse {
		if ($this->userId === null) {
			$this->logger->warning('User not found');
			return JsonResponse::fail(null, Http::STATUS_NOT_FOUND);
		}

		return JsonResponse::success(
			$this->appointmentConfigService->getAllAppointmentConfigurations($this->userId)
		);
		try {
			$appointmentConfigs = $this->appointmentConfigService->getAllAppointmentConfigurations($this->userId);
			return JsonResponse::success($appointmentConfigs);
		} catch (ServiceException $e) {
			$this->logger->error('No appointment configurations found', ['exception' => $e]);
			return JsonResponse::fail([], $e->getHttpCode() ?? Http::STATUS_BAD_REQUEST);
		}
	}

	/**
@@ -71,6 +82,7 @@ class AppointmentConfigController extends Controller {
	 */
	public function show(int $id): JsonResponse {
		if ($this->userId === null) {
			$this->logger->warning('User not found');
			return JsonResponse::fail();
		}

@@ -78,9 +90,8 @@ class AppointmentConfigController extends Controller {
			$appointmentConfig = $this->appointmentConfigService->findByIdAndUser($id, $this->userId);
			return JsonResponse::success($appointmentConfig);
		} catch (ClientException $e) {
			$this->logger->warning('No appointment configuration found with id ' . $id, ['exception' => $e]);
			return JsonResponse::fail([], $e->getHttpCode() ?? Http::STATUS_BAD_REQUEST);
		} catch (ServiceException $e) {
			return JsonResponse::errorFromThrowable($e);
		}
	}

@@ -145,6 +156,7 @@ class AppointmentConfigController extends Controller {
			);
			return JsonResponse::success($appointmentConfig);
		} catch (ServiceException $e) {
			$this->logger->error('Could not create new configuration', ['exception' => $e]);
			return JsonResponse::errorFromThrowable($e);
		}
	}
@@ -193,7 +205,8 @@ class AppointmentConfigController extends Controller {

		try {
			$appointmentConfig = $this->appointmentConfigService->findByIdAndUser($id, $this->userId);
		} catch (ServiceException $e) {
		} catch (ClientException $e) {
			$this->logger->error('Could not find configuration with id ' . $id, ['exception' => $e]);
			return JsonResponse::errorFromThrowable($e);
		}

@@ -218,6 +231,7 @@ class AppointmentConfigController extends Controller {
			$appointmentConfig = $this->appointmentConfigService->update($appointmentConfig);
			return JsonResponse::success($appointmentConfig);
		} catch (ServiceException $e) {
			$this->logger->error('Could not update configuration with id ' . $id, ['exception' => $e]);
			return JsonResponse::errorFromThrowable($e, 403);
		}
	}
@@ -227,13 +241,16 @@ class AppointmentConfigController extends Controller {
	 */
	public function destroy(int $id): JsonResponse {
		if ($this->userId === null) {
			$this->logger->warning('User not found');
			return JsonResponse::fail(null, Http::STATUS_NOT_FOUND);
		}

		try {
			// delete all outstanding bookings
			$this->appointmentConfigService->delete($id, $this->userId);
			return JsonResponse::success();
		} catch (ServiceException $e) {
			$this->logger->error('Could not delete configuration with id ' . $id, ['exception' => $e]);
			return JsonResponse::errorFromThrowable($e, 403);
		}
	}
+3 −2
Original line number Diff line number Diff line
@@ -58,7 +58,8 @@ class AppointmentController extends Controller {
								IUserManager $userManager,
								AppointmentConfigService $configService,
								IInitialState $initialState,
								?string $userId) {
								?string $userId
								) {
		parent::__construct(Application::APP_ID, $request);

		$this->userManager = $userManager;
@@ -94,7 +95,7 @@ class AppointmentController extends Controller {
		);
		$this->initialState->provideInitialState(
			'appointmentConfigs',
			array_filter($this->configService->getAllAppointmentConfigurations($userId), function (AppointmentConfig $config): bool {
			array_filter($this->configService->getAllAppointmentConfigurations($userId), static function (AppointmentConfig $config): bool {
				return $config->getVisibility() === AppointmentConfig::VISIBILITY_PUBLIC;
			}),
		);
Loading