Merge pull request 'fix(schedule): limit to 24 hours ahead with a clear message (#275)' (#433) from fix/schedule-24h into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s
This commit was merged in pull request #433.
This commit is contained in:
@@ -20,7 +20,12 @@ import { IContent } from 'matrix-js-sdk';
|
|||||||
import { useTimestampFormatter } from '../../hooks/useTimestampFormatter';
|
import { useTimestampFormatter } from '../../hooks/useTimestampFormatter';
|
||||||
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
import { useMatrixClient } from '../../hooks/useMatrixClient';
|
||||||
import { stopPropagation } from '../../utils/keyboard';
|
import { stopPropagation } from '../../utils/keyboard';
|
||||||
import { scheduleMessage } from '../../utils/scheduledMessages';
|
import {
|
||||||
|
describeScheduleError,
|
||||||
|
MAX_SCHEDULE_AHEAD_MS,
|
||||||
|
scheduleMessage,
|
||||||
|
SCHEDULE_TOO_FAR_TEXT,
|
||||||
|
} from '../../utils/scheduledMessages';
|
||||||
import { useModalStyle } from '../../hooks/useModalStyle';
|
import { useModalStyle } from '../../hooks/useModalStyle';
|
||||||
import {
|
import {
|
||||||
toLocalDate,
|
toLocalDate,
|
||||||
@@ -121,7 +126,13 @@ export function ScheduleMessageModal({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const diffMs = sendAt.getTime() - Date.now();
|
const diffMs = sendAt.getTime() - Date.now();
|
||||||
if (diffMs < 60_000) {
|
// [Gitea #275] Say so as soon as a too-late time is picked, not on submit.
|
||||||
|
const tooFar = diffMs > MAX_SCHEDULE_AHEAD_MS;
|
||||||
|
setError((e) => {
|
||||||
|
if (tooFar) return SCHEDULE_TOO_FAR_TEXT;
|
||||||
|
return e === SCHEDULE_TOO_FAR_TEXT ? null : e;
|
||||||
|
});
|
||||||
|
if (diffMs < 60_000 || tooFar) {
|
||||||
setPreview(null);
|
setPreview(null);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -149,6 +160,10 @@ export function ScheduleMessageModal({
|
|||||||
setError('Scheduled time must be at least 1 minute in the future.');
|
setError('Scheduled time must be at least 1 minute in the future.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (diffMs > MAX_SCHEDULE_AHEAD_MS) {
|
||||||
|
setError(SCHEDULE_TOO_FAR_TEXT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!messageText.trim()) {
|
if (!messageText.trim()) {
|
||||||
setError('Please enter a message to schedule.');
|
setError('Please enter a message to schedule.');
|
||||||
return;
|
return;
|
||||||
@@ -162,7 +177,7 @@ export function ScheduleMessageModal({
|
|||||||
onScheduled(delayId, sendAt.getTime(), content);
|
onScheduled(delayId, sendAt.getTime(), content);
|
||||||
onClose();
|
onClose();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setError(err instanceof Error ? err.message : 'Failed to schedule message.');
|
setError(describeScheduleError(err));
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -247,6 +262,8 @@ export function ScheduleMessageModal({
|
|||||||
<input
|
<input
|
||||||
id="schedule-date"
|
id="schedule-date"
|
||||||
type="date"
|
type="date"
|
||||||
|
min={toLocalDate(new Date())}
|
||||||
|
max={toLocalDate(new Date(Date.now() + MAX_SCHEDULE_AHEAD_MS))}
|
||||||
value={dateValue}
|
value={dateValue}
|
||||||
onChange={(e) => setDateValue(e.target.value)}
|
onChange={(e) => setDateValue(e.target.value)}
|
||||||
style={pickerInputStyle(color, config)}
|
style={pickerInputStyle(color, config)}
|
||||||
@@ -294,7 +311,8 @@ export function ScheduleMessageModal({
|
|||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
) : (
|
) : (
|
||||||
(dateValue || timeValue) && (
|
(dateValue || timeValue) &&
|
||||||
|
error !== SCHEDULE_TOO_FAR_TEXT && (
|
||||||
<Text size="T200" style={{ color: color.Critical.Main }}>
|
<Text size="T200" style={{ color: color.Critical.Main }}>
|
||||||
Must be at least 1 minute in the future
|
Must be at least 1 minute in the future
|
||||||
</Text>
|
</Text>
|
||||||
|
|||||||
@@ -179,3 +179,15 @@ test('groupScheduledByRoom: groups and sorts by sendAt', () => {
|
|||||||
);
|
);
|
||||||
assert.equal(g.get('!2')?.length, 1);
|
assert.equal(g.get('!2')?.length, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('[#275] the server limit maps to friendly text; other errors keep theirs', async () => {
|
||||||
|
const { describeScheduleError, SCHEDULE_TOO_FAR_TEXT, MAX_SCHEDULE_AHEAD_MS } =
|
||||||
|
await import('./scheduledMessages');
|
||||||
|
assert.equal(MAX_SCHEDULE_AHEAD_MS, 86_400_000);
|
||||||
|
const tooLarge = Object.assign(new Error('The requested delay (172800000ms) exceeds…'), {
|
||||||
|
errcode: 'ORG.MATRIX.MSC4140_DELAY_TOO_LARGE',
|
||||||
|
});
|
||||||
|
assert.equal(describeScheduleError(tooLarge), SCHEDULE_TOO_FAR_TEXT);
|
||||||
|
assert.equal(describeScheduleError(new Error('Boom')), 'Boom');
|
||||||
|
assert.equal(describeScheduleError('nope'), 'Failed to schedule message.');
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,6 +1,22 @@
|
|||||||
import { IContent, MatrixClient, Method } from 'matrix-js-sdk';
|
import { IContent, MatrixClient, Method } from 'matrix-js-sdk';
|
||||||
import type { ScheduledMessage } from '../state/scheduledMessages';
|
import type { ScheduledMessage } from '../state/scheduledMessages';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Gitea #275] Production Synapse caps delayed events at
|
||||||
|
* `max_event_delay_duration: 24h`; a later time is rejected with
|
||||||
|
* ORG.MATRIX.MSC4140_DELAY_TOO_LARGE. The dialog enforces the same limit and
|
||||||
|
* the server's error maps to the same text, in case the limit changes.
|
||||||
|
*/
|
||||||
|
export const MAX_SCHEDULE_AHEAD_MS = 24 * 60 * 60 * 1000;
|
||||||
|
export const SCHEDULE_TOO_FAR_TEXT = 'You can schedule up to 24 hours ahead.';
|
||||||
|
|
||||||
|
/** A user-facing sentence for a failed schedule. */
|
||||||
|
export const describeScheduleError = (err: unknown): string => {
|
||||||
|
const errcode = (err as { errcode?: unknown } | null)?.errcode;
|
||||||
|
if (errcode === 'ORG.MATRIX.MSC4140_DELAY_TOO_LARGE') return SCHEDULE_TOO_FAR_TEXT;
|
||||||
|
return err instanceof Error ? err.message : 'Failed to schedule message.';
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule a message via MSC4140 (delayed messages).
|
* Schedule a message via MSC4140 (delayed messages).
|
||||||
* Synapse implementation: pass org.matrix.msc4140.delay on the standard
|
* Synapse implementation: pass org.matrix.msc4140.delay on the standard
|
||||||
|
|||||||
Reference in New Issue
Block a user