2020-10-01 08:33:22 +00:00
|
|
|
import Route from '@ember/routing/route';
|
2021-09-15 18:50:11 +00:00
|
|
|
import { get, setProperties, action } from '@ember/object';
|
2021-02-19 16:42:16 +00:00
|
|
|
import { inject as service } from '@ember/service';
|
|
|
|
import HTTPError from 'consul-ui/utils/http/error';
|
2020-10-01 08:33:22 +00:00
|
|
|
|
2020-10-19 16:30:30 +00:00
|
|
|
// paramsFor
|
|
|
|
import { routes } from 'consul-ui/router';
|
|
|
|
import wildcard from 'consul-ui/utils/routing/wildcard';
|
2021-02-19 16:42:16 +00:00
|
|
|
|
2020-10-19 16:30:30 +00:00
|
|
|
const isWildcard = wildcard(routes);
|
|
|
|
|
2020-10-01 08:33:22 +00:00
|
|
|
export default class BaseRoute extends Route {
|
2021-05-26 16:43:46 +00:00
|
|
|
@service('container') container;
|
|
|
|
@service('env') env;
|
2021-02-19 16:42:16 +00:00
|
|
|
@service('repository/permission') permissions;
|
2021-05-26 16:43:46 +00:00
|
|
|
@service('router') router;
|
2021-02-19 16:42:16 +00:00
|
|
|
|
2021-09-22 17:32:51 +00:00
|
|
|
redirect(model, transition) {
|
|
|
|
// remove any references to index as it is the same as the root routeName
|
|
|
|
const routeName = this.routeName
|
|
|
|
.split('.')
|
|
|
|
.filter(item => item !== 'index')
|
|
|
|
.join('.');
|
|
|
|
const to = get(routes, `${routeName}._options.redirect`);
|
|
|
|
if (typeof to !== 'undefined') {
|
|
|
|
// TODO: Does this need to return?
|
|
|
|
// Almost remember things getting strange if you returned from here
|
|
|
|
// which is why I didn't do it originally so be sure to look properly if
|
|
|
|
// you feel like adding a return
|
|
|
|
this.replaceWith(`${routeName}${to}`, model);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-19 16:42:16 +00:00
|
|
|
/**
|
|
|
|
* Inspects a custom `abilities` array on the router for this route. Every
|
|
|
|
* abililty needs to 'pass' for the route not to throw a 403 error. Anything
|
|
|
|
* more complex then this (say ORs) should use a single ability and perform
|
2021-03-11 09:29:11 +00:00
|
|
|
* the OR logic in the test for the ability. Note, this ability check happens
|
2021-02-19 16:42:16 +00:00
|
|
|
* before any calls to the backend for this model/route.
|
|
|
|
*/
|
|
|
|
async beforeModel() {
|
2021-03-11 09:29:11 +00:00
|
|
|
// remove any references to index as it is the same as the root routeName
|
|
|
|
const routeName = this.routeName
|
|
|
|
.split('.')
|
|
|
|
.filter(item => item !== 'index')
|
|
|
|
.join('.');
|
|
|
|
const abilities = get(routes, `${routeName}._options.abilities`) || [];
|
2021-02-19 16:42:16 +00:00
|
|
|
if (abilities.length > 0) {
|
|
|
|
if (!abilities.every(ability => this.permissions.can(ability))) {
|
2021-03-11 09:29:11 +00:00
|
|
|
throw new HTTPError('403');
|
2021-02-19 16:42:16 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-01 15:45:09 +00:00
|
|
|
/**
|
|
|
|
* By default any empty string query parameters should remove the query
|
|
|
|
* parameter from the URL. This is the most common behavior if you don't
|
|
|
|
* require this behavior overwrite this method in the specific Route for the
|
|
|
|
* specific queryParam key.
|
|
|
|
* If the behaviour should be different add an empty: [] parameter to the
|
|
|
|
* queryParameter configuration to configure what is deemed 'empty'
|
|
|
|
*/
|
|
|
|
serializeQueryParam(value, key, type) {
|
2021-02-19 16:42:16 +00:00
|
|
|
if (typeof value !== 'undefined') {
|
2020-12-01 15:45:09 +00:00
|
|
|
const empty = get(this, `queryParams.${key}.empty`);
|
2021-02-19 16:42:16 +00:00
|
|
|
if (typeof empty === 'undefined') {
|
2020-12-01 15:45:09 +00:00
|
|
|
// by default any queryParams when an empty string mean undefined,
|
|
|
|
// therefore remove the queryParam from the URL
|
2021-02-19 16:42:16 +00:00
|
|
|
if (value === '') {
|
2020-12-01 15:45:09 +00:00
|
|
|
value = undefined;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
const possible = empty[0];
|
|
|
|
let actual = value;
|
2021-02-19 16:42:16 +00:00
|
|
|
if (Array.isArray(actual)) {
|
2020-12-01 15:45:09 +00:00
|
|
|
actual = actual.split(',');
|
|
|
|
}
|
2021-02-19 16:42:16 +00:00
|
|
|
const diff = possible.filter(item => !actual.includes(item));
|
|
|
|
if (diff.length === 0) {
|
2020-12-01 15:45:09 +00:00
|
|
|
value = undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return value;
|
|
|
|
}
|
2021-02-19 16:42:16 +00:00
|
|
|
|
2021-10-01 10:07:58 +00:00
|
|
|
// TODO: this is only required due to intention_id trying to do too much
|
|
|
|
// therefore we need to change the route parameter intention_id to just
|
|
|
|
// intention or id or similar then we can revert to only returning a model if
|
|
|
|
// we have searchProps (or a child route overwrites model)
|
2021-09-15 18:50:11 +00:00
|
|
|
model() {
|
|
|
|
const model = {};
|
|
|
|
if (
|
|
|
|
typeof this.queryParams !== 'undefined' &&
|
|
|
|
typeof this.queryParams.searchproperty !== 'undefined'
|
|
|
|
) {
|
|
|
|
model.searchProperties = this.queryParams.searchproperty.empty[0];
|
|
|
|
}
|
|
|
|
return model;
|
|
|
|
}
|
|
|
|
|
2020-10-19 16:30:30 +00:00
|
|
|
/**
|
|
|
|
* Set the routeName for the controller so that it is available in the template
|
|
|
|
* for the route/controller.. This is mainly used to give a route name to the
|
|
|
|
* Outlet component
|
|
|
|
*/
|
2020-10-01 08:33:22 +00:00
|
|
|
setupController(controller, model) {
|
|
|
|
setProperties(controller, {
|
2021-09-15 18:50:11 +00:00
|
|
|
...model,
|
2020-10-01 08:33:22 +00:00
|
|
|
routeName: this.routeName,
|
|
|
|
});
|
|
|
|
super.setupController(...arguments);
|
|
|
|
}
|
2021-02-19 16:42:16 +00:00
|
|
|
|
2021-05-26 16:43:46 +00:00
|
|
|
optionalParams() {
|
|
|
|
return this.container.get(`location:${this.env.var('locationType')}`).optionalParams();
|
|
|
|
}
|
|
|
|
|
2020-10-19 16:30:30 +00:00
|
|
|
/**
|
|
|
|
* Adds urldecoding to any wildcard route `params` passed into ember `model`
|
|
|
|
* hooks, plus of course anywhere else where `paramsFor` is used. This means
|
|
|
|
* the entire ember app is now changed so that all paramsFor calls returns
|
|
|
|
* urldecoded params instead of raw ones.
|
|
|
|
* For example we use this largely for URLs for the KV store:
|
|
|
|
* /kv/*key > /ui/kv/%25-kv-name/%25-here > key = '%-kv-name/%-here'
|
|
|
|
*/
|
|
|
|
paramsFor(name) {
|
|
|
|
const params = super.paramsFor(...arguments);
|
|
|
|
if (isWildcard(this.routeName)) {
|
|
|
|
return Object.keys(params).reduce(function(prev, item) {
|
|
|
|
if (typeof params[item] !== 'undefined') {
|
|
|
|
prev[item] = decodeURIComponent(params[item]);
|
|
|
|
} else {
|
|
|
|
prev[item] = params[item];
|
|
|
|
}
|
|
|
|
return prev;
|
|
|
|
}, {});
|
|
|
|
} else {
|
|
|
|
return params;
|
|
|
|
}
|
|
|
|
}
|
2021-09-15 18:50:11 +00:00
|
|
|
|
|
|
|
@action
|
|
|
|
async replaceWith(routeName, obj) {
|
|
|
|
await Promise.resolve();
|
|
|
|
let params = [];
|
|
|
|
if (typeof obj === 'string') {
|
|
|
|
params = [obj];
|
|
|
|
}
|
|
|
|
if (typeof obj !== 'undefined' && !Array.isArray(obj) && typeof obj !== 'string') {
|
|
|
|
params = Object.values(obj);
|
|
|
|
}
|
|
|
|
return super.replaceWith(routeName, ...params);
|
|
|
|
}
|
|
|
|
|
|
|
|
@action
|
|
|
|
async transitionTo(routeName, obj) {
|
|
|
|
await Promise.resolve();
|
|
|
|
let params = [];
|
|
|
|
if (typeof obj === 'string') {
|
|
|
|
params = [obj];
|
|
|
|
}
|
|
|
|
if (typeof obj !== 'undefined' && !Array.isArray(obj) && typeof obj !== 'string') {
|
|
|
|
params = Object.values(obj);
|
|
|
|
}
|
|
|
|
return super.transitionTo(routeName, ...params);
|
|
|
|
}
|
2020-10-01 08:33:22 +00:00
|
|
|
}
|