diff --git a/appinfo/info.xml b/appinfo/info.xml
index a695b9fabd50f7d579fbeb089f13f6422598d363..44ce9959d2672d24f9f69d91206f512c58a04a06 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -27,4 +27,9 @@
OCA\EcloudAccounts\Command\Migrate2FASecrets
+
+
+ OCA\EcloudAccounts\Migration\CreateTasksCalendar
+
+
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 3574f538feb8edcd24943bce57dfec8f9d867f8c..47f82a4cad9ebf090114962503e390a6aaf700f5 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -26,20 +26,29 @@ declare(strict_types=1);
namespace OCA\EcloudAccounts\AppInfo;
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCA\EcloudAccounts\Listeners\BeforeTemplateRenderedListener;
+use OCA\EcloudAccounts\Listeners\BeforeUserDeletedListener;
+use OCA\EcloudAccounts\Listeners\UserChangedListener;
+use OCA\EcloudAccounts\Service\LDAPConnectionService;
use OCP\AppFramework\App;
+use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
-use OCP\AppFramework\Bootstrap\IBootContext;
-use OCA\EcloudAccounts\Listeners\BeforeUserDeletedListener;
-use OCA\EcloudAccounts\Service\LDAPConnectionService;
+use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
+use OCP\Defaults;
+use OCP\IDBConnection;
+use OCP\IUser;
use OCP\User\Events\BeforeUserDeletedEvent;
use OCP\User\Events\UserChangedEvent;
-use OCA\EcloudAccounts\Listeners\UserChangedListener;
-use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent;
-use OCA\EcloudAccounts\Listeners\BeforeTemplateRenderedListener;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
class Application extends App implements IBootstrap {
public const APP_ID = 'ecloud-accounts';
+ public const TASKS_CALENDAR_URI = 'tasks';
+ public const TASKS_CALENDAR_NAME = 'Tasks';
+ public const TASKS_CALENDAR_COMPONENT = 'VTODO';
public function __construct(array $urlParams = []) {
parent::__construct(self::APP_ID, $urlParams);
@@ -52,9 +61,38 @@ class Application extends App implements IBootstrap {
}
public function boot(IBootContext $context): void {
+ $context->injectFn([$this, 'createTasksCalendar']);
$serverContainer = $context->getServerContainer();
$serverContainer->registerService('LDAPConnectionService', function ($c) {
return new LDAPConnectionService();
});
}
+
+ public function createTasksCalendar(CalDavBackend $calDav, IDBConnection $db, Defaults $themingDefaults, EventDispatcherInterface $dispatcher): void {
+ $dispatcher->addListener(IUser::class . '::firstLogin', function (GenericEvent $event) use ($calDav, $themingDefaults, $db) {
+ $user = $event->getSubject();
+ if (!$user instanceof IUser) {
+ return;
+ }
+ $userId = $user->getUID();
+ $principal = 'principals/users/' . $userId;
+ $calendar = $calDav->getCalendarByUri($principal, self::TASKS_CALENDAR_URI);
+ $query = $db->getQueryBuilder();
+ $query->select('uri')->from('calendars')
+ ->where($query->expr()->eq('uri', $query->createNamedParameter(self::TASKS_CALENDAR_URI)))
+ ->andWhere($query->expr()->eq('principaluri', $query->createNamedParameter($principal)))
+ ->andWhere($query->expr()->eq('components', $query->createNamedParameter(self::TASKS_CALENDAR_COMPONENT)))
+ ->setMaxResults(1);
+ $stmt = $query->executeQuery();
+ $row = $stmt->fetch();
+ $stmt->closeCursor();
+ if ($row === false) {
+ $calDav->createCalendar($principal, self::TASKS_CALENDAR_URI, [
+ '{DAV:}displayname' => self::TASKS_CALENDAR_NAME,
+ '{http://apple.com/ns/ical/}calendar-color' => $themingDefaults->getColorPrimary(),
+ 'components' => self::TASKS_CALENDAR_COMPONENT
+ ]);
+ }
+ });
+ }
}
diff --git a/lib/Migration/CreateTasksCalendar.php b/lib/Migration/CreateTasksCalendar.php
new file mode 100644
index 0000000000000000000000000000000000000000..b7b8f24d722af45b0f27e50e10e6b800128a2904
--- /dev/null
+++ b/lib/Migration/CreateTasksCalendar.php
@@ -0,0 +1,153 @@
+
+ *
+ * @author Joas Schilling
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+namespace OCA\EcloudAccounts\Migration;
+
+use OCA\DAV\CalDAV\CalDavBackend;
+use OCP\Defaults;
+use OCP\IConfig;
+use OCP\IDBConnection;
+use OCP\IUserManager;
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+
+/**
+ * Class CreateTasksCalendar
+ *
+ * @package OCA\EcloudAccounts\Migration
+ */
+class CreateTasksCalendar implements IRepairStep {
+ public const APP_ID = 'ecloud-accounts';
+ public const TASKS_CALENDAR_URI = 'tasks';
+ public const TASKS_CALENDAR_NAME = 'Tasks';
+ public const TASKS_CALENDAR_COMPONENT = 'VTODO';
+
+ /** @var IDBConnection */
+ protected $connection;
+
+ /** @var IConfig */
+ protected $config;
+
+ /** @var IUserManager */
+ private $userManager;
+
+ /** @var CalDavBackend */
+ protected $calDav;
+
+ /** @var Defaults */
+ protected $themingDefaults;
+
+
+ public function __construct(IDBConnection $connection, IConfig $config, IUserManager $userManager, CalDavBackend $calDav, Defaults $themingDefaults) {
+ $this->connection = $connection;
+ $this->config = $config;
+ $this->userManager = $userManager;
+ $this->calDav = $calDav;
+ $this->themingDefaults = $themingDefaults;
+ }
+
+ /**
+ * Returns the step's name
+ *
+ * @return string
+ * @since 9.1.0
+ */
+ public function getName() {
+ return 'Fix by creating Tasks calendar for user if not exist.';
+ }
+
+ /**
+ * Returns the array of calendars
+ *
+ * @return array
+ */
+ private function getPrincipalUriByCalendar():array {
+ $query = $this->connection->getQueryBuilder();
+ $expr = $query->expr();
+ $query->select($query->createFunction('DISTINCT ' . $query->getColumnName('c1.principaluri')))
+ ->from('calendars', 'c1')
+ ->leftJoin('c1', 'calendars', 'c2', $expr->andX(
+ $expr->eq('c1.principaluri', 'c2.principaluri'),
+ $expr->eq('c2.uri', $query->createNamedParameter('tasks')),
+ $expr->eq('c2.components', $query->createNamedParameter('VTODO'))
+ )
+ )
+ ->where($query->expr()->isNull('c2.principaluri'));
+ $stmt = $query->executeQuery();
+ return $stmt->fetchAll();
+ }
+
+ /**
+ * Returns the unique Task Uri
+ *
+ * @return string
+ */
+ private function getUniqueTaskUri($principal, $taskUri):string {
+ $qb = $this->connection->getQueryBuilder();
+ $qb->select('uri')
+ ->from('calendars')
+ ->where($qb->expr()->eq('uri', $qb->createNamedParameter($taskUri)))
+ ->andWhere($qb->expr()->eq('principaluri', $qb->createNamedParameter($principal)));
+ $count = $qb->execute()->fetchColumn();
+
+ // If the name already exists, add a suffix until you find an available task uri
+ if ($count > 0) {
+ $i = 1;
+ while ($count > 0) {
+ $newUriName = $taskUri . '-' . $i;
+ $qb->select('uri');
+ $qb->where($qb->expr()->eq('uri', $qb->createNamedParameter($newUriName)));
+ $qb->andWhere($qb->expr()->eq('principaluri', $qb->createNamedParameter($principal)));
+ $count = $qb->execute()->fetchColumn();
+ $i++;
+ }
+ $taskUri = $newUriName;
+ }
+ return $taskUri;
+ }
+
+
+
+ /**
+ * @param IOutput $output
+ */
+ public function run(IOutput $output) {
+ if ($this->config->getAppValue(self::APP_ID, 'CreateTasksHasRun') === 'yes') {
+ $output->info('Repair step already executed');
+ return;
+ }
+ //get all principal uri having no task calendar with component as TODO but have personal calendar
+ $result = $this->getPrincipalUriByCalendar();
+ foreach ($result as $row) {
+ $principal = $row['principaluri'];
+ $taskUri = $this->getUniqueTaskUri($principal, self::TASKS_CALENDAR_URI);
+ $this->calDav->createCalendar($principal, $taskUri, [
+ '{DAV:}displayname' => self::TASKS_CALENDAR_NAME,
+ '{http://apple.com/ns/ical/}calendar-color' => $this->themingDefaults->getColorPrimary(),
+ 'components' => 'VTODO'
+ ]);
+ };
+ // if everything is done, no need to redo the repair during next upgrade
+ $this->config->setAppValue(self::APP_ID, 'CreateTasksHasRun', 'yes');
+ }
+}