mirror of
https://github.com/getredash/redash.git
synced 2026-05-11 09:01:27 -04:00
* change has_access and require_access signatures to work with the objects that require access, instead of their groups
* change has_access and require_access signatures to work with the objects that require access, instead of their groups
* use the textless endpoint (/api/queries/:id/results) for pristine
queriest
* Revert "use the textless endpoint (/api/queries/:id/results) for pristine"
This reverts commit cd2cee7738.
* go to textless /api/queries/:id/results by default
* change `run_query`'s signature to accept a ParameterizedQuery instead of
constructing it inside
* raise HTTP 400 when receiving invalid parameter values. Fixes #3394
* support querystring params
* extract coercing of numbers to function, along with a friendlier
implementation
* wire embeds to textless endpoint
* allow users with view_only permissions to execute queries on the
textless endpoint, as it only allows safe queries to run
* enqueue jobs for ApiUsers
* add parameters component for embeds
* include existing parameters in embed code
* fetch correct values for json requests
* remove previous embed parameter code
* rename `id` to `user_id`
* support executing queries using Query api_keys by instantiating an ApiUser that would be able to execute the specific query
* bring back ALLOW_PARAMETERS_IN_EMBEDS (with link on deprecation coming up)
* show deprecation messages for ALLOW_PARAMETERS_IN_EMBEDS. Also, move
other message (email not verified) to use the same mechanism
* add link to forum message on setting deprecation
* rephrase deprecation message
* add link to forum message regarding embed deprecation
* change API to /api/queries/:id/dropdowns/:dropdown_id
* split to 2 different dropdown endpoints and implement the second
* add test cases for /api/queries/:id/dropdowns/:id
* use new /dropdowns endpoint in frontend
* first e2e test for sharing embeds
* Pleasing the CodeClimate overlords
* All glory to CodeClimate
* change has_access and require_access signatures to work with the objects that require access, instead of their groups
* split has_access between normal users and ApiKey users
* remove residues from bad rebase
* allow access to safe queries via api keys
* rename `object` to `obj`
* support both objects and group dicts in `has_access` and `require_access`
* simplify permission tests once `has_access` accepts groups
* change has_access and require_access signatures to work with the objects that require access, instead of their groups
* rename `object` to `obj`
* support both objects and group dicts in `has_access` and `require_access`
* simplify permission tests once `has_access` accepts groups
* fix bad rebase
* send embed parameters through POST data
* no need to log `is_api_key`
* move query fetching by api_key to within the Query model
* fetch user by adding a get_by_id function on the User model
* pass parameters as POST data (fixes test failure introduced by switching
from query string parameters to POST data)
* test the right thing - queries with safe parameters should be embeddable
* introduce cy.clickThrough
* add another Cypress test to make sure unsafe queries cannot be embedded
* serialize Parameters into query string
* set is_api_key as the last parameter to (hopefully) avoid
backward-dependency problems
* Update redash/models/parameterized_query.py
Co-Authored-By: rauchy <omer@rauchy.net>
* attempt to fix empty percy snapshots
* snap percies after DOM is fully loaded
129 lines
3.3 KiB
JavaScript
129 lines
3.3 KiB
JavaScript
import debug from 'debug';
|
|
import { includes, extend } from 'lodash';
|
|
|
|
// eslint-disable-next-line import/no-mutable-exports
|
|
export let Auth = null;
|
|
|
|
export const currentUser = {
|
|
canEdit(object) {
|
|
const userId = object.user_id || (object.user && object.user.id);
|
|
return this.hasPermission('admin') || (userId && userId === this.id);
|
|
},
|
|
|
|
hasPermission(permission) {
|
|
return includes(this.permissions, permission);
|
|
},
|
|
|
|
get isAdmin() {
|
|
return this.hasPermission('admin');
|
|
},
|
|
};
|
|
|
|
export const clientConfig = {};
|
|
export const messages = [];
|
|
|
|
const logger = debug('redash:auth');
|
|
const session = { loaded: false };
|
|
|
|
function updateSession(sessionData) {
|
|
logger('Updating session to be:', sessionData);
|
|
extend(session, sessionData, { loaded: true });
|
|
extend(currentUser, session.user);
|
|
extend(clientConfig, session.client_config);
|
|
extend(messages, session.messages);
|
|
}
|
|
|
|
function AuthService($window, $location, $q, $http) {
|
|
return {
|
|
isAuthenticated() {
|
|
return session.loaded && session.user.id;
|
|
},
|
|
login() {
|
|
const next = encodeURI($location.url());
|
|
logger('Calling login with next = %s', next);
|
|
window.location.href = `login?next=${next}`;
|
|
},
|
|
logout() {
|
|
logger('Logout.');
|
|
$window.location.href = 'logout';
|
|
},
|
|
loadSession() {
|
|
logger('Loading session');
|
|
if (session.loaded && session.user.id) {
|
|
logger('Resolving with local value.');
|
|
return $q.resolve(session);
|
|
}
|
|
|
|
this.setApiKey(null);
|
|
return $http.get('api/session').then((response) => {
|
|
updateSession(response.data);
|
|
return session;
|
|
});
|
|
},
|
|
loadConfig() {
|
|
logger('Loading config');
|
|
return $http.get('/api/config').then((response) => {
|
|
updateSession({ client_config: response.data.client_config, user: { permissions: [] }, messages: [] });
|
|
return response.data;
|
|
});
|
|
},
|
|
setApiKey(apiKey) {
|
|
logger('Set API key to: %s', apiKey);
|
|
this.apiKey = apiKey;
|
|
},
|
|
getApiKey() {
|
|
return this.apiKey;
|
|
},
|
|
requireSession() {
|
|
logger('Requested authentication');
|
|
if (this.isAuthenticated()) {
|
|
return $q.when(session);
|
|
}
|
|
return this.loadSession()
|
|
.then(() => {
|
|
if (this.isAuthenticated()) {
|
|
logger('Loaded session');
|
|
return session;
|
|
}
|
|
logger('Need to login, redirecting');
|
|
this.login();
|
|
})
|
|
.catch(() => {
|
|
logger('Need to login, redirecting');
|
|
this.login();
|
|
});
|
|
},
|
|
};
|
|
}
|
|
|
|
function apiKeyHttpInterceptor($injector) {
|
|
return {
|
|
request(config) {
|
|
const apiKey = $injector.get('Auth').getApiKey();
|
|
if (apiKey) {
|
|
config.headers.Authorization = `Key ${apiKey}`;
|
|
}
|
|
|
|
return config;
|
|
},
|
|
};
|
|
}
|
|
|
|
export default function init(ngModule) {
|
|
ngModule.factory('Auth', AuthService);
|
|
ngModule.value('currentUser', currentUser);
|
|
ngModule.value('clientConfig', clientConfig);
|
|
ngModule.value('messages', messages);
|
|
ngModule.factory('apiKeyHttpInterceptor', apiKeyHttpInterceptor);
|
|
|
|
ngModule.config(($httpProvider) => {
|
|
$httpProvider.interceptors.push('apiKeyHttpInterceptor');
|
|
});
|
|
|
|
ngModule.run(($injector) => {
|
|
Auth = $injector.get('Auth');
|
|
});
|
|
}
|
|
|
|
init.init = true;
|