Passed
Push — master ( ba9758...3eda05 )
by Joas
16:56 queued 13s
created
apps/dav/lib/BackgroundJob/UserStatusAutomation.php 1 patch
Indentation   +146 added lines, -146 removed lines patch added patch discarded remove patch
@@ -39,150 +39,150 @@
 block discarded – undo
39 39
 use Sabre\VObject\Recur\RRuleIterator;
40 40
 
41 41
 class UserStatusAutomation extends TimedJob {
42
-	protected IDBConnection $connection;
43
-	protected IJobList $jobList;
44
-	protected LoggerInterface $logger;
45
-	protected IManager $manager;
46
-	protected IConfig $config;
47
-
48
-	public function __construct(ITimeFactory $timeFactory,
49
-								IDBConnection $connection,
50
-								IJobList $jobList,
51
-								LoggerInterface $logger,
52
-								IManager $manager,
53
-								IConfig $config) {
54
-		parent::__construct($timeFactory);
55
-		$this->connection = $connection;
56
-		$this->jobList = $jobList;
57
-		$this->logger = $logger;
58
-		$this->manager = $manager;
59
-		$this->config = $config;
60
-
61
-		// Interval 0 might look weird, but the last_checked is always moved
62
-		// to the next time we need this and then it's 0 seconds ago.
63
-		$this->setInterval(0);
64
-	}
65
-
66
-	/**
67
-	 * @inheritDoc
68
-	 */
69
-	protected function run($argument) {
70
-		if (!isset($argument['userId'])) {
71
-			$this->jobList->remove(self::class, $argument);
72
-			$this->logger->info('Removing invalid ' . self::class . ' background job');
73
-			return;
74
-		}
75
-
76
-		$userId = $argument['userId'];
77
-		$automationEnabled = $this->config->getUserValue($userId, 'dav', 'user_status_automation', 'no') === 'yes';
78
-		if (!$automationEnabled) {
79
-			$this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the setting is disabled');
80
-			$this->jobList->remove(self::class, $argument);
81
-			return;
82
-		}
83
-
84
-		$property = $this->getAvailabilityFromPropertiesTable($userId);
85
-
86
-		if (!$property) {
87
-			$this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the user has no availability settings');
88
-			$this->jobList->remove(self::class, $argument);
89
-			return;
90
-		}
91
-
92
-		$isCurrentlyAvailable = false;
93
-		$nextPotentialToggles = [];
94
-
95
-		$now = new \DateTime('now');
96
-		$lastMidnight = (clone $now)->setTime(0, 0);
97
-
98
-		$vObject = Reader::read($property);
99
-		foreach ($vObject->getComponents() as $component) {
100
-			if ($component->name !== 'VAVAILABILITY') {
101
-				continue;
102
-			}
103
-			/** @var VAvailability $component */
104
-			$availables = $component->getComponents();
105
-			foreach ($availables as $available) {
106
-				/** @var Available $available */
107
-				if ($available->name === 'AVAILABLE') {
108
-					/** @var \DateTimeInterface $effectiveStart */
109
-					/** @var \DateTimeInterface $effectiveEnd */
110
-					[$effectiveStart, $effectiveEnd] = $available->getEffectiveStartEnd();
111
-
112
-					try {
113
-						$it = new RRuleIterator((string) $available->RRULE, $effectiveStart);
114
-						$it->fastForward($lastMidnight);
115
-
116
-						$startToday = $it->current();
117
-						if ($startToday && $startToday <= $now) {
118
-							$duration = $effectiveStart->diff($effectiveEnd);
119
-							$endToday = $startToday->add($duration);
120
-							if ($endToday > $now) {
121
-								// User is currently available
122
-								// Also queuing the end time as next status toggle
123
-								$isCurrentlyAvailable = true;
124
-								$nextPotentialToggles[] = $endToday->getTimestamp();
125
-							}
126
-
127
-							// Availability enabling already done for today,
128
-							// so jump to the next recurrence to find the next status toggle
129
-							$it->next();
130
-						}
131
-
132
-						if ($it->current()) {
133
-							$nextPotentialToggles[] = $it->current()->getTimestamp();
134
-						}
135
-					} catch (\Exception $e) {
136
-						$this->logger->error($e->getMessage(), ['exception' => $e]);
137
-					}
138
-				}
139
-			}
140
-		}
141
-
142
-		$nextAutomaticToggle = min($nextPotentialToggles);
143
-		$this->setLastRunToNextToggleTime($userId, $nextAutomaticToggle - 1);
144
-
145
-		if ($isCurrentlyAvailable) {
146
-			$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
147
-		} else {
148
-			// The DND status automation is more important than the "Away - In call" so we also restore that one if it exists.
149
-			$this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_CALL, IUserStatus::AWAY);
150
-			$this->manager->setUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND, true);
151
-		}
152
-		$this->logger->debug('User status automation ran');
153
-	}
154
-
155
-	protected function setLastRunToNextToggleTime(string $userId, int $timestamp): void {
156
-		$query = $this->connection->getQueryBuilder();
157
-
158
-		$query->update('jobs')
159
-			->set('last_run', $query->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT))
160
-			->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
161
-		$query->executeStatement();
162
-
163
-		$this->logger->debug('Updated user status automation last_run to ' . $timestamp . ' for user ' . $userId);
164
-	}
165
-
166
-	/**
167
-	 * @param string $userId
168
-	 * @return false|string
169
-	 */
170
-	protected function getAvailabilityFromPropertiesTable(string $userId) {
171
-		$propertyPath = 'calendars/' . $userId . '/inbox';
172
-		$propertyName = '{' . Plugin::NS_CALDAV . '}calendar-availability';
173
-
174
-		$query = $this->connection->getQueryBuilder();
175
-		$query->select('propertyvalue')
176
-			->from('properties')
177
-			->where($query->expr()->eq('userid', $query->createNamedParameter($userId)))
178
-			->andWhere($query->expr()->eq('propertypath', $query->createNamedParameter($propertyPath)))
179
-			->andWhere($query->expr()->eq('propertyname', $query->createNamedParameter($propertyName)))
180
-			->setMaxResults(1);
181
-
182
-		$result = $query->executeQuery();
183
-		$property = $result->fetchOne();
184
-		$result->closeCursor();
185
-
186
-		return $property;
187
-	}
42
+    protected IDBConnection $connection;
43
+    protected IJobList $jobList;
44
+    protected LoggerInterface $logger;
45
+    protected IManager $manager;
46
+    protected IConfig $config;
47
+
48
+    public function __construct(ITimeFactory $timeFactory,
49
+                                IDBConnection $connection,
50
+                                IJobList $jobList,
51
+                                LoggerInterface $logger,
52
+                                IManager $manager,
53
+                                IConfig $config) {
54
+        parent::__construct($timeFactory);
55
+        $this->connection = $connection;
56
+        $this->jobList = $jobList;
57
+        $this->logger = $logger;
58
+        $this->manager = $manager;
59
+        $this->config = $config;
60
+
61
+        // Interval 0 might look weird, but the last_checked is always moved
62
+        // to the next time we need this and then it's 0 seconds ago.
63
+        $this->setInterval(0);
64
+    }
65
+
66
+    /**
67
+     * @inheritDoc
68
+     */
69
+    protected function run($argument) {
70
+        if (!isset($argument['userId'])) {
71
+            $this->jobList->remove(self::class, $argument);
72
+            $this->logger->info('Removing invalid ' . self::class . ' background job');
73
+            return;
74
+        }
75
+
76
+        $userId = $argument['userId'];
77
+        $automationEnabled = $this->config->getUserValue($userId, 'dav', 'user_status_automation', 'no') === 'yes';
78
+        if (!$automationEnabled) {
79
+            $this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the setting is disabled');
80
+            $this->jobList->remove(self::class, $argument);
81
+            return;
82
+        }
83
+
84
+        $property = $this->getAvailabilityFromPropertiesTable($userId);
85
+
86
+        if (!$property) {
87
+            $this->logger->info('Removing ' . self::class . ' background job for user "' . $userId . '" because the user has no availability settings');
88
+            $this->jobList->remove(self::class, $argument);
89
+            return;
90
+        }
91
+
92
+        $isCurrentlyAvailable = false;
93
+        $nextPotentialToggles = [];
94
+
95
+        $now = new \DateTime('now');
96
+        $lastMidnight = (clone $now)->setTime(0, 0);
97
+
98
+        $vObject = Reader::read($property);
99
+        foreach ($vObject->getComponents() as $component) {
100
+            if ($component->name !== 'VAVAILABILITY') {
101
+                continue;
102
+            }
103
+            /** @var VAvailability $component */
104
+            $availables = $component->getComponents();
105
+            foreach ($availables as $available) {
106
+                /** @var Available $available */
107
+                if ($available->name === 'AVAILABLE') {
108
+                    /** @var \DateTimeInterface $effectiveStart */
109
+                    /** @var \DateTimeInterface $effectiveEnd */
110
+                    [$effectiveStart, $effectiveEnd] = $available->getEffectiveStartEnd();
111
+
112
+                    try {
113
+                        $it = new RRuleIterator((string) $available->RRULE, $effectiveStart);
114
+                        $it->fastForward($lastMidnight);
115
+
116
+                        $startToday = $it->current();
117
+                        if ($startToday && $startToday <= $now) {
118
+                            $duration = $effectiveStart->diff($effectiveEnd);
119
+                            $endToday = $startToday->add($duration);
120
+                            if ($endToday > $now) {
121
+                                // User is currently available
122
+                                // Also queuing the end time as next status toggle
123
+                                $isCurrentlyAvailable = true;
124
+                                $nextPotentialToggles[] = $endToday->getTimestamp();
125
+                            }
126
+
127
+                            // Availability enabling already done for today,
128
+                            // so jump to the next recurrence to find the next status toggle
129
+                            $it->next();
130
+                        }
131
+
132
+                        if ($it->current()) {
133
+                            $nextPotentialToggles[] = $it->current()->getTimestamp();
134
+                        }
135
+                    } catch (\Exception $e) {
136
+                        $this->logger->error($e->getMessage(), ['exception' => $e]);
137
+                    }
138
+                }
139
+            }
140
+        }
141
+
142
+        $nextAutomaticToggle = min($nextPotentialToggles);
143
+        $this->setLastRunToNextToggleTime($userId, $nextAutomaticToggle - 1);
144
+
145
+        if ($isCurrentlyAvailable) {
146
+            $this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND);
147
+        } else {
148
+            // The DND status automation is more important than the "Away - In call" so we also restore that one if it exists.
149
+            $this->manager->revertUserStatus($userId, IUserStatus::MESSAGE_CALL, IUserStatus::AWAY);
150
+            $this->manager->setUserStatus($userId, IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::DND, true);
151
+        }
152
+        $this->logger->debug('User status automation ran');
153
+    }
154
+
155
+    protected function setLastRunToNextToggleTime(string $userId, int $timestamp): void {
156
+        $query = $this->connection->getQueryBuilder();
157
+
158
+        $query->update('jobs')
159
+            ->set('last_run', $query->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT))
160
+            ->where($query->expr()->eq('id', $query->createNamedParameter($this->getId(), IQueryBuilder::PARAM_INT)));
161
+        $query->executeStatement();
162
+
163
+        $this->logger->debug('Updated user status automation last_run to ' . $timestamp . ' for user ' . $userId);
164
+    }
165
+
166
+    /**
167
+     * @param string $userId
168
+     * @return false|string
169
+     */
170
+    protected function getAvailabilityFromPropertiesTable(string $userId) {
171
+        $propertyPath = 'calendars/' . $userId . '/inbox';
172
+        $propertyName = '{' . Plugin::NS_CALDAV . '}calendar-availability';
173
+
174
+        $query = $this->connection->getQueryBuilder();
175
+        $query->select('propertyvalue')
176
+            ->from('properties')
177
+            ->where($query->expr()->eq('userid', $query->createNamedParameter($userId)))
178
+            ->andWhere($query->expr()->eq('propertypath', $query->createNamedParameter($propertyPath)))
179
+            ->andWhere($query->expr()->eq('propertyname', $query->createNamedParameter($propertyName)))
180
+            ->setMaxResults(1);
181
+
182
+        $result = $query->executeQuery();
183
+        $property = $result->fetchOne();
184
+        $result->closeCursor();
185
+
186
+        return $property;
187
+    }
188 188
 }
Please login to merge, or discard this patch.