feat: SAS services & tests for RESTORE, #84

This commit is contained in:
^ 2024-04-30 00:20:40 +01:00
parent ec7615e7e3
commit 9ad7ae47b5
12 changed files with 537 additions and 113 deletions

29
sas/package-lock.json generated
View File

@ -7,7 +7,7 @@
"name": "dc-sas",
"dependencies": {
"@sasjs/cli": "^4.11.1",
"@sasjs/core": "^4.49.0"
"@sasjs/core": "^4.51.3"
}
},
"node_modules/@coolaj86/urequest": {
@ -116,9 +116,9 @@
"integrity": "sha512-Grwydm5GxBsYk238PZw41XPjXVVQ9vWcvfZ06L2P0bQbvK0sGn7l69JA7H5MGr3QcaLpiD4Kg70cAh7PgE+JOw=="
},
"node_modules/@sasjs/core": {
"version": "4.49.0",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.49.0.tgz",
"integrity": "sha512-hp3Hb4DkT6FmowyNHTOvSlgmSObW9WeuTJj+TQlwPgnBo59mAB4XFUnUaYSA+7ghvsHqUZf1OP2eSYqmnN5swQ=="
"version": "4.51.3",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.51.3.tgz",
"integrity": "sha512-ATc6+Mk0oEN14Ih9jZYJAuNhU4wcXqDgD3oKGnCvW/jVVcMNRNuQlh6O2bBR9H31DnCW7W94MxhtPHud786+tg=="
},
"node_modules/@sasjs/lint": {
"version": "2.3.1",
@ -229,6 +229,12 @@
"@types/node": "*"
}
},
"node_modules/@types/tough-cookie": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
"peer": true
},
"node_modules/abab": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
@ -1828,9 +1834,9 @@
}
},
"@sasjs/core": {
"version": "4.49.0",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.49.0.tgz",
"integrity": "sha512-hp3Hb4DkT6FmowyNHTOvSlgmSObW9WeuTJj+TQlwPgnBo59mAB4XFUnUaYSA+7ghvsHqUZf1OP2eSYqmnN5swQ=="
"version": "4.51.3",
"resolved": "https://registry.npmjs.org/@sasjs/core/-/core-4.51.3.tgz",
"integrity": "sha512-ATc6+Mk0oEN14Ih9jZYJAuNhU4wcXqDgD3oKGnCvW/jVVcMNRNuQlh6O2bBR9H31DnCW7W94MxhtPHud786+tg=="
},
"@sasjs/lint": {
"version": "2.3.1",
@ -1927,6 +1933,12 @@
"@types/node": "*"
}
},
"@types/tough-cookie": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
"peer": true
},
"abab": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz",
@ -2953,7 +2965,8 @@
"ws": {
"version": "8.13.0",
"resolved": "https://registry.npmjs.org/ws/-/ws-8.13.0.tgz",
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA=="
"integrity": "sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==",
"requires": {}
},
"xml": {
"version": "1.0.1",

View File

@ -29,6 +29,6 @@
"private": true,
"dependencies": {
"@sasjs/cli": "^4.11.1",
"@sasjs/core": "^4.49.0"
"@sasjs/core": "^4.51.3"
}
}

View File

@ -0,0 +1,136 @@
/**
@file
@brief Checks if a user is able to restore a LOAD_REF
@details Not all LOAD_REFs can be restored - maybe the user does not have
permission, maybe the load was never loaded, or maybe the load was not
tracked.
The macro creates two output (global) macro variables.
@param [in] LOAD_REF The Load Reference to check
@param [out] outresult= (ALLOW_RESTORE) Output macro variable NAME. Will be
given the value of YES or NO depending on whether the user is allowed to
restore the load ref.
@param [out] outreason= (REASON) Output macro variable NAME.
Will be populated with the reason for which the restore decision was made.
<h4> SAS Macros </h4>
@li mf_nobs.sas
@li mf_getuser.sas
@li mpe_accesscheck.sas
@li mpe_getgroups.sas
<h4> Related Macros </h4>
@li mpe_checkrestore.test.sas
@version 9.2
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
%macro mpe_checkrestore(load_ref,
outresult=ALLOW_RESTORE,
outreason=REASON
);
%global &outresult &outreason;
%let &outresult=NO;
%let &outreason=NOTFOUND;
/* grab user groups */
%local user;
%let user=%mf_getuser();
%mpe_getgroups(user=&user,outds=work.groups)
/* check if user is admin */
%local is_admin;
%let is_admin=0;
proc sql;
select count(*) into: is_admin from work.groups
where groupname="&dc_admin_group";
%if &is_admin>0 %then %do;
%let allow_restore=YES;
%let reason=IS ADMIN;
%return;
%end;
/* check if user has basic access */
%local libds;
proc sql noprint;
select cats(base_lib,'.',base_ds) into: libds
from &mpelib..mpe_submit
where TABLE_ID="&load_ref";
%mpe_accesscheck(&libds,outds=work.access_check
,user=&user
,access_level=EDIT
)
%if %mf_nobs(access_check)=0 %then %do;
%let allow_restore=NO;
%let reason=No access in MPE_TABLES;
%return;
%end;
/* check if user has column level security rules */
proc sql;
create table work.cls_rules as
select *
from &mpelib..mpe_column_level_security
where &dc_dttmtfmt. lt tx_to
and CLS_SCOPE in ("EDIT",'ALL')
and CLS_ACTIVE=1
and upcase(CLS_GROUP) in (select upcase(groupname) from work.groups)
and CLS_LIBREF="%upcase(&base_lib)"
and CLS_TABLE="%upcase(&base_ds)";
%if %mf_nobs(work.cls_rules)>0 %then %do;
%let allow_restore=NO;
%let reason=User has restrictions in MPE_COLUMN_LEVEL_SECURITY;
data _null_;
set work.cls_rules;
putlog (_all_)(=);
if _n_>5 then stop;
run;
%return;
%end;
/* check if user has row level security rules */
proc sql;
create table work.rls_rules as
select *
from &mpelib..mpe_row_level_security
where &dc_dttmtfmt. lt tx_to
and rls_scope in ("EDIT",'ALL')
and upcase(rls_group) in (select upcase(groupname) from work.groups)
and rls_libref="&base_lib"
and rls_table="&base_ds"
and rls_active=1;
%if %mf_nobs(work.rls_rules)>0 %then %do;
%let allow_restore=NO;
%let reason=User has restrictions in MPE_ROW_LEVEL_SECURITY;
data _null_;
set work.rls_rules;
putlog (_all_)(=);
if _n_>5 then stop;
run;
%return;
%end;
%else %do;
/* check if there is actually a version to restore */
%local chk;
%let chk=0;
proc sql noprint;
select count(*) into: chk from &dc_libref..mpe_audit
where load_ref="&table";
%if &chk=0 %then %do;
%let allow_restore=NO;
%let reason=No entry for &table in MPE_AUDIT;
%end;
%else %do;
%let allow_restore=YES;
%let reason=CHECKS PASSED;
%end;
%return;
%end;
%mend mpe_checkrestore;

View File

@ -0,0 +1,59 @@
/**
@file
@brief Testing mpe_checkrestore macro
@details Checking functionality of mpe_checkrestore.sas macro
<h4> SAS Macros </h4>
@li dc_getsettings.sas
@li mpe_checkrestore.sas
@li mp_assert.sas
@li mp_assertscope.sas
@li mp_testservice.sas
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
/* first, run a data update */
%mp_testservice(&appLoc/tests/services/auditors/postdata.test.1,
viyacontext=&defaultcontext
)
/* now grab the latest update */
%let loadref=0;
data APPROVE1;
set &mpelib..mpe_submit end=last;
if last then call symputx('loadref',table_id);
run;
%global dc_repo_users dc_macros dc_libref dc_staging_area dc_admin_group
mpelib dc_dttmtfmt;
%dc_getsettings()
%put checking it is restorable;
%global allow_restore reason;
%mp_assertscope(SNAPSHOT)
%mpe_checkrestore(&loadref,outresult=ALLOW_RESTORE,outreason=REASON)
%mp_assertscope(COMPARE,
desc=Checking macro variables against previous snapshot,
ignorelist=ALLOW_RESTORE REASON
MCLIB0_JADP1LEN MCLIB0_JADP2LEN MCLIB0_JADPNUM MCLIB0_JADVLEN
MCLIB2_JADP1LEN MCLIB2_JADP2LEN MCLIB2_JADPNUM MCLIB2_JADVLEN
)
%mp_assert(
iftrue=(&syscc=0),
desc=Checking successful submission
)
%mp_assert(
iftrue=(&ALLOW_RESTORE=YES),
desc=Checking restoring is possible
)
%mp_assert(
iftrue=(&REASON=IS ADMIN),
desc=Checking reason code returned
)

View File

@ -387,7 +387,7 @@ run;
/* get log back */
proc printto log=&logloc;run;
data _null_; infile tmp; input; putlog _infile_;run;
/* scan log for invalid data warning */
/* scan log for invalid data warnings */
data _null_;
infile tmp;
input;

View File

@ -33,7 +33,8 @@
dc_activation_key /* extracted in dc_getsettings */
dc_locale /* extracted in dc_getsettings */
dc_dttmtfmt /* can be overridden in dc_getsettings */
_debug
_debug /* automatic variable when provided in URL */
sasjs_mdebug /* used to show extra info when _debug is enabled */
;
%if &mpeinit=1 %then %return;
@ -110,4 +111,9 @@ run;
,msg=%str(Problem during compilation or with STP precode (&syswarningtext))
)
%if "&_debug"="2477" or "&_debug"="fields,log,trace" or "&_debug"="131"
%then %do;
%let sasjs_mdebug=1;
%end;
%mend mpeinit;

View File

@ -233,7 +233,7 @@
"streamWeb": true,
"streamWebFolder": "web",
"webSourcePath": "../client/dist",
"streamServiceName": "DataController",
"streamServiceName": "DataController2",
"streamLogo": "favicon.ico",
"assetPaths": []
}

View File

@ -34,12 +34,18 @@ data work.jsdata;
SOME_DATETIME=put(dttm2,datetime19.);
some_time=put(tm2,time.);
drop dt2 dttm2 tm2;
_____DELETE__THIS__RECORD_____='No';
if _n_=1 then do;
primary_key_field=sum(&maxpk,1);
some_char=' leadingblanks';
some_num=._;
_____DELETE__THIS__RECORD_____='Yes';
output;
_____DELETE__THIS__RECORD_____='No';
do i=&maxpk to 5;
/* modify 1 record and add 4 more */
primary_key_field=i;
some_char=' leadingblanks';
some_num=ranuni(0);
some_bestnum=._;
output;
end;
end;
else stop;
run;
@ -52,7 +58,7 @@ run;
)
%let status=0;
data work.sasparams;
data _null_;
set web1.sasparams;
putlog (_all_)(=);
if status='SUCCESS' then call symputx('status',1);
@ -91,7 +97,7 @@ data _null_;
/* the JSON libname engine removes leading blanks!!!! */
if index(_infile_,' leadingblanks') then call symputx('leadcheck',1);
/* there is no clean way to send a special missing - so is sent as string */
if index(_infile_,',"SOME_NUM":"_"') then call symputx('speshcheck',1);
if index(_infile_,',"SOME_BESTNUM":"_"') then call symputx('speshcheck',1);
run;
@ -103,3 +109,32 @@ run;
iftrue=(&leadcheck=1),
desc=Checking special characters were applied
)
/* Now actually approve the table */
data work.sascontroltable;
ACTION='APPROVE_TABLE';
TABLE="&dsid";
/* difftime is numeric for approve action */
DIFFTIME="%sysfunc(datetime())";
output;
stop;
run;
%mx_testservice(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web3,
outref=wb3,
mdebug=&sasjs_mdebug
)
%let status=0;
data _null_;
set web3.apparams;
putlog (_all_)(=);
if response='SUCCESS!' then call symputx('status',1);
run;
%mp_assert(
iftrue=(&status=1 and &syscc=0),
desc=Checking successful submission
)

View File

@ -0,0 +1,152 @@
/**
@file restore.sas
@brief Restores a data version
@details Only applies if the history is stored in the audit table
<h4> SAS Macros </h4>
@li dc_assignlib.sas
@li mf_nobs.sas
@li mp_abort.sas
@li mp_ds2csv.sas
@li mp_stripdiffs.sas
@li mpeinit.sas
@li mpe_checkrestore.sas
@li mpe_loader.sas
<h4> Service Inputs </h4>
<h5> restore_in </h5>
|LOAD_REF:$32|
|---|
|DCXXXXXX|
@version 9.2
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
and may not be re-distributed or re-sold without the express permission of
4GL Apps Ltd.
**/
%mpeinit()
%let loadref=;
data _null_;
set work.restore_in;
call symputx('loadref',load_ref);
run;
/**
* Check if user has basic access permission to RESTORE the table
*/
%put checking access;
%global allow_restore reason;
%mpe_checkrestore(&loadref,outresult=ALLOW_RESTORE,outreason=REASON)
%mp_abort(iftrue= (&ALLOW_RESTORE ne YES)
,mac=&_program..sas
,msg=%str(Cannot restore because: &reason)
)
/* grab the base DS */
proc sql noprint;
select cats(base_lib,'.',base_ds) into: tgtds
from &mpelib..mpe_submit
where TABLE_ID="&loadref";
/* find the audit table */
select coalescec(audit_libds,"&mpelib..MPE_AUDIT") into: difftable
from &mpelib..MPE_TABLES
where libref="%scan(&tgtds,1,.)"
& dsn="%scan(&tgtds,2,.)"
& &dc_dttmtfmt<tx_to;
%mp_abort(iftrue= ("&difftable"="0")
,mac=&_program..sas
,msg=%str(No audit table configured for &tgtds)
)
/* assign the library */
%dc_assignlib(READ,%scan(&tgtds,1,.))
/* extract the differences to be applied */
%mp_stripdiffs(&tgtds,&loadref,&difftable
,outds=work.mp_stripdiffs
,mdebug=&sasjs_mdebug
)
/* abort if any issues */
%mp_abort(iftrue= (&syscc>0)
,mac=&_program..sas
,msg=%str(syscc=&syscc after stripdiffs)
)
%mp_abort(iftrue= (%mf_nobs(work.mp_stripdiffs)=0)
,mac=&_program..sas
,msg=%str(THERE ARE NO DIFFERENCES TO APPLY)
)
/* create a new load ref */
%let mperef=DC%left(%sysfunc(datetime(),B8601DT19.3))_%substr(
%sysfunc(ranuni(0)),3,6)_%substr(%str(&sysjobid ),1,4);
/* Create package folder */
%let dir=&mpelocapprovals/&mperef;
%mf_mkdir(&dir)
options notes mprint;
libname approve "&dir";
/* take copy of macvars */
data _null_;
file "&dir/macvars.sas";
set sashelp.vmacro;
where scope='GLOBAL';
put '%let ' name '=' value ';';
run;
/* copy the diffs dataset */
data approve.jsdset;
length _____DELETE__THIS__RECORD_____ $3;
if 0 then call missing(_____DELETE__THIS__RECORD_____);
set work.mp_stripdiffs;
run;
/* export to csv */
%mp_ds2csv(approve.jsdset
,dlm=COMMA
,outfile="&dir/%trim(&tgtds).csv"
,outencoding="UTF-8"
,headerformat=NAME
,termstr=CRLF
)
%mp_abort(iftrue= (&syscc ne 0)
,mac=&_program
,msg=%str(syscc=&syscc when writing the CSV)
)
%mpe_loader(mperef=&mperef
,submitted_reason_txt=Restoring &loadref
,dc_dttmtfmt=&dc_dttmtfmt
)
%mp_abort(mode=INCLUDE)
%mp_abort(
iftrue=(%sysfunc(fileexist(%sysfunc(pathname(work))/mf_abort.error))=1)
,mac=&_program..sas
,msg=%str(mf_abort.error=1)
)
%mp_abort(iftrue= (&syscc ne 0)
,mac=&_program..sas
,msg=%str(syscc=&syscc)
)
/* send relevant SUCCESS values */
data work.restore_out;
loadref="&mperef";
run;
%webout(OPEN)
%webout(OBJ,restore_out)
%webout(CLOSE)

View File

@ -0,0 +1,109 @@
/**
@file
@brief testing restore process
<h4> SAS Macros </h4>
@li mf_getuniquefileref.sas
@li mx_testservice.sas
@li mp_assert.sas
**/
%let _program=&appLoc/services/editors/restore;
/* take a snapshot of the table for later comparison */
proc sort data=&mpelib..mpe_x_test out=work.origds;
by primary_key_field;
run;
/* run an update */
%mx_testservice(&appLoc/tests/services/auditors/postdata.test.1,
viyacontext=&defaultcontext
)
/* grab the loadref for later reversion */
%let loadref=0;
data APPROVE1;
set &mpelib..mpe_submit end=last;
if last then call symputx('loadref',table_id);
run;
/* run another update for good measure */
%mx_testservice(&appLoc/tests/services/auditors/postdata.test.1,
viyacontext=&defaultcontext
)
/* now we are ready to revert */
data work.restore_in;
load_ref="&loadref";
output;
stop;
run;
%mx_testservice(&_program,
viyacontext=&defaultcontext,
inputdatasets=work.restore_in,
outlib=web1,
mdebug=&sasjs_mdebug
)
/* check for success */
%let loadref=0;
data work.restore_out;
set web1.restore_out;
putlog (_all_)(=);
call symputx('newref',loadref);
run;
%mp_assert(
iftrue=(&newref ne 0),
desc=Checking successful submission of a reversion,
outds=work.test_results
)
/* approve the reversion */
data work.sascontroltable;
ACTION='APPROVE_TABLE';
TABLE="&newref";
/* difftime is numeric for approve action */
DIFFTIME="%sysfunc(datetime())";
output;
stop;
run;
%mx_testservice(&appLoc/services/auditors/postdata,
viyacontext=&defaultcontext,
inputdatasets=work.sascontroltable,
outlib=web3,
outref=wb3,
mdebug=&sasjs_mdebug
)
%let status=0;
data _null_;
set web3.apparams;
putlog (_all_)(=);
if response='SUCCESS!' then call symputx('status',1);
run;
%mp_assert(
iftrue=(&status=1 and &syscc=0),
desc=Checking successful submission of reversion
)
/* compare snapshot with latest data */
proc sort data=&mpelib..mpe_x_test out=work.compareds;
by primary_key_field;
run;
proc compare base=work.origds compare=work.compareds
out=work.resultds outnoequal;
run;
data _null_;
set work.resultds;
if &sasjs_mdebug=1 then putlog (_all_)(=);
if _n_>10 then stop;
run;
%mp_assert(
iftrue=(&sysinfo le 41),
desc=Checking compare of MPE_X_TEST,
outds=work.test_results
)

View File

@ -4,13 +4,9 @@
@details
<h4> SAS Macros </h4>
@li dc_assignlib.sas
@li mf_getengine.sas
@li mf_getuser.sas
@li mf_nobs.sas
@li mp_abort.sas
@li mpe_accesscheck.sas
@li mpe_getgroups.sas
@li mpe_checkrestore.sas
<h4> Service Inputs </h4>
<h5> sascontroltable </h5>
@ -25,6 +21,12 @@
@li allow_restore YES if a user can restore, else NO
@li REASON reason why a restore is / is no possible
<h4> Data Inputs </h4>
@li MPE_AUDIT
@li MPE_COLUMN_LEVEL_SECURITY
@li MPE_ROW_LEVEL_SECURITY
@li MPE_SUBMIT
@version 9.2
@author 4GL Apps Ltd
@copyright 4GL Apps Ltd. This code may only be used within Data Controller
@ -41,10 +43,6 @@ data _null_;
call symputx('table',table);
run;
%dc_assignlib(WRITE,%scan(&table,1,.))
%let max_ver_dttm=0;
data APPROVE1;
set &mpelib..mpe_submit
(rename=(SUBMITTED_ON_DTTM=submitted_on REVIEWED_ON_DTTM=REVIEWED_ON));
@ -52,7 +50,6 @@ data APPROVE1;
TABLE_NM=cats(base_lib,'.',base_ds);
BASE_TABLE=table_nm;
call symputx('base_lib',base_lib);
call symputx('base_ds',base_ds);
REVIEWED_ON_DTTM=put(reviewed_on,datetime19.);
SUBMITTED_ON_DTTM=put(submitted_on,datetime19.);
run;
@ -61,91 +58,8 @@ run;
* Check if user has basic access permission to RESTORE the table
*/
%put checking access;
%global allow_restore reason;
%let allow_restore=NO;
%let reason=NOTFOUND;
%macro access_check();
/* grab user groups */
%let user=%mf_getuser();
%mpe_getgroups(user=&user,outds=work.groups)
/* check if user is admin */
%let is_admin=0;
proc sql;
select count(*) into: is_admin from work.groups where groupname="&MPEADMINS";
%if &is_admin>0 %then %do;
%let allow_restore=YES;
%let reason=IS ADMIN;
%return;
%end;
/* check if user has basic access */
%mpe_accesscheck(&base_lib..&base_ds,outds=work.access_check
,user=&user
,access_level=EDIT
)
%if %mf_nobs(access_check)=0 %then %do;
%let allow_restore=NO;
%let reason=No access in MPE_TABLES;
%return;
%end;
/* check if user has column level security rules */
proc sql;
create table work.cls_rules as
select *
from &mpelib..mpe_column_level_security
where &dc_dttmtfmt. lt tx_to
and CLS_SCOPE in ("EDIT",'ALL')
and CLS_ACTIVE=1
and upcase(CLS_GROUP) in (select upcase(groupname) from work.groups)
and CLS_LIBREF="%upcase(&base_lib)"
and CLS_TABLE="%upcase(&base_ds)";
%if %mf_nobs(work.cls_rules)>0 %then %do;
%let allow_restore=NO;
%let reason=User has restrictions in MPE_COLUMN_LEVEL_SECURITY;
data _null_;
set work.cls_rules;
putlog (_all_)(=);
if _n_>5 then stop;
run;
%return;
%end;
/* check if user has row level security rules */
proc sql;
create table work.rls_rules as
select *
from &mpelib..mpe_row_level_security
where &dc_dttmtfmt. lt tx_to
and rls_scope in ("EDIT",'ALL')
and upcase(rls_group) in (select upcase(groupname) from work.groups)
and rls_libref="&base_lib"
and rls_table="&base_ds"
and rls_active=1;
%if %mf_nobs(work.rls_rules)>0 %then %do;
%let allow_restore=NO;
%let reason=User has restrictions in MPE_ROW_LEVEL_SECURITY;
data _null_;
set work.rls_rules;
putlog (_all_)(=);
if _n_>5 then stop;
run;
%return;
%end;
%else %do;
%let allow_restore=YES;
%let reason=CHECKS PASSED;
%return;
%end;
%mend access_check;
%access_check();
%mpe_checkrestore(&table,outresult=ALLOW_RESTORE,outreason=REASON)
data work.jsParams;
set approve1;

View File

@ -92,6 +92,6 @@ run;
desc=Checking data was returned
)
%mp_assert(
iftrue=(&allow_edit=YES),
iftrue=(&ALLOW_RESTORE=YES),
desc=Checking admin user can restore
)