-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implement unattended helper functions (#172)
* implement unattended execution functions * validate unattended mode * fix lint errors * fix lint * update codacy exclude paths * update type definition * 2.15.0
- Loading branch information
1 parent
602a8c1
commit eabcef6
Showing
13 changed files
with
248 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { DataContext } from "./types"; | ||
import {ConfigurationBase} from '@themost/common'; | ||
|
||
export declare interface ConfigurableApplication { | ||
getConfiguration(): ConfigurationBase | ||
} | ||
|
||
export declare function executeInUnattendedMode(context: DataContext, func: (callback: (err?: Error) => void) => void, callback: (err?: Error) => void): void; | ||
export declare function executeInUnattendedModeAsync(context: DataContext, func: () => Promise<void>): Promise<void>; | ||
export declare function enableUnattendedExecution(app: ConfigurableApplication, account?: string): void; | ||
export declare function disableUnattendedExecution(app: ConfigurableApplication): void; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
var unattendedMode = Symbol('unattendedMode'); | ||
var {RandomUtils} = require('@themost/common'); | ||
|
||
/** | ||
* Execute a callable function with elevated privileges in unattended mode. | ||
* @param {import('./types').DataContext} context | ||
* @param {function(function(Error?): void)} callable | ||
* @param {function(Error?): void} callback | ||
* @returns {void} | ||
*/ | ||
function executeInUnattendedMode(context, callable, callback) { | ||
if (typeof callable !== 'function') { | ||
return callback(new Error('Unattended mode requires a callable function')); | ||
} | ||
// if the context is already in unattended mode | ||
if (context[unattendedMode]) { | ||
try { | ||
// execute callable function | ||
void callable(function (err) { | ||
return callback(err); | ||
}); | ||
} catch (err) { | ||
return callback(err); | ||
} | ||
} else { | ||
var interactiveUser; | ||
try { | ||
const account = context.getConfiguration().getSourceAt('settings/auth/unattendedExecutionAccount'); | ||
if (account == null) { | ||
return callback(new Error('The unattended execution account is not defined. The operation cannot be completed.')); | ||
} | ||
// enter unattended mode | ||
context[unattendedMode] = true; | ||
// get interactive user | ||
if (context.user) { | ||
interactiveUser = Object.assign({}, context.user); | ||
// set interactive user | ||
context.interactiveUser = interactiveUser; | ||
} | ||
if (account) { | ||
context.user = {name: account, authenticationType: 'Basic'}; | ||
} | ||
void callable(function (err) { | ||
// restore user | ||
if (interactiveUser) { | ||
context.user = Object.assign({}, interactiveUser); | ||
} | ||
delete context.interactiveUser; | ||
// exit unattended mode | ||
delete context[unattendedMode]; | ||
return callback(err); | ||
}); | ||
} catch (err) { | ||
// restore user | ||
if (interactiveUser) { | ||
context.user = Object.assign({}, interactiveUser); | ||
} | ||
delete context.interactiveUser; | ||
// exit unattended mode | ||
delete context[unattendedMode]; | ||
return callback(err); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Execute a callable function with elevated privileges in unattended mode. | ||
* @param {import('./types').DataContext} context | ||
* @param {function(): Promise<void>} callable | ||
* @returns {Promise<void>} | ||
*/ | ||
function executeInUnattendedModeAsync(context, callable) { | ||
return new Promise((resolve, reject) => { | ||
void executeInUnattendedMode(context, function (cb) { | ||
return callable().then(function () { | ||
return cb(); | ||
}).catch(function (err) { | ||
return cb(err); | ||
}); | ||
}, function (err) { | ||
if (err) { | ||
return reject(err); | ||
} | ||
return resolve(); | ||
}); | ||
}); | ||
} | ||
|
||
/** | ||
* Enables unattended mode | ||
* @param {{getConfiguration(): import('@themost/common').ConfigurationBase}} app | ||
* @param {string=} executionAccount | ||
*/ | ||
function enableUnattendedExecution(app, executionAccount) { | ||
app.getConfiguration().setSourceAt('settings/auth/unattendedExecutionAccount', executionAccount || RandomUtils.randomChars(14)); | ||
} | ||
/** | ||
* Disables unattended mode | ||
* @param {{getConfiguration(): import('@themost/common').ConfigurationBase}} app | ||
*/ | ||
function disableUnattendedExecution(app) { | ||
app.getConfiguration().setSourceAt('settings/auth/unattendedExecutionAccount', null); | ||
} | ||
|
||
module.exports = { | ||
executeInUnattendedMode, | ||
executeInUnattendedModeAsync, | ||
enableUnattendedExecution, | ||
disableUnattendedExecution | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
const {TraceUtils} = require('@themost/common'); | ||
const JestLogger = require('./jest.logger'); | ||
// noinspection JSCheckFunctionSignatures | ||
TraceUtils.useLogger(new JestLogger()); | ||
/* global jest */ | ||
jest.setTimeout(30000); |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
import {TestApplication, TestApplication2} from './TestApplication'; | ||
import { | ||
DataContext, | ||
disableUnattendedExecution, | ||
enableUnattendedExecution, | ||
executeInUnattendedModeAsync | ||
} from '@themost/data'; | ||
|
||
describe('UnattendedMode', () => { | ||
let app: TestApplication; | ||
let context: DataContext; | ||
beforeAll((done) => { | ||
app = new TestApplication2(); | ||
context = app.createContext(); | ||
return done(); | ||
}); | ||
afterAll(async () => { | ||
await context.finalizeAsync(); | ||
await app.finalize(); | ||
}); | ||
it('should execute in unattended mode', async () => { | ||
// set context user | ||
context.user = { | ||
name: '[email protected]' | ||
}; | ||
const items = await context.model('Order').where<any>( | ||
(x) => x.orderedItem.name === 'Razer Blade (2013)' | ||
).getItems(); | ||
expect(items.length).toBeFalsy(); | ||
await executeInUnattendedModeAsync(context, async () => { | ||
expect(context.interactiveUser).toBeTruthy(); | ||
expect(context.interactiveUser.name).toEqual('[email protected]'); | ||
const items = await context.model('Order').where<any>( | ||
(x) => x.orderedItem.name === 'Razer Blade (2013)' | ||
).getItems(); | ||
expect(items.length).toBeTruthy(); | ||
}); | ||
expect(context.interactiveUser).toBeFalsy(); | ||
}); | ||
|
||
it('should execute in unattended mode and get error', async () => { | ||
// set context user | ||
context.user = { | ||
name: '[email protected]' | ||
}; | ||
await expect(executeInUnattendedModeAsync(context, async () => { | ||
throw new Error('Custom error'); | ||
})).rejects.toThrow(); | ||
expect(context.interactiveUser).toBeFalsy(); | ||
expect(context.user.name).toEqual('[email protected]'); | ||
}); | ||
|
||
it('should execute in unattended mode in series', async () => { | ||
// set context user | ||
context.user = { | ||
name: '[email protected]' | ||
}; | ||
await executeInUnattendedModeAsync(context, async () => { | ||
expect(context.interactiveUser).toBeTruthy(); | ||
const items = await context.model('Order').where<any>( | ||
(x) => x.orderedItem.name === 'Razer Blade (2013)' | ||
).getItems(); | ||
expect(items.length).toBeTruthy(); | ||
await executeInUnattendedModeAsync(context, async () => { | ||
expect(context.interactiveUser).toBeTruthy(); | ||
expect(context.interactiveUser.name).toEqual('[email protected]'); | ||
const items = await context.model('Order').where<any>( | ||
(x) => x.orderedItem.name === 'Sony VAIO Flip 15' | ||
).getItems(); | ||
expect(items.length).toBeTruthy(); | ||
}); | ||
}); | ||
expect(context.interactiveUser).toBeFalsy(); | ||
expect(context.user.name).toEqual('[email protected]'); | ||
}); | ||
|
||
it('should disable unattended execution', async () => { | ||
// set context user | ||
context.user = { | ||
name: '[email protected]' | ||
}; | ||
disableUnattendedExecution(app); | ||
expect(app.getConfiguration().getSourceAt('settings/auth/unattendedExecutionAccount')).toBeFalsy(); | ||
await expect(executeInUnattendedModeAsync(context, async () => { | ||
await context.model('Order').where<any>( | ||
(x) => x.orderedItem.name === 'Sony VAIO Flip 15' | ||
).getItems(); | ||
})).rejects.toThrow('The unattended execution account is not defined. The operation cannot be completed.'); | ||
expect(context.interactiveUser).toBeFalsy(); | ||
enableUnattendedExecution(app); | ||
expect(app.getConfiguration().getSourceAt('settings/auth/unattendedExecutionAccount')).toBeTruthy(); | ||
await executeInUnattendedModeAsync(context, async () => { | ||
const items = await context.model('Order').where<any>( | ||
(x) => x.orderedItem.name === 'Razer Blade (2013)' | ||
).getItems(); | ||
expect(items.length).toBeTruthy(); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,9 +18,12 @@ | |
"dom" | ||
], | ||
"paths": { | ||
"@themost/data": [ | ||
"./index" | ||
] | ||
} | ||
}, | ||
"exclude": [ | ||
"node_modules" | ||
] | ||
} | ||
} |