Skip to content

Commit bcff929

Browse files
committed
edited notes: recognize not valid dates/keywords, return 0 limit to client
1 parent ad9a058 commit bcff929

File tree

2 files changed

+65
-14
lines changed

2 files changed

+65
-14
lines changed

apps/server/src/routes/api/edited-notes.spec.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ function keywordResolvesToDate(dateStrOrKeyword: string, expectedDate: string) {
2525
});
2626
}
2727

28+
function keywordDoesNotResolve(dateStrOrKeyword: string) {
29+
cls.init(() => {
30+
cls.set("localNowDateTime", clientDate);
31+
const dateFilter = dateNoteLabelKeywordToDateFilter(dateStrOrKeyword);
32+
expect(dateFilter.date).toBe(null);
33+
});
34+
}
35+
2836
describe("edited-notes::dateNoteLabelKeywordToDateFilter", () => {
2937
beforeEach(() => {
3038
vi.stubEnv('TZ', 'UTC');
@@ -70,16 +78,32 @@ describe("edited-notes::dateNoteLabelKeywordToDateFilter", () => {
7078
keywordResolvesToDate("2020-12", "2020-12");
7179
});
7280

81+
it("returns original string for partial month", () => {
82+
keywordResolvesToDate("2020-1", "2020-1");
83+
});
84+
85+
it("returns original string for partial month with trailing dash", () => {
86+
keywordResolvesToDate("2020-", "2020-");
87+
});
88+
7389
it("returns original string for year", () => {
7490
keywordResolvesToDate("2020", "2020");
7591
});
7692

77-
it("returns original string for unrecognized keyword", () => {
78-
keywordResolvesToDate("FOO", "FOO");
93+
it("returns original string for potentially partial day", () => {
94+
keywordResolvesToDate("2020-12-1", "2020-12-1");
95+
});
96+
97+
it("returns null for partial year", () => {
98+
keywordDoesNotResolve("202");
99+
});
100+
101+
it("returns null for arbitrary string", () => {
102+
keywordDoesNotResolve("FOO");
79103
});
80104

81-
it("returns original string for partially recognized keyword", () => {
82-
keywordResolvesToDate("TODAY-", "TODAY-");
105+
it("returns null for missing delta", () => {
106+
keywordDoesNotResolve("TODAY-");
83107
});
84108

85109
it("resolves 'today' (lowercase) to today's date", () => {

apps/server/src/routes/api/edited-notes.ts

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@ interface NotePojoWithNotePath extends NotePojo {
2424
function getEditedNotesOnDate(req: Request) {
2525
const dateFilter = dateNoteLabelKeywordToDateFilter(req.params.date);
2626

27+
if (!dateFilter.date) {
28+
return {
29+
notes: [],
30+
limit: 0,
31+
} satisfies EditedNotesResponse;
32+
}
33+
2734
const sqlParams = { date: dateFilter.date + "%" };
2835
const limit = 50;
2936
const sqlQuery = /*sql*/`\
@@ -117,7 +124,7 @@ function formatDateFromKeywordAndDelta(
117124

118125
interface DateValue {
119126
// kind: "date",
120-
date: string,
127+
date: string | null,
121128
}
122129

123130
type DateFilter = DateValue;
@@ -146,22 +153,42 @@ type DateFilter = DateValue;
146153
* @returns A `DateFilter` object containing the resolved date string.
147154
*/
148155
export function dateNoteLabelKeywordToDateFilter(dateStr: string): DateFilter {
149-
const match = dateStr.match(/^(today|month|year)([+-]\d+)?$/i);
156+
const keywordAndDelta = dateStr.match(/^(today|month|year)([+-]\d+)?$/i);
157+
158+
if (keywordAndDelta) {
159+
const keyword = keywordAndDelta[1].toLowerCase();
160+
const delta = keywordAndDelta[2] ? parseInt(keywordAndDelta[2]) : 0;
150161

151-
if (!match) {
162+
const clientDate = dayjs(dateUtils.localNowDate());
163+
const date = formatDateFromKeywordAndDelta(clientDate, keyword, delta);
164+
return {
165+
date: date
166+
};
167+
}
168+
169+
// Check if it's a valid date format (YYYY-MM-DD, YYYY-MM, or YYYY)
170+
const isDatePrefix = isValidDatePrefix(dateStr);
171+
172+
if (isDatePrefix) {
152173
return {
153174
date: dateStr
175+
};
176+
} else {
177+
// Not a keyword and not a valid date prefix
178+
return {
179+
date: null
154180
}
155181
}
182+
}
156183

157-
const keyword = match[1].toLowerCase();
158-
const delta = match[2] ? parseInt(match[2]) : 0;
159-
160-
const clientDate = dayjs(dateUtils.localNowDate());
161-
const date = formatDateFromKeywordAndDelta(clientDate, keyword, delta);
162-
return {
163-
date: date
184+
function isValidDatePrefix(dateStr: string): boolean {
185+
// Check if it starts with YYYY format
186+
if (/^\d{4}/.test(dateStr)) {
187+
const year = parseInt(dateStr.substring(0, 4));
188+
return !isNaN(year) && year > 0 && year < 10000;
164189
}
190+
191+
return false;
165192
}
166193

167194
export default {

0 commit comments

Comments
 (0)