Initial TicketTracker release
This commit is contained in:
commit
125b1d22ff
128 files changed
+26208
No files matched your search
@@ -0,0 +1,135 @@
|
||||
export const ticketPattern = /^Ticket#\d{6}$/;
|
||||
export const trackableTicketPattern = /^(Ticket#\d{6}|Fix#\d+)$/;
|
||||
export const monthPattern = /^\d{4}-\d{2}$/;
|
||||
export const dayPattern = /^\d{4}-\d{2}-\d{2}$/;
|
||||
export const usernamePattern = /^\S{3,40}$/u;
|
||||
|
||||
export function requireString(value: unknown, field: string) {
|
||||
if (typeof value !== "string" || value.trim().length === 0) {
|
||||
throw badRequest(`${field} is required`);
|
||||
}
|
||||
|
||||
return value.trim();
|
||||
}
|
||||
|
||||
export function parseTicketNumber(value: unknown) {
|
||||
const ticketNumber = requireString(value, "ticketNumber");
|
||||
|
||||
if (!ticketPattern.test(ticketNumber)) {
|
||||
throw badRequest("ticketNumber must match Ticket#XXXXXX");
|
||||
}
|
||||
|
||||
return ticketNumber;
|
||||
}
|
||||
|
||||
export function parseTrackableTicketNumber(value: unknown) {
|
||||
const ticketNumber = requireString(value, "ticketNumber");
|
||||
|
||||
if (!trackableTicketPattern.test(ticketNumber)) {
|
||||
throw badRequest("ticketNumber must match Ticket#XXXXXX or Fix#ID");
|
||||
}
|
||||
|
||||
return ticketNumber;
|
||||
}
|
||||
|
||||
export function parseUsername(value: unknown) {
|
||||
const username = requireString(value, "username");
|
||||
|
||||
if (!usernamePattern.test(username)) {
|
||||
throw badRequest("username must be 3-40 characters without spaces");
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
export function parseMonth(value: string) {
|
||||
if (!monthPattern.test(value)) {
|
||||
throw badRequest("month must use YYYY-MM");
|
||||
}
|
||||
|
||||
const monthStart = `${value}-01`;
|
||||
const date = new Date(`${monthStart}T00:00:00.000Z`);
|
||||
|
||||
if (Number.isNaN(date.getTime()) || date.getUTCMonth() + 1 !== Number(value.slice(5, 7))) {
|
||||
throw badRequest("month is invalid");
|
||||
}
|
||||
|
||||
const next = new Date(date);
|
||||
next.setUTCMonth(next.getUTCMonth() + 1);
|
||||
|
||||
return {
|
||||
label: value,
|
||||
start: monthStart,
|
||||
startIso: date.toISOString(),
|
||||
endIso: next.toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
export function parseDay(value: string) {
|
||||
if (!dayPattern.test(value)) {
|
||||
throw badRequest("day must use YYYY-MM-DD");
|
||||
}
|
||||
|
||||
const date = new Date(`${value}T00:00:00.000Z`);
|
||||
|
||||
if (Number.isNaN(date.getTime()) || date.toISOString().slice(0, 10) !== value) {
|
||||
throw badRequest("day is invalid");
|
||||
}
|
||||
|
||||
const next = new Date(date);
|
||||
next.setUTCDate(next.getUTCDate() + 1);
|
||||
|
||||
return {
|
||||
label: value,
|
||||
start: value,
|
||||
startIso: date.toISOString(),
|
||||
endIso: next.toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
export function parsePositiveInteger(value: unknown, field: string) {
|
||||
const number = Number(value);
|
||||
|
||||
if (!Number.isInteger(number) || number < 0) {
|
||||
throw badRequest(`${field} must be a positive integer`);
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
export function parseWorkType(value: unknown) {
|
||||
if (value !== "support" && value !== "consulting") {
|
||||
throw badRequest("workType must be support or consulting");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function parseBillingStatus(value: unknown) {
|
||||
if (value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value !== "billed" && value !== "non_billable") {
|
||||
throw badRequest("billingStatus must be billed, non_billable or null");
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export function parseIsoDate(value: unknown, field: string) {
|
||||
const raw = requireString(value, field);
|
||||
const date = new Date(raw);
|
||||
|
||||
if (Number.isNaN(date.getTime())) {
|
||||
throw badRequest(`${field} must be an ISO date`);
|
||||
}
|
||||
|
||||
return date;
|
||||
}
|
||||
|
||||
export function badRequest(message: string) {
|
||||
const error = new Error(message) as Error & { status?: number };
|
||||
error.status = 400;
|
||||
return error;
|
||||
}
|
||||
Reference in new issue
Block a user