diff --git a/src/pages/api/reports/funnel.ts b/src/pages/api/reports/funnel.ts index 35759a3030..f3ea41aa6e 100644 --- a/src/pages/api/reports/funnel.ts +++ b/src/pages/api/reports/funnel.ts @@ -31,7 +31,10 @@ const schema = { .of( yup.object().shape({ type: yup.string().required(), - value: yup.string().required(), + value: yup + .string() + .matches(/^[a-zA-Z0-9/*-_]+$/, 'Invalid URL pattern') + .required(), }), ) .min(2) diff --git a/src/queries/analytics/reports/getFunnel.ts b/src/queries/analytics/reports/getFunnel.ts index f9ceb85cd1..0a812d8a52 100644 --- a/src/queries/analytics/reports/getFunnel.ts +++ b/src/queries/analytics/reports/getFunnel.ts @@ -70,9 +70,19 @@ async function relationalQuery( (pv, cv, i) => { const levelNumber = i + 1; const startSum = i > 0 ? 'union ' : ''; - const operator = cv.type === 'url' && cv.value.endsWith('*') ? 'like' : '='; - const column = cv.type === 'url' ? 'url_path' : 'event_name'; - const paramValue = cv.value.endsWith('*') ? cv.value.replace('*', '%') : cv.value; + const isURL = cv.type === 'url'; + const column = isURL ? 'url_path' : 'event_name'; + + let operator = '='; + let paramValue = cv.value; + + if (isURL && cv.value.includes('*')) { + operator = '~'; + paramValue = cv.value.replace(/\*/g, '.*'); + } else if (isURL && cv.value.endsWith('*')) { + operator = 'like'; + paramValue = cv.value.replace('*', '%'); + } if (levelNumber === 1) { pv.levelOneQuery = ` @@ -167,9 +177,26 @@ async function clickhouseQuery( const levelNumber = i + 1; const startSum = i > 0 ? 'union all ' : ''; const startFilter = i > 0 ? 'or' : ''; - const operator = cv.type === 'url' && cv.value.endsWith('*') ? 'like' : '='; const column = cv.type === 'url' ? 'url_path' : 'event_name'; - const paramValue = cv.value.endsWith('*') ? cv.value.replace('*', '%') : cv.value; + + let operator: string; + let paramValue: string; + + if (cv.type === 'url') { + if (cv.value.includes('*')) { + operator = 'match'; + paramValue = cv.value.replace(/\*/g, '.*'); + } else if (cv.value.endsWith('*')) { + operator = 'like'; + paramValue = cv.value.replace('*', '%'); + } else { + operator = '='; + paramValue = cv.value; + } + } else { + operator = '='; + paramValue = cv.value; + } if (levelNumber === 1) { pv.levelOneQuery = `\n