Skip to content

Commit

Permalink
hide query params with empty values
Browse files Browse the repository at this point in the history
workaround for emberjs/ember.js#18683
  • Loading branch information
aaxelb committed Jan 17, 2020
1 parent 021b014 commit 97fd330
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 16 deletions.
6 changes: 0 additions & 6 deletions app/application/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,6 @@ export default class ApplicationRoute extends Route.extend(
@service i18n!: I18N;
@service currentUser!: CurrentUser;

queryParams = {
viewOnlyToken: {
refreshModel: false,
},
};

afterModel() {
const i18n = this.get('i18n');
const availableLocales: [string] = i18n.get('locales').toArray();
Expand Down
4 changes: 2 additions & 2 deletions app/locations/auto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import AutoLocation from '@ember/routing/auto-location';
import GuidLocationMixin from 'ember-osf-web/locations/guid-mixin';
import CleanUrlLocationMixin from 'ember-osf-web/locations/clean-url-mixin';

// Sadly the `auto` location must be overriden, otherwise
// ember-cli's server doesn't allow visiting specific URLs
export default class GuidAutoLocation extends AutoLocation.extend(GuidLocationMixin) {
export default class CleanUrlAutoLocation extends AutoLocation.extend(CleanUrlLocationMixin) {
}
File renamed without changes.
4 changes: 2 additions & 2 deletions app/locations/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { inject as service } from '@ember/service';
import { waitForQueue } from 'ember-concurrency';
import { task } from 'ember-concurrency-decorators';

import GuidLocationMixin from 'ember-osf-web/locations/guid-mixin';
import CleanUrlLocationMixin from 'ember-osf-web/locations/clean-url-mixin';
import OsfRouterService from 'ember-osf-web/services/osf-router';
import Ready from 'ember-osf-web/services/ready';
import scrollTo from 'ember-osf-web/utils/scroll-to';
Expand All @@ -17,7 +17,7 @@ function splitFragment(url: string): [string, string?] {
}

// Add support for scrolling to elements according to the URL's #fragment.
export default class FragmentHistoryLocation extends HistoryLocation.extend(GuidLocationMixin) {
export default class FragmentHistoryLocation extends HistoryLocation.extend(CleanUrlLocationMixin) {
@service ready!: Ready;
@service osfRouter!: OsfRouterService;

Expand Down
4 changes: 2 additions & 2 deletions app/locations/none.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import NoneLocation from '@ember/routing/none-location';
import GuidLocationMixin from 'ember-osf-web/locations/guid-mixin';
import CleanUrlLocationMixin from 'ember-osf-web/locations/clean-url-mixin';

// Sadly the `none` location must be overriden, otherwise
// ember-test-helper's helpers will leave --segments left over in the URL
export default class GuidNoneLocation extends NoneLocation.extend(GuidLocationMixin) {
export default class CleanUrlNoneLocation extends NoneLocation.extend(CleanUrlLocationMixin) {
path!: string;

// Opt out of URL "cleaning" when in tests.
Expand Down
14 changes: 11 additions & 3 deletions app/utils/clean-url.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
import { assert } from '@ember/debug';
import { filterQueryParams } from './url-parts';

/**
* Remove the --guidtype portions of a URL that are only used for guid routing
* and should never appear in a real URL.
* Given a URL, remove cruft that should not be visible to the user:
* - `/--foo/` path segments (only used for guid/engine routing)
* - trailing slash at the end of the path
* - query params with empty values (workaround for a bug in ember:
* https://github.com/emberjs/ember.js/issues/18683)
* NOTE: this may cause problems if a query param has a non-empty default
* value but may be set to an empty value.
*
*/
export default function cleanURL(url: string) {
assert(`cleanURL expects a path starting with '/', got '${url}'`, url.startsWith('/'));

const cleanedURL = url
const cleanedURL = filterQueryParams(url, (_, value) => Boolean(value))
.replace(/(?:^|\/)--[^/?]+/g, '') // remove '--foo' segments
.replace(/\/(?=$|[?#])/, ''); // remove trailing slash

Expand Down
23 changes: 23 additions & 0 deletions app/utils/url-parts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,29 @@ export function addQueryParam(url: string, key: string, value: string): string {
});
}

export function filterQueryParams(
url: string,
filterFn: (key: string, value: string) => boolean,
): string {
const { path, queryString, fragment } = splitUrl(url);

const queryParams = deserializeQueryString(queryString || '');

const filteredQueryParams: Record<string, string> = {};

Object.entries(queryParams)
.filter(([key, value]) => filterFn(key, value))
.forEach(([key, value]) => {
filteredQueryParams[key] = value;
});

return joinUrl({
path,
queryString: param(filteredQueryParams),
fragment,
});
}

export function addPathSegment(url: string, segment: string): string {
const { path, queryString, fragment } = splitUrl(url);
return joinUrl({
Expand Down
20 changes: 20 additions & 0 deletions tests/unit/utils/clean-url-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,26 @@ const TEST_CASES = [{
input: '/--user/abcd/?query=param#frag',
cleanOutput: '/abcd?query=param#frag',
notFoundOutput: 'abcd#frag',
}, {
input: '/?aoeu=',
cleanOutput: '/',
notFoundOutput: '',
}, {
input: '/AttheEnd/--registries/?query=',
cleanOutput: '/AttheEnd',
notFoundOutput: 'AttheEnd',
}, {
input: '/normal--url/?query=param&empty=',
cleanOutput: '/normal--url?query=param',
notFoundOutput: 'normal--url',
}, {
input: '/--user/abcd/?some-empty=#frag',
cleanOutput: '/abcd#frag',
notFoundOutput: 'abcd#frag',
}, {
input: '/--user/abcd/?blah=&blee=&query=param#frag',
cleanOutput: '/abcd?query=param#frag',
notFoundOutput: 'abcd#frag',
}];

module('Unit | Utility | cleanURL', () => {
Expand Down
81 changes: 80 additions & 1 deletion tests/unit/utils/url-parts-test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { addPathSegment, addQueryParam, joinUrl, splitUrl } from 'ember-osf-web/utils/url-parts';
import { module, test } from 'qunit';

import {
addPathSegment,
addQueryParam,
filterQueryParams,
joinUrl,
splitUrl,
} from 'ember-osf-web/utils/url-parts';

module('Unit | Utility | url-parts', () => {
test('splitUrl and joinUrl', assert => {
const testCases = [
Expand Down Expand Up @@ -140,4 +147,76 @@ module('Unit | Utility | url-parts', () => {
assert.equal(actual, testCase.expected, 'addPathSegment added a path segment');
}
});

test('filterQueryParams', assert => {
const testCases: Array<{
initial: string,
filterFn: (k: string, v: string) => boolean,
expected: string,
}> = [
{
initial: 'https://osf.io/',
filterFn: () => true,
expected: 'https://osf.io/',
},
{
initial: 'https://osf.io/?blah=blee&bloo=blah&blee=blee',
filterFn: () => true,
expected: 'https://osf.io/?blah=blee&bloo=blah&blee=blee',
},
{
initial: 'https://osf.io/?blah=blee&bloo=blah&blee=blee',
filterFn: () => false,
expected: 'https://osf.io/',
},
{
initial: 'https://osf.io/?blah=blee&bloo=blah&blee=blee',
filterFn: (k, v) => k === v,
expected: 'https://osf.io/?blah=blee&bloo=blah',
},
{
initial: 'https://osf.io/?blah=blah&bloo=blah&blee=blee',
filterFn: (k, v) => k !== v,
expected: 'https://osf.io/?bloo=blah',
},
{
initial: 'https://osf.io/?blah=blah&bloo=blah&blee=blee#plus-fragment',
filterFn: (k, v) => k !== v,
expected: 'https://osf.io/?bloo=blah#plus-fragment',
},
{
initial: '/just/a/path?blah=blee&bloo=blah&blee=blee',
filterFn: () => true,
expected: '/just/a/path?blah=blee&bloo=blah&blee=blee',
},
{
initial: '/just/a/path?blah=blee&bloo=blah&blee=blee',
filterFn: () => false,
expected: '/just/a/path',
},
{
initial: '/just/a/path?blah=blee&bloo=blah&blee=blee',
filterFn: (k, v) => k === v,
expected: '/just/a/path?blah=blee&bloo=blah',
},
{
initial: '/just/a/path?blah=blee&bloo=blah&blee=blee#plus-fragment',
filterFn: () => false,
expected: '/just/a/path#plus-fragment',
},
{
initial: '/just/a/path?blah=blee&bloo=blah&blee=blee#plus-fragment',
filterFn: (k, v) => k === v,
expected: '/just/a/path?blah=blee&bloo=blah#plus-fragment',
},
];

for (const testCase of testCases) {
const actual = filterQueryParams(
testCase.initial,
testCase.filterFn,
);
assert.equal(actual, testCase.expected, 'filterQueryParams filtered query params');
}
});
});

0 comments on commit 97fd330

Please sign in to comment.