Page MenuHomePhabricator

D13608.id32887.diff
No OneTemporary

D13608.id32887.diff

Index: src/__phutil_library_map__.php
===================================================================
--- src/__phutil_library_map__.php
+++ src/__phutil_library_map__.php
@@ -2935,6 +2935,7 @@
'PhabricatorVeryWowEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorVeryWowEnglishTranslation.php',
'PhabricatorViewerDatasource' => 'applications/people/typeahead/PhabricatorViewerDatasource.php',
'PhabricatorWatcherHasObjectEdgeType' => 'applications/transactions/edges/PhabricatorWatcherHasObjectEdgeType.php',
+ 'PhabricatorWeeklyRoutineTriggerClock' => 'infrastructure/daemon/workers/clock/PhabricatorWeeklyRoutineTriggerClock.php',
'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php',
'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php',
'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php',
@@ -6865,6 +6866,7 @@
'PhabricatorVeryWowEnglishTranslation' => 'PhutilTranslation',
'PhabricatorViewerDatasource' => 'PhabricatorTypeaheadDatasource',
'PhabricatorWatcherHasObjectEdgeType' => 'PhabricatorEdgeType',
+ 'PhabricatorWeeklyRoutineTriggerClock' => 'PhabricatorTriggerClock',
'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider',
'PhabricatorWorker' => 'Phobject',
'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask',
Index: src/infrastructure/daemon/workers/clock/PhabricatorWeeklyRoutineTriggerClock.php
===================================================================
--- /dev/null
+++ src/infrastructure/daemon/workers/clock/PhabricatorWeeklyRoutineTriggerClock.php
@@ -0,0 +1,146 @@
+<?php
+
+/**
+ * Triggers a weekly clock at different hours on different days.
+ *
+ * This clock triggers events multiple times on selected days.
+ */
+final class PhabricatorWeeklyRoutineTriggerClock
+ extends PhabricatorTriggerClock {
+
+ private function validateRuleString($rule_string) {
+ $components = explode(' on ', $rule_string);
+ if (count($components) <= 0 || count($components) > 2) {
+ throw new PhutilTypeCheckException(pht(
+ 'Incorrect rule specification "%s"',
+ $rule_string));
+ }
+
+ $time_frame = $this->parseTimeComponent($components[0]);
+ if ($time_frame === null) {
+ throw new PhutilTypeCheckException(pht(
+ 'Invalid time specification "%s"',
+ $components[0]));
+ }
+
+ $days_listed = null;
+ if (count($components) === 2) {
+ // Parse the day.
+ $days = array(
+ 'Sunday', 'Monday', 'Tuesday',
+ 'Wednesday', 'Thursday', 'Friday',
+ 'Saturday',
+ );
+ $day_string = str_replace(' ', '', $components[1]);
+ $days_listed = explode(',', $day_string);
+ foreach ($days_listed as $day) {
+ if (!in_array($components[1], $days)) {
+ throw new PhutilTypeCheckException(pht(
+ 'Invalid day specification "%s"',
+ $day));
+ }
+ }
+ }
+
+ return array(
+ 'time_frame' => $time_frame,
+ 'days_listed' => $days_listed,
+ );
+ }
+
+ public function validateProperties(array $properties) {
+ PhutilTypeSpec::checkMap(
+ $properties,
+ array(
+ 'start' => 'int',
+ 'rules' => 'string',
+ ));
+
+ $rules_string = idx($properties, 'rules');
+ foreach (phutil_split_lines($rules_string) as $rule_string) {
+ $this->validateRuleString($rule_string);
+ }
+ }
+
+ /*
+ * Parses a time component string, returning the number of
+ * seconds since the start of a UTC day.
+ */
+ private function parseTimeComponent($time_string) {
+ $result = date_parse($time_string);
+ if ($result === false || $result['error_count'] > 0) {
+ return null;
+ }
+
+ $hour = idx($result, 'hour', 0);
+ $minute = idx($result, 'minute', 0);
+ $second = idx($result, 'second', 0);
+
+ $total = ($hour * 3600) + ($minute * 60) + $second;
+
+ $zone_adjustment = idx($result, 'tz_id');
+ if ($zone_adjustment !== null) {
+ $origin_dtz = new DateTimeZone('UTC');
+ $remote_dtz = new DateTimeZone($zone_adjustment);
+ $origin_dt = new DateTime('now', $origin_dtz);
+ $remote_dt = new DateTime('now', $remote_dtz);
+ $total += $origin_dtz->getOffset($origin_dt) -
+ $remote_dtz->getOffset($remote_dt);
+ }
+
+ return array(
+ 'seconds' => $total,
+ );
+ }
+
+ public function getNextEventEpoch($last_epoch, $is_reschedule) {
+ $start_epoch = $this->getProperty('start');
+ if (!$last_epoch) {
+ $last_epoch = $start_epoch;
+ }
+
+ $rules_string = $this->getProperty('rules');
+
+ $now = $this->getProperty('start');
+ if ($last_epoch) {
+ $now = $last_epoch;
+ }
+
+ $epochs = array();
+ foreach (phutil_split_lines($rules_string) as $rule_string) {
+ $rule = $this->validateRuleString($rule_string);
+
+ $days_listed = idx($rule, 'days_listed');
+ $seconds_since_midnight = idx(idx($rule, 'time_frame'), 'seconds');
+
+ if ($days_listed === null) {
+ $target = strtotime('midnight', $now) +
+ $seconds_since_midnight;
+
+ if ($target <= $now) {
+ $target = strtotime('midnight tomorrow', $now) +
+ $seconds_since_midnight;
+ }
+ } else {
+ foreach ($days_listed as $day) {
+ $target = strtotime('midnight '.$day, $now) +
+ $seconds_since_midnight;
+
+ if ($target <= $now) {
+ $target = strtotime('midnight next '.$day, $now) +
+ $seconds_since_midnight;
+ }
+ }
+ }
+
+ if ($target > $now) {
+ $epochs[] = $target;
+ }
+ }
+
+ sort($epochs);
+
+ return head($epochs);
+ }
+
+}

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 1, 1:18 PM (20 h, 37 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
17377604
Default Alt Text
D13608.id32887.diff (5 KB)

Event Timeline