send session variables in event trigger payload (close #1328) (#1458)

This commit is contained in:
Tirumarai Selvan 2019-01-28 11:42:52 +05:30 committed by Vamshi Surabhi
parent 81c950ecc5
commit e590144d02
6 changed files with 114 additions and 51 deletions

View File

@ -23,10 +23,11 @@ JSON payload
{
"event": {
"session_variables": <session-variables>,
"op": "<op-name>",
"data": {
"old": <column-values>,
"new": <column-values>
"old": <column-values>,
"new": <column-values>
}
},
"created_at": "<timestamp>",
@ -48,6 +49,9 @@ JSON payload
* - Key
- Type
- Description
* - session-variables
- Object_ or NULL
- Key-value pairs of session variables (i.e. "x-hasura-\*" variables) and their values. NULL if no session variables found.
* - op-name
- OpName_
- Name of the operation. Can only be "INSERT", "UPDATE" or "DELETE"
@ -104,6 +108,11 @@ JSON payload
"name": "users"
},
"event": {
"session_variables": {
"x-hasura-role": "admin",
"x-hasura-allowed-roles": "['user', 'boo', 'admin']",
"x-hasura-user-id": "1"
},
"op": "INSERT",
"data": {
"old": null,

View File

@ -88,13 +88,13 @@ instance ToJSON Event where
$(deriveFromJSON (aesonDrop 1 snakeCase){omitNothingFields=True} ''Event)
data Request
= Request
data WebhookRequest
= WebhookRequest
{ _rqPayload :: Value
, _rqHeaders :: Maybe [HeaderConf]
, _rqVersion :: T.Text
}
$(deriveToJSON (aesonDrop 3 snakeCase){omitNothingFields=True} ''Request)
$(deriveToJSON (aesonDrop 3 snakeCase){omitNothingFields=True} ''WebhookRequest)
data WebhookResponse
= WebhookResponse
@ -117,7 +117,7 @@ data Invocation
= Invocation
{ iEventId :: EventId
, iStatus :: Int
, iRequest :: Request
, iRequest :: WebhookRequest
, iResponse :: Response
}
@ -338,8 +338,8 @@ tryWebhook logenv pool e = do
where
decodeBS = TE.decodeUtf8With TE.lenientDecode
mkWebhookReq :: Value -> [HeaderConf] -> Request
mkWebhookReq payload headers = Request payload (mkMaybe headers) invocationVersion
mkWebhookReq :: Value -> [HeaderConf] -> WebhookRequest
mkWebhookReq payload headers = WebhookRequest payload (mkMaybe headers) invocationVersion
mkResp :: Int -> TBS.TByteString -> [HeaderConf] -> Response
mkResp status payload headers =

View File

@ -7,8 +7,20 @@ CREATE OR REPLACE function hdb_views.{{QUALIFIED_TRIGGER_NAME}}() RETURNS trigge
_new record;
_data json;
payload json;
session_variables json;
server_version_num int;
BEGIN
id := gen_random_uuid();
server_version_num := current_setting('server_version_num');
IF server_version_num >= 90600 THEN
session_variables := current_setting('hasura.user', 't');
ELSE
BEGIN
session_variables := current_setting('hasura.user');
EXCEPTION WHEN OTHERS THEN
session_variables := NULL;
END;
END IF;
IF TG_OP = 'UPDATE' THEN
_old := {{OLD_ROW}};
_new := {{NEW_ROW}};
@ -23,7 +35,8 @@ CREATE OR REPLACE function hdb_views.{{QUALIFIED_TRIGGER_NAME}}() RETURNS trigge
);
payload := json_build_object(
'op', TG_OP,
'data', _data
'data', _data,
'session_variables', session_variables
)::text;
IF (TG_OP <> 'UPDATE') OR (_old <> _new) THEN
INSERT INTO

View File

@ -137,8 +137,8 @@ class HGECtx:
)
return resp.status_code, resp.json()
def v1q(self, q):
h = dict()
def v1q(self, q, headers = {}):
h = headers.copy()
if self.hge_key is not None:
h['X-Hasura-Access-Key'] = self.hge_key
resp = self.http.post(

View File

@ -21,7 +21,7 @@ def select_last_event_fromdb(hge_ctx):
return st_code, resp
def insert(hge_ctx, table, row, returning=[]):
def insert(hge_ctx, table, row, returning=[], headers = {}):
q = {
"type": "insert",
"args": {
@ -30,11 +30,11 @@ def insert(hge_ctx, table, row, returning=[]):
"returning": returning
}
}
st_code, resp = hge_ctx.v1q(q)
st_code, resp = hge_ctx.v1q(q, headers = headers)
return st_code, resp
def update(hge_ctx, table, where_exp, set_exp):
def update(hge_ctx, table, where_exp, set_exp, headers = {}):
q = {
"type": "update",
"args": {
@ -43,11 +43,11 @@ def update(hge_ctx, table, where_exp, set_exp):
"$set": set_exp
}
}
st_code, resp = hge_ctx.v1q(q)
st_code, resp = hge_ctx.v1q(q, headers = headers)
return st_code, resp
def delete(hge_ctx, table, where_exp):
def delete(hge_ctx, table, where_exp, headers = {}):
q = {
"type": "delete",
"args": {
@ -55,7 +55,7 @@ def delete(hge_ctx, table, where_exp):
"where": where_exp
}
}
st_code, resp = hge_ctx.v1q(q)
st_code, resp = hge_ctx.v1q(q, headers = headers)
return st_code, resp
class TestCreateAndDelete(DefaultTestQueries):
@ -89,10 +89,9 @@ class TestCreateEvtQuery(object):
"old": None,
"new": init_row
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -102,7 +101,7 @@ class TestCreateEvtQuery(object):
}
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data)
exp_ev_data = {
"old": {"c1": 1, "c2": "world"},
@ -110,7 +109,7 @@ class TestCreateEvtQuery(object):
}
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data)
class TestRetryConf(object):
@ -132,7 +131,6 @@ class TestRetryConf(object):
"old": None,
"new": init_row
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
time.sleep(15)
@ -162,7 +160,7 @@ class TestEvtHeaders(object):
headers = {"X-Header-From-Value": "MyValue", "X-Header-From-Env": "MyEnvValue"}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data, headers = headers)
class TestUpdateEvtQuery(object):
@ -186,11 +184,10 @@ class TestUpdateEvtQuery(object):
"old": None,
"new": {"c1": 1, "c2": "hello"}
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_cols", table, "INSERT", exp_ev_data, headers, "/new")
check_event(hge_ctx, "t1_cols", table, "INSERT", exp_ev_data, webhook_path = "/new")
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -198,7 +195,7 @@ class TestUpdateEvtQuery(object):
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data, headers, "/new")
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data, webhook_path = "/new")
where_exp = {"c1": 1}
set_exp = {"c1": 2}
@ -208,7 +205,7 @@ class TestUpdateEvtQuery(object):
}
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data, headers, "/new")
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data, webhook_path ="/new")
where_exp = {"c1": 2}
exp_ev_data = {
@ -217,7 +214,7 @@ class TestUpdateEvtQuery(object):
}
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_cols", table, "DELETE", exp_ev_data, headers, "/new")
check_event(hge_ctx, "t1_cols", table, "DELETE", exp_ev_data, webhook_path = "/new")
class TestDeleteEvtQuery(object):
@ -241,11 +238,10 @@ class TestDeleteEvtQuery(object):
"old": None,
"new": init_row
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -256,7 +252,7 @@ class TestDeleteEvtQuery(object):
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data)
exp_ev_data = {
"old": {"c1": 1, "c2": "world"},
@ -265,7 +261,7 @@ class TestDeleteEvtQuery(object):
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data)
class TestEvtSelCols:
@ -287,10 +283,9 @@ class TestEvtSelCols:
"old": None,
"new": {"c1": 1, "c2": "hello"}
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
check_event(hge_ctx, "t1_cols", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_cols", table, "INSERT", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -298,7 +293,7 @@ class TestEvtSelCols:
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c1": 2}
@ -308,7 +303,7 @@ class TestEvtSelCols:
}
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_cols", table, "UPDATE", exp_ev_data)
where_exp = {"c1": 2}
exp_ev_data = {
@ -317,7 +312,7 @@ class TestEvtSelCols:
}
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_cols", table, "DELETE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_cols", table, "DELETE", exp_ev_data)
def test_selected_cols_dep(self, hge_ctx):
st_code, resp = hge_ctx.v1q({
@ -357,10 +352,9 @@ class TestEvtInsertOnly:
"old": None,
"new": init_row
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
check_event(hge_ctx, "t1_insert", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_insert", table, "INSERT", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -371,7 +365,7 @@ class TestEvtInsertOnly:
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_insert", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_insert", table, "UPDATE", exp_ev_data)
exp_ev_data = {
"old": {"c1": 1, "c2": "world"},
@ -380,7 +374,7 @@ class TestEvtInsertOnly:
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
with pytest.raises(queue.Empty):
check_event(hge_ctx, "t1_insert", table, "DELETE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_insert", table, "DELETE", exp_ev_data)
class TestEvtSelPayload:
@ -402,10 +396,9 @@ class TestEvtSelPayload:
"old": None,
"new": {"c1": 1, "c2": "hello"}
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
check_event(hge_ctx, "t1_payload", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_payload", table, "INSERT", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -415,7 +408,7 @@ class TestEvtSelPayload:
}
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_payload", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_payload", table, "UPDATE", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c1": 2}
@ -425,7 +418,7 @@ class TestEvtSelPayload:
}
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_payload", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_payload", table, "UPDATE", exp_ev_data)
where_exp = {"c1": 2}
exp_ev_data = {
@ -434,7 +427,7 @@ class TestEvtSelPayload:
}
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_payload", table, "DELETE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_payload", table, "DELETE", exp_ev_data)
def test_selected_payload_dep(self, hge_ctx):
st_code, resp = hge_ctx.v1q({
@ -474,10 +467,9 @@ class TestWebhookEnv(object):
"old": None,
"new": init_row
}
headers = {}
st_code, resp = insert(hge_ctx, table, init_row)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
@ -487,7 +479,7 @@ class TestWebhookEnv(object):
}
st_code, resp = update(hge_ctx, table, where_exp, set_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data)
exp_ev_data = {
"old": {"c1": 1, "c2": "world"},
@ -495,4 +487,48 @@ class TestWebhookEnv(object):
}
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data, headers, "/")
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data)
class TestSessionVariables(object):
@pytest.fixture(autouse=True)
def transact(self, request, hge_ctx):
print("In setup method")
st_code, resp = hge_ctx.v1q_f('queries/event_triggers/basic/setup.yaml')
assert st_code == 200, resp
yield
st_code, resp = hge_ctx.v1q_f('queries/event_triggers/basic/teardown.yaml')
assert st_code == 200, resp
def test_basic(self, hge_ctx):
table = {"schema": "hge_tests", "name": "test_t1"}
init_row = {"c1": 1, "c2": "hello"}
exp_ev_data = {
"old": None,
"new": init_row
}
session_variables = { 'x-hasura-role': 'admin', 'x-hasura-allowed-roles': "['admin','user']", 'x-hasura-user-id': '1'}
st_code, resp = insert(hge_ctx, table, init_row, headers = session_variables)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "INSERT", exp_ev_data, session_variables = session_variables)
where_exp = {"c1": 1}
set_exp = {"c2": "world"}
exp_ev_data = {
"old": init_row,
"new": {"c1": 1, "c2": "world"}
}
session_variables = { 'x-hasura-role': 'admin', 'x-hasura-random': 'some_random_info', 'X-Random-Header': 'not_session_variable'}
st_code, resp = update(hge_ctx, table, where_exp, set_exp, headers = session_variables)
assert st_code == 200, resp
session_variables.pop('X-Random-Header')
check_event(hge_ctx, "t1_all", table, "UPDATE", exp_ev_data, session_variables = session_variables)
exp_ev_data = {
"old": {"c1": 1, "c2": "world"},
"new": None
}
st_code, resp = delete(hge_ctx, table, where_exp)
assert st_code == 200, resp
check_event(hge_ctx, "t1_all", table, "DELETE", exp_ev_data)

View File

@ -40,13 +40,18 @@ def validate_event_webhook(ev_webhook_path, webhook_path):
assert ev_webhook_path == webhook_path
def check_event(hge_ctx, trig_name, table, operation, exp_ev_data, headers, webhook_path):
def check_event(hge_ctx, trig_name, table, operation, exp_ev_data,
headers = {},
webhook_path = '/',
session_variables = {'x-hasura-role': 'admin'}
):
ev_full = hge_ctx.get_event(3)
validate_event_webhook(ev_full['path'], webhook_path)
validate_event_headers(ev_full['headers'], headers)
validate_event_payload(ev_full['body'], trig_name, table)
ev = ev_full['body']['event']
assert ev['op'] == operation, ev
assert ev['session_variables'] == session_variables, ev
assert ev['data'] == exp_ev_data, ev