Add a 'usp' URL parameter that can be used for tracking
Well, actually this change *removes* the URL parameter. :-) So the
webserver will get and log it, but the user will not be bothered by it.
Change-Id: Ieb1374ce9ff5ec30b589a7b340d24cb6f50d5653
diff --git a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
index 676ef7b..e0bd0b9 100644
--- a/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
+++ b/polygerrit-ui/app/elements/core/gr-router/gr-router.ts
@@ -68,6 +68,7 @@
import {firePageError} from '../../../utils/event-util';
import {addQuotesWhen} from '../../../utils/string-util';
import {windowLocationReload} from '../../../utils/dom-util';
+import {toPath, toPathname, toSearchParams} from '../../../utils/url-util';
const RoutePattern = {
ROOT: '/',
@@ -762,20 +763,21 @@
/** Page.js middleware that try parse the querystring into queryMap. */
_queryStringMiddleware(ctx: PageContext, next: PageNextCallback) {
- let queryMap: Map<string, string> | URLSearchParams = new Map<
- string,
- string
- >();
+ (ctx as PageContextWithQueryMap).queryMap = this.createQueryMap(ctx);
+ next();
+ }
+
+ private createQueryMap(ctx: PageContext) {
if (ctx.querystring) {
// https://caniuse.com/#search=URLSearchParams
if (window.URLSearchParams) {
- queryMap = new URLSearchParams(ctx.querystring);
+ return new URLSearchParams(ctx.querystring);
} else {
- queryMap = new Map(this._parseQueryString(ctx.querystring));
+ this.reporting.reportExecution('noURLSearchParams');
+ return new Map(this._parseQueryString(ctx.querystring));
}
}
- (ctx as PageContextWithQueryMap).queryMap = queryMap;
- next();
+ return new Map<string, string>();
}
/**
@@ -806,13 +808,13 @@
pattern,
(ctx, next) => this._loadUserMiddleware(ctx, next),
(ctx, next) => this._queryStringMiddleware(ctx, next),
- data => {
+ ctx => {
this.reporting.locationChanged(handlerName);
const promise = authRedirect
- ? this._redirectIfNotLoggedIn(data)
+ ? this._redirectIfNotLoggedIn(ctx)
: Promise.resolve();
promise.then(() => {
- this[handlerName](data as PageContextWithQueryMap);
+ this[handlerName](ctx as PageContextWithQueryMap);
});
}
);
@@ -846,6 +848,21 @@
next();
});
+ // Remove the tracking param 'usp' (User Source Parameter) from the URL,
+ // just to have users look at cleaner URLs.
+ page((ctx, next) => {
+ if (window.URLSearchParams) {
+ const pathname = toPathname(ctx.canonicalPath);
+ const searchParams = toSearchParams(ctx.canonicalPath);
+ if (searchParams.has('usp')) {
+ searchParams.delete('usp');
+ this._redirect(toPath(pathname, searchParams));
+ return;
+ }
+ }
+ next();
+ });
+
// Middleware
page((ctx, next) => {
document.body.scrollTop = 0;
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
index 1be1d63..a7b5410 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
@@ -97,7 +97,7 @@
*
* Every execution is only reported once per session.
*/
- reportExecution(id: string, details: EventDetails): void;
+ reportExecution(id: string, details?: EventDetails): void;
trackApi(plugin: PluginApi, object: string, method: string): void;
reportInteraction(eventName: string, details?: EventDetails): void;
/**
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
index e57670d..f1e09c1 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
@@ -792,7 +792,7 @@
);
}
- reportExecution(id: string, details: EventDetails) {
+ reportExecution(id: string, details?: EventDetails) {
if (this.executionReported.has(id)) return;
this.executionReported.add(id);
this.reporter(
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
index 7d66484..047bb4e 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
@@ -65,7 +65,7 @@
error: () => {
log('error');
},
- reportExecution: (id: string, details: EventDetails) => {
+ reportExecution: (id: string, details?: EventDetails) => {
log(`reportExecution '${id}': ${JSON.stringify(details)}`);
},
trackApi: (plugin: PluginApi, object: string, method: string) => {
diff --git a/polygerrit-ui/app/utils/url-util.ts b/polygerrit-ui/app/utils/url-util.ts
index f977ab6..4115062 100644
--- a/polygerrit-ui/app/utils/url-util.ts
+++ b/polygerrit-ui/app/utils/url-util.ts
@@ -78,3 +78,33 @@
const withoutPlus = url.replace(/\+/g, '%20');
return decodeURIComponent(withoutPlus);
}
+
+/**
+ * @param path URL path including search params, but without host
+ */
+export function toPathname(path: string) {
+ const i = path.indexOf('?');
+ const hasQuery = i > -1;
+ const pathname = hasQuery ? path.slice(0, i) : path;
+ return pathname;
+}
+
+/**
+ * @param path URL path including search params, but without host
+ */
+export function toSearchParams(path: string) {
+ const i = path.indexOf('?');
+ const hasQuery = i > -1;
+ const querystring = hasQuery ? path.slice(i + 1) : '';
+ return new URLSearchParams(querystring);
+}
+
+/**
+ * @param pathname URL path without search params
+ * @param params
+ */
+export function toPath(pathname: string, searchParams: URLSearchParams) {
+ const paramString = searchParams.toString();
+ const middle = paramString ? '?' : '';
+ return pathname + middle + paramString;
+}
diff --git a/polygerrit-ui/app/utils/url-util_test.js b/polygerrit-ui/app/utils/url-util_test.js
index b1b17f4..5cd4bb4 100644
--- a/polygerrit-ui/app/utils/url-util_test.js
+++ b/polygerrit-ui/app/utils/url-util_test.js
@@ -20,7 +20,11 @@
getBaseUrl,
getDocsBaseUrl,
_testOnly_clearDocsBaseUrlCache,
- encodeURL, singleDecodeURL,
+ encodeURL,
+ singleDecodeURL,
+ toPath,
+ toPathname,
+ toSearchParams,
} from './url-util.js';
suite('url-util tests', () => {
@@ -124,4 +128,23 @@
});
});
});
+
+ test('toPathname', () => {
+ assert.equal(toPathname('asdf'), 'asdf');
+ assert.equal(toPathname('asdf?qwer=zxcv'), 'asdf');
+ });
+
+ test('toSearchParams', () => {
+ assert.equal(toSearchParams('asdf').toString(), '');
+ assert.equal(toSearchParams('asdf?qwer=zxcv').get('qwer'), 'zxcv');
+ });
+
+ test('toPathname', () => {
+ const params = new URLSearchParams();
+ assert.equal(toPath('asdf', params), 'asdf');
+ params.set('qwer', 'zxcv');
+ assert.equal(toPath('asdf', params), 'asdf?qwer=zxcv');
+ assert.equal(toPath(toPathname('asdf?qwer=zxcv'),
+ toSearchParams('asdf?qwer=zxcv')), 'asdf?qwer=zxcv');
+ });
});