Skip to content

Commit

Permalink
KZL-1005 - Add method to use request context in SDK queries (#1245)
Browse files Browse the repository at this point in the history
Adds a method to use the original request user inside the requests sent by the embedded SDK.
The main purpose of this feature is to properly set Kuzzle metadata (author and updater) on documents.

Call to sdk.as(user) method will instantiate a new SDK with a FunnelProcotol that takes the user in the constructor and inject it in the request context before passing the request to theFunnel.

// This will create a document with `author` metadata to `null`
this.context.accessors.sdk.document.create(...); 

// This will create a document with `author` metadata to the original request user
this.context.accessors.sdk.as(request.context.user).document.create(...);

// This will throw a PluginImplementationError, no user impersonation for now
this.context.accessors.sdk.as({ user: { _id: 'gordon' } }).document.create(...);
Documentation: kuzzleio/documentation#253
  • Loading branch information
Aschen authored and alexandrebouthinon committed Mar 20, 2019
1 parent 6fdc39f commit b65bb21
Show file tree
Hide file tree
Showing 5 changed files with 3,230 additions and 3,104 deletions.
47 changes: 34 additions & 13 deletions lib/api/core/plugins/pluginContext.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
const
Bluebird = require('bluebird'),
_ = require('lodash'),
User = require('../models/security/user'),
Koncorde = require('koncorde'),
KuzzleSDK = require('kuzzle-sdk').Kuzzle,
FunnelProtocol = require('../sdk/funnelProtocol'),
Expand Down Expand Up @@ -77,7 +78,7 @@ class PluginContext {
// forbids uppercased characters in index names.
internalEngineIndex = `%plugin:${pluginName}`.toLowerCase(),
pluginInternalEngine = new InternalEngine(kuzzle, internalEngineIndex),
sdk = new KuzzleSDK(new FunnelProtocol(kuzzle.funnel));
kuzzleSdk = new KuzzleSDK(new FunnelProtocol(kuzzle.funnel));

pluginInternalEngine.init(new PluginInternalEngineBootstrap(pluginName, kuzzle, pluginInternalEngine));

Expand Down Expand Up @@ -135,20 +136,40 @@ class PluginContext {
get: () => curryTrigger(kuzzle, pluginName)
});

const getPluginSdk = sdk => ({
query: sdk.query.bind(sdk),
auth: sdk.auth,
bulk: sdk.bulk,
collection: sdk.collection,
document: sdk.document,
index: sdk.index,
ms: sdk.ms,
realtime: new Proxy({}, {
get () {
throw new PluginImplementationError('Realtime controller is not available in plugins. You should use plugin hooks instead');
}
}),
security: sdk.security,
server: sdk.server
});

Object.defineProperty(this.accessors, 'sdk', {
enumerable: true,
get: () => ({
query: sdk.query.bind(sdk),
auth: sdk.auth,
bulk: sdk.bulk,
collection: sdk.collection,
document: sdk.document,
index: sdk.index,
ms: sdk.ms,
realtime: sdk.realtime,
security: sdk.security,
server: sdk.server
})
get: () => {
const pluginSdk = getPluginSdk(kuzzleSdk);

pluginSdk.as = user => {
if (!(user instanceof User)) {
throw new PluginImplementationError('You must provide a valid User object when adding context with as()');
}

return getPluginSdk(
new KuzzleSDK(new FunnelProtocol(kuzzle.funnel, user))
);
};

return pluginSdk;
}
});

/**
Expand Down
32 changes: 26 additions & 6 deletions lib/api/core/sdk/funnelProtocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,43 @@
'use strict';

const
KuzzleEventEmitter = require('kuzzle-sdk').KuzzleEventEmitter,
Request = require('kuzzle-common-objects').Request;
{
Request,
errors: {
InternalError: KuzzleInternalError
}
} = require('kuzzle-common-objects'),
User = require('../models/security/user'),
KuzzleEventEmitter = require('kuzzle-sdk').KuzzleEventEmitter;

class FunnelProtocol extends KuzzleEventEmitter {
constructor(funnel) {
constructor(funnel, user = null) {
super();

this.funnel = funnel;
this.id = 'funnel';
this.user = user;

if (this.user && !(this.user instanceof User)) {
throw new KuzzleInternalError(`FunnelProtocol.constructor: Invalid User object '${JSON.stringify(user)}'`);
}
}

isReady() {
isReady () {
return true;
}

/**
* Hydrate the user and execute SDK query
*/
query (request) {
return this.funnel.executePluginRequest(new Request(request))
.then(result => ({result}));
const kuzzleRequest = new Request(request, {
connection: { protocol: 'funnel' },
user: this.user
});

return this.funnel.executePluginRequest(kuzzleRequest)
.then(result => ({ result }));
}
}

Expand Down
Loading

0 comments on commit b65bb21

Please sign in to comment.