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; break;
case 'weekly': case 'weekly':
$days = ['', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; $days = [1 => 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
$dayName = $days[$scheduleDay] ?? 'Monday'; $dayName = $days[(int)$scheduleDay] ?? 'Monday';
$next = new DateTime("next {$dayName} " . $time); $next = new DateTime("next {$dayName} " . $time);
break; break;
case 'monthly': case 'monthly':
$day = max(1, min(28, (int)$scheduleDay)); $day = max(1, min(31, (int)$scheduleDay));
$next = new DateTime(); $next = new DateTime();
$next->modify('first day of next month'); $next->modify('first day of next month');
$next->setDate($next->format('Y'), $next->format('m'), $day); // Clamp to last day of target month (handles Feb, 30-day months)
list($h, $m) = explode(':', $time); $daysInMonth = (int)$next->format('t');
$next->setTime((int)$h, (int)$m, 0); $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; break;
default: default:
+4 -1
View File
@@ -35,7 +35,10 @@ class SynapseHelper {
return null; 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); $url = rtrim($baseUrl, '/') . '/_synapse/admin/v2/users/' . rawurlencode($matrixId);
$ch = curl_init($url); $ch = curl_init($url);
+2 -1
View File
@@ -176,7 +176,8 @@ class RecurringTicketModel {
break; break;
case 'weekly': 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); $next = new DateTime("next {$dayName} " . $scheduleTime);
break; break;