2 Commits

Author SHA1 Message Date
jared 6e1ae01cac Fix recurring ticket schedule edge cases in API and model
- manage_recurring.php calculateNextRun(): expand monthly cap from 28→31
  with proper last-day-of-month clamping (matches model fix); use split
  with ':00' append to handle malformed time strings without crashing;
  fix weekly day array to start at index 1 (not 0) so day=0 never maps
  to empty string and blows up DateTime
- RecurringTicketModel::calculateNextRunTime(): same weekly day array fix
  (start at index 1) to eliminate '' → DateTime exception on day=0

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:16:41 -04:00
jared c3ab5c5716 Fix double URL-encoding of Matrix user ID in SynapseHelper
rawurlencode($username) was called on line 38 (encoding the username),
then rawurlencode($matrixId) was called on line 39 encoding the already-
encoded string — causing %20 to become %2520 for usernames with special
characters. Fixed by building $matrixId with the plain username and only
encoding the full Matrix ID once in the URL path.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-05 18:12:02 -04:00
3 changed files with 15 additions and 8 deletions
+9 -6
View File
@@ -147,18 +147,21 @@ function calculateNextRun($scheduleType, $scheduleDay, $scheduleTime) {
break;
case 'weekly':
$days = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
$dayName = $days[$scheduleDay] ?? 'Monday';
$days = [1 => 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
$dayName = $days[(int)$scheduleDay] ?? 'Monday';
$next = new DateTime("next {$dayName} " . $time);
break;
case 'monthly':
$day = max(1, min(28, (int)$scheduleDay));
$day = max(1, min(31, (int)$scheduleDay));
$next = new DateTime();
$next->modify('first day of next month');
$next->setDate($next->format('Y'), $next->format('m'), $day);
list($h, $m) = explode(':', $time);
$next->setTime((int)$h, (int)$m, 0);
// Clamp to last day of target month (handles Feb, 30-day months)
$daysInMonth = (int)$next->format('t');
$day = min($day, $daysInMonth);
$next->setDate((int)$next->format('Y'), (int)$next->format('m'), $day);
$parts = explode(':', $time . ':00'); // ensure at least H:M
$next->setTime((int)$parts[0], (int)$parts[1], 0);
break;
default:
+4 -1
View File
@@ -35,7 +35,10 @@ class SynapseHelper {
return null;
}
$matrixId = '@' . rawurlencode($username) . ':' . $domain;
// Build the Matrix user ID and percent-encode it once for the URL path.
// rawurlencode($username) here would double-encode any special chars when
// the full $matrixId string is encoded again below.
$matrixId = '@' . $username . ':' . $domain;
$url = rtrim($baseUrl, '/') . '/_synapse/admin/v2/users/' . rawurlencode($matrixId);
$ch = curl_init($url);
+2 -1
View File
@@ -176,7 +176,8 @@ class RecurringTicketModel {
break;
case 'weekly':
$dayName = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][$scheduleDay] ?? 'Monday';
$dayNames = [1 => 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
$dayName = $dayNames[(int)$scheduleDay] ?? 'Monday';
$next = new DateTime("next {$dayName} " . $scheduleTime);
break;