diff --git a/sas/sasjs/services/public/getchangeinfo.sas b/sas/sasjs/services/public/getchangeinfo.sas
index 63a47eb..c65249d 100644
--- a/sas/sasjs/services/public/getchangeinfo.sas
+++ b/sas/sasjs/services/public/getchangeinfo.sas
@@ -4,9 +4,26 @@
@details
SAS Macros
- @li mf_getengine.sas
@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
+
+ Service Inputs
+ sascontroltable
+ @li table table ID or LOAD_REF used to uniquely identify a staged change
+
+ Service Outputs
+
+ work.jsparams
+ Mainly sourced from MPE_SUBMIT plus some extra cols:
+
+ @li LIB_ENGINE Library engine
+ @li allow_restore YES if a user can restore, else NO
+ @li REASON reason why a restore is / is no possible
@version 9.2
@author 4GL Apps Ltd
@@ -35,13 +52,106 @@ 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;
-data jsParams;
+/**
+ * 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();
+
+
+data work.jsParams;
set approve1;
LIB_ENGINE="%mf_getEngine(&base_lib)";
+ allow_restore="&allow_restore";
+ REASON="&reason";
run;
%mp_abort(iftrue= (&syscc ne 0)
diff --git a/sas/sasjs/services/public/getchangeinfo.test.sas b/sas/sasjs/services/public/getchangeinfo.test.sas
new file mode 100644
index 0000000..8c5625e
--- /dev/null
+++ b/sas/sasjs/services/public/getchangeinfo.test.sas
@@ -0,0 +1,97 @@
+/**
+ @file
+ @brief testing getchangeinfo service
+
+ SAS Macros
+ @li mp_assertcolvals.sas
+ @li mf_getuniquefileref.sas
+
+**/
+
+%let _program=&appLoc/services/public/getchangeinfo;
+
+/**
+ * First part - stage some data (for diffing)
+ */
+data work.sascontroltable;
+ action='LOAD';
+ message="getdiffs prep";
+ libds="&dclib..MPE_X_TEST";
+ output;
+ stop;
+run;
+proc sql noprint;
+select max(primary_key_field) into: maxpk from &dclib..mpe_x_test;
+data work.jsdata;
+ set &dclib..mpe_x_test(rename=(
+ some_date=dt2 SOME_DATETIME=dttm2 SOME_TIME=tm2)
+ );
+ /* for now, the adapter sends these as strings */
+ some_date=put(dt2,date9.);
+ 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=._;
+ output;
+ end;
+ else if _n_<3 then do;
+ SOME_NUM=ranuni(0);
+ end;
+ else stop;
+run;
+
+%mx_testservice(&appLoc/services/editors/stagedata,
+ viyacontext=&defaultcontext,
+ inputdatasets=work.jsdata work.sascontroltable,
+ outlib=web1,
+ mdebug=&sasjs_mdebug
+)
+
+%let status=0;
+data work.sasparams;
+ set web1.sasparams;
+ putlog (_all_)(=);
+ if status='SUCCESS' then call symputx('status',1);
+ call symputx('dsid',dsid);
+run;
+%mp_assert(
+ iftrue=(&status=1 and &syscc=0),
+ desc=Checking successful submission
+)
+
+
+/* now call getchangeinfo */
+%let f3=%mf_getuniquefileref();
+data _null_;
+ file &f3 termstr=crlf;
+ put 'TABLE:$43.';
+ put "&dsid";
+run;
+%mp_testservice(&_program,
+ viyacontext=&defaultcontext,
+ inputfiles=&f3:sascontroltable,
+ outlib=web3,
+ mdebug=&sasjs_mdebug
+)
+
+data work.jsparams;
+ set web3.jsparams;
+ putlog (_all_)(=);
+ call symputx('ALLOW_RESTORE',ALLOW_RESTORE);
+run;
+%mp_assert(
+ iftrue=(&syscc=0),
+ desc=Checking successful execution
+)
+%mp_assert(
+ iftrue=(%mf_nobs(work.jsparams)=1),
+ desc=Checking data was returned
+)
+%mp_assert(
+ iftrue=(&allow_edit=YES),
+ desc=Checking admin user can restore
+)