mirror of
https://github.com/sasjs/core.git
synced 2025-12-11 06:24:35 +00:00
Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f285505b79 | ||
|
|
67f5c50300 | ||
|
|
ce39e4f779 | ||
|
|
9c80f5664c | ||
|
|
83466c001b | ||
|
|
ad315be503 | ||
|
|
c41ae2dcc8 | ||
| d9f8e92fac | |||
|
|
d42ede15db | ||
|
|
08ea9f7c00 | ||
|
|
c327e1fc0d | ||
|
|
02fddcf9a1 | ||
|
|
4752bfbb05 | ||
|
|
767ddd7add | ||
|
|
54a24ced83 | ||
|
|
57ae2981f1 | ||
|
|
a3043ac685 | ||
|
|
2bdb90b0be | ||
|
|
2cd846d504 | ||
|
|
f593c7bec9 | ||
|
|
c8805db0b5 | ||
|
|
1eb6d8cec9 | ||
|
|
ed19ee03af | ||
|
|
a1c931b5e6 | ||
|
|
cb553a31ab | ||
|
|
557df272ff | ||
|
|
0cb3c96c15 | ||
|
|
1cb39d4d61 | ||
|
|
934b7d4f8a | ||
|
|
24c50cde56 | ||
|
|
055e8d2f13 | ||
|
|
abfe7fe339 | ||
|
|
16ed91f6a9 | ||
|
|
67ba2a5286 | ||
|
|
3d7f9b71e1 | ||
|
|
1d972fad11 | ||
|
|
e23bc461c4 | ||
|
|
28ed458b83 | ||
|
|
827210e010 | ||
|
|
de2f32da36 | ||
|
|
6fa0fc5dc6 | ||
|
|
73e3d9d419 | ||
|
|
5f2229e3d5 | ||
|
|
d19c4a517c |
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
17
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
## Issue
|
||||
|
||||
Link any related issue(s) in this section.
|
||||
|
||||
## Intent
|
||||
|
||||
What this PR intends to achieve.
|
||||
|
||||
## Implementation
|
||||
|
||||
What code changes have been made to achieve the intent.
|
||||
|
||||
## Checks
|
||||
|
||||
- [ ] Code is formatted correctly (`sasjs lint`).
|
||||
- [ ] Any new functionality has been unit tested.
|
||||
- [ ] All unit tests are passing (`sasjs test`).
|
||||
@@ -6,9 +6,6 @@
|
||||
|
||||
%put %mf_existVarList(sashelp.class, age sex name dummyvar);
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_abort.sas
|
||||
|
||||
@param libds 2 part dataset or view reference
|
||||
@param varlist space separated variable names
|
||||
|
||||
|
||||
@@ -23,18 +23,19 @@
|
||||
@author Allan Bowe
|
||||
**/
|
||||
|
||||
%macro mf_getuser(type=META
|
||||
%macro mf_getuser(
|
||||
)/*/STORE SOURCE*/;
|
||||
%local user metavar;
|
||||
%if &type=OS %then %let metavar=_secureusername;
|
||||
%else %let metavar=_metaperson;
|
||||
%local user;
|
||||
|
||||
%if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER;
|
||||
%else %if %symexist(&metavar) %then %do;
|
||||
%if %length(&&&metavar)=0 %then %let user=&sysuserid;
|
||||
%if %symexist(_sasjs_username) %then %let user=&_sasjs_username;
|
||||
%else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do;
|
||||
%let user=&SYS_COMPUTE_SESSION_OWNER;
|
||||
%end;
|
||||
%else %if %symexist(_metaperson) %then %do;
|
||||
%if %length(&_metaperson)=0 %then %let user=&sysuserid;
|
||||
/* sometimes SAS will add @domain extension - remove for consistency */
|
||||
/* but be sure to quote in case of usernames with commas */
|
||||
%else %let user=%unquote(%scan(%quote(&&&metavar),1,@));
|
||||
%else %let user=%unquote(%scan(%quote(&_metaperson),1,@));
|
||||
%end;
|
||||
%else %let user=&sysuserid;
|
||||
|
||||
|
||||
@@ -15,16 +15,20 @@
|
||||
recognise this and fetch the log of the parent session instead)
|
||||
@li STP environments must finish cleanly to avoid the log being sent to
|
||||
_webout. To assist with this, we also run stpsrvset('program error', 0)
|
||||
and set SYSCC=0. We take a unique "soft abort" approach - we open a macro
|
||||
and set SYSCC=0.
|
||||
Where possible, we take a unique "soft abort" approach - we open a macro
|
||||
but don't close it! This works everywhere EXCEPT inside a \%include inside
|
||||
a macro. For that, we recommend you use mp_include.sas to perform the
|
||||
include, and then call \%mp_abort(mode=INCLUDE) from the source program (ie,
|
||||
OUTSIDE of the top-parent macro).
|
||||
The soft abort has also been found to be ineffective in 9.4m6 windows
|
||||
environments and above, so in these cases, endsas is used.
|
||||
|
||||
|
||||
@param mac= to contain the name of the calling macro
|
||||
@param mac= (mp_abort.sas) To contain the name of the calling macro. Do not
|
||||
use &sysmacroname as this will always resolve to MP_ABORT.
|
||||
@param msg= message to be returned
|
||||
@param iftrue= supply a condition under which the macro should be executed.
|
||||
@param iftrue= (1=1) Supply a condition for which the macro should be executed
|
||||
@param errds= (work.mp_abort_errds) There is no clean way to end a process
|
||||
within a %include called within a macro. Furthermore, there is no way to
|
||||
test if a macro is called within a %include. To handle this particular
|
||||
@@ -45,11 +49,12 @@
|
||||
@li REGULAR (default)
|
||||
@li INCLUDE
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
|
||||
<h4> Related Macros </h4>
|
||||
@li mp_include.sas
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
@cond
|
||||
**/
|
||||
|
||||
@@ -58,174 +63,196 @@
|
||||
, mode=REGULAR
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
%global sysprocessmode sysprocessname;
|
||||
%global sysprocessmode sysprocessname sasjs_stpsrv_header_loc sasjsprocessmode;
|
||||
%local fref fid i;
|
||||
|
||||
%if not(%eval(%unquote(&iftrue))) %then %return;
|
||||
%if not(%eval(%unquote(&iftrue))) %then %return;
|
||||
|
||||
%put NOTE: /// mp_abort macro executing //;
|
||||
%if %length(&mac)>0 %then %put NOTE- called by &mac;
|
||||
%put NOTE - &msg;
|
||||
%put NOTE: /// mp_abort macro executing //;
|
||||
%if %length(&mac)>0 %then %put NOTE- called by &mac;
|
||||
%put NOTE - &msg;
|
||||
|
||||
%if %symexist(_SYSINCLUDEFILEDEVICE)
|
||||
/* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
|
||||
and "&SYSPROCESSNAME " ne "Compute Server "
|
||||
%if %symexist(_SYSINCLUDEFILEDEVICE)
|
||||
/* abort cancel FILE does not restart outside the INCLUDE on Viya 3.5 */
|
||||
and %superq(SYSPROCESSNAME) ne %str(Compute Server)
|
||||
%then %do;
|
||||
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
|
||||
data &errds;
|
||||
iftrue='1=1';
|
||||
length mac $100 msg $5000;
|
||||
mac=symget('mac');
|
||||
msg=symget('msg');
|
||||
run;
|
||||
data _null_;
|
||||
abort cancel FILE;
|
||||
run;
|
||||
%return;
|
||||
%end;
|
||||
%end;
|
||||
|
||||
/* Web App Context */
|
||||
%if %symexist(_PROGRAM)
|
||||
or %superq(SYSPROCESSNAME) = %str(Compute Server)
|
||||
or &mode=INCLUDE
|
||||
%then %do;
|
||||
options obs=max replace mprint;
|
||||
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
|
||||
%then %do;
|
||||
%if "*&_SYSINCLUDEFILEDEVICE*" ne "**" %then %do;
|
||||
data &errds;
|
||||
iftrue='1=1';
|
||||
length mac $100 msg $5000;
|
||||
mac=symget('mac');
|
||||
msg=symget('msg');
|
||||
run;
|
||||
options nosyntaxcheck;
|
||||
%end;
|
||||
|
||||
%if &mode=INCLUDE %then %do;
|
||||
%if %sysfunc(exist(&errds))=1 %then %do;
|
||||
data _null_;
|
||||
abort cancel FILE;
|
||||
set &errds;
|
||||
call symputx('iftrue',iftrue,'l');
|
||||
call symputx('mac',mac,'l');
|
||||
call symputx('msg',msg,'l');
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
%if (&iftrue)=0 %then %return;
|
||||
%end;
|
||||
%else %do;
|
||||
%put &sysmacroname: No include errors found;
|
||||
%return;
|
||||
%end;
|
||||
%end;
|
||||
|
||||
/* Stored Process Server web app context */
|
||||
%if %symexist(_METAFOLDER)
|
||||
or "&SYSPROCESSNAME "="Compute Server "
|
||||
or &mode=INCLUDE
|
||||
%then %do;
|
||||
options obs=max replace mprint;
|
||||
%if "%substr(&sysver,1,1)" ne "4" and "%substr(&sysver,1,1)" ne "5"
|
||||
%then %do;
|
||||
options nosyntaxcheck;
|
||||
%end;
|
||||
|
||||
%if &mode=INCLUDE %then %do;
|
||||
%if %sysfunc(exist(&errds))=1 %then %do;
|
||||
data _null_;
|
||||
set &errds;
|
||||
call symputx('iftrue',iftrue,'l');
|
||||
call symputx('mac',mac,'l');
|
||||
call symputx('msg',msg,'l');
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
%if (&iftrue)=0 %then %return;
|
||||
%end;
|
||||
%else %do;
|
||||
%put &sysmacroname: No include errors found;
|
||||
%return;
|
||||
%end;
|
||||
%end;
|
||||
|
||||
/* extract log errs / warns, if exist */
|
||||
%local logloc logline;
|
||||
%global logmsg; /* capture global messages */
|
||||
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
|
||||
%else %let logloc=%qsysfunc(getoption(LOG));
|
||||
proc printto log=log;run;
|
||||
%let logline=0;
|
||||
%if %length(&logloc)>0 %then %do;
|
||||
/* extract log errs / warns, if exist */
|
||||
%local logloc logline;
|
||||
%global logmsg; /* capture global messages */
|
||||
%if %symexist(SYSPRINTTOLOG) %then %let logloc=&SYSPRINTTOLOG;
|
||||
%else %let logloc=%qsysfunc(getoption(LOG));
|
||||
proc printto log=log;run;
|
||||
%let logline=0;
|
||||
%if %length(&logloc)>0 %then %do;
|
||||
data _null_;
|
||||
infile &logloc lrecl=5000;
|
||||
input; putlog _infile_;
|
||||
i=1;
|
||||
retain logonce 0;
|
||||
if (
|
||||
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
|
||||
) and logonce=0 then
|
||||
do;
|
||||
call symputx('logline',_n_);
|
||||
logonce+1;
|
||||
end;
|
||||
run;
|
||||
/* capture log including lines BEFORE the err */
|
||||
%if &logline>0 %then %do;
|
||||
data _null_;
|
||||
infile &logloc lrecl=5000;
|
||||
input; putlog _infile_;
|
||||
input;
|
||||
i=1;
|
||||
retain logonce 0;
|
||||
if (
|
||||
_infile_=:"%str(WARN)ING" or _infile_=:"%str(ERR)OR"
|
||||
) and logonce=0 then
|
||||
do;
|
||||
call symputx('logline',_n_);
|
||||
logonce+1;
|
||||
end;
|
||||
run;
|
||||
/* capture log including lines BEFORE the err */
|
||||
%if &logline>0 %then %do;
|
||||
data _null_;
|
||||
infile &logloc lrecl=5000;
|
||||
stoploop=0;
|
||||
if _n_ ge &logline-15 and stoploop=0 then do until (i>22);
|
||||
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
|
||||
input;
|
||||
i=1;
|
||||
stoploop=0;
|
||||
if _n_ ge &logline-15 and stoploop=0 then do until (i>22);
|
||||
call symputx('logmsg',catx('\n',symget('logmsg'),_infile_));
|
||||
input;
|
||||
i+1;
|
||||
stoploop=1;
|
||||
end;
|
||||
if stoploop=1 then stop;
|
||||
run;
|
||||
%end;
|
||||
%end;
|
||||
|
||||
%if %symexist(SYS_JES_JOB_URI) %then %do;
|
||||
/* setup webout */
|
||||
OPTIONS NOBOMFILE;
|
||||
%if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
|
||||
filename _webout temp lrecl=999999 mod;
|
||||
%end;
|
||||
%else %do;
|
||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
|
||||
name="_webout.json" lrecl=999999 mod;
|
||||
%end;
|
||||
%end;
|
||||
|
||||
/* send response in SASjs JSON format */
|
||||
data _null_;
|
||||
file _webout mod lrecl=32000 encoding='utf-8';
|
||||
length msg syswarningtext syserrortext $32767 ;
|
||||
sasdatetime=datetime();
|
||||
msg=symget('msg');
|
||||
%if &logline>0 %then %do;
|
||||
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
|
||||
%end;
|
||||
/* escape the escapes */
|
||||
msg=tranwrd(msg,'\','\\');
|
||||
/* escape the quotes */
|
||||
msg=tranwrd(msg,'"','\"');
|
||||
/* ditch the CRLFs as chrome complains */
|
||||
msg=compress(msg,,'kw');
|
||||
/* quote without quoting the quotes (which are escaped instead) */
|
||||
msg=cats('"',msg,'"');
|
||||
if symexist('_debug') then debug=quote(trim(symget('_debug')));
|
||||
else debug='""';
|
||||
put '>>weboutBEGIN<<';
|
||||
put '{"SYSDATE" : "' "&SYSDATE" '"';
|
||||
put ',"SYSTIME" : "' "&SYSTIME" '"';
|
||||
put ',"sasjsAbort" : [{';
|
||||
put ' "MSG":' msg ;
|
||||
put ' ,"MAC": "' "&mac" '"}]';
|
||||
put ",""SYSUSERID"" : ""&sysuserid"" ";
|
||||
put ',"_DEBUG":' debug ;
|
||||
if symexist('_metauser') then do;
|
||||
_METAUSER=quote(trim(symget('_METAUSER')));
|
||||
put ",""_METAUSER"": " _METAUSER;
|
||||
_METAPERSON=quote(trim(symget('_METAPERSON')));
|
||||
put ',"_METAPERSON": ' _METAPERSON;
|
||||
end;
|
||||
if symexist('SYS_JES_JOB_URI') then do;
|
||||
SYS_JES_JOB_URI=quote(trim(symget('SYS_JES_JOB_URI')));
|
||||
put ',"SYS_JES_JOB_URI": ' SYS_JES_JOB_URI;
|
||||
end;
|
||||
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
|
||||
put ',"_PROGRAM" : ' _PROGRAM ;
|
||||
put ",""SYSCC"" : ""&syscc"" ";
|
||||
syserrortext=quote(trim(symget('syserrortext')));
|
||||
put ",""SYSERRORTEXT"" : " syserrortext;
|
||||
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
|
||||
put ",""SYSJOBID"" : ""&sysjobid"" ";
|
||||
put ",""SYSSCPL"" : ""&sysscpl"" ";
|
||||
put ",""SYSSITE"" : ""&syssite"" ";
|
||||
sysvlong=quote(trim(symget('sysvlong')));
|
||||
put ',"SYSVLONG" : ' sysvlong;
|
||||
syswarningtext=quote(trim(symget('syswarningtext')));
|
||||
put ",""SYSWARNINGTEXT"" : " syswarningtext;
|
||||
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
|
||||
put "}" @;
|
||||
put '>>weboutEND<<';
|
||||
run;
|
||||
|
||||
%put _all_;
|
||||
|
||||
%if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
|
||||
data _null_;
|
||||
putlog 'stpsrvset program err and syscc';
|
||||
rc=stpsrvset('program error', 0);
|
||||
call symputx("syscc",0,"g");
|
||||
i+1;
|
||||
stoploop=1;
|
||||
end;
|
||||
if stoploop=1 then stop;
|
||||
run;
|
||||
%end;
|
||||
%end;
|
||||
|
||||
%if %symexist(SYS_JES_JOB_URI) %then %do;
|
||||
/* setup webout for Viya */
|
||||
options nobomfile;
|
||||
%if "X&SYS_JES_JOB_URI.X"="XX" %then %do;
|
||||
filename _webout temp lrecl=999999 mod;
|
||||
%end;
|
||||
%else %do;
|
||||
filename _webout filesrvc parenturi="&SYS_JES_JOB_URI"
|
||||
name="_webout.json" lrecl=999999 mod;
|
||||
%end;
|
||||
%end;
|
||||
%else %if %sysfunc(filename(fref,&sasjs_stpsrv_header_loc))=0 %then %do;
|
||||
options nobomfile;
|
||||
/* set up http header for SASjs Server */
|
||||
%let fid=%sysfunc(fopen(&fref,A));
|
||||
%if &fid=0 %then %do;
|
||||
%put %str(ERR)OR: %sysfunc(sysmsg());
|
||||
%return;
|
||||
%end;
|
||||
%let rc=%sysfunc(fput(&fid,%str(Content-Type: application/json)));
|
||||
%let rc=%sysfunc(fwrite(&fid));
|
||||
%let rc=%sysfunc(fclose(&fid));
|
||||
%let rc=%sysfunc(filename(&fref));
|
||||
%end;
|
||||
|
||||
/* send response in SASjs JSON format */
|
||||
data _null_;
|
||||
file _webout mod lrecl=32000 encoding='utf-8';
|
||||
length msg syswarningtext syserrortext $32767 mode $10 ;
|
||||
sasdatetime=datetime();
|
||||
msg=symget('msg');
|
||||
%if &logline>0 %then %do;
|
||||
msg=cats(msg,'\n\nLog Extract:\n',symget('logmsg'));
|
||||
%end;
|
||||
/* escape the escapes */
|
||||
msg=tranwrd(msg,'\','\\');
|
||||
/* escape the quotes */
|
||||
msg=tranwrd(msg,'"','\"');
|
||||
/* ditch the CRLFs as chrome complains */
|
||||
msg=compress(msg,,'kw');
|
||||
/* quote without quoting the quotes (which are escaped instead) */
|
||||
msg=cats('"',msg,'"');
|
||||
if symexist('_debug') then debug=quote(trim(symget('_debug')));
|
||||
else debug='""';
|
||||
if symget('sasjsprocessmode')='Stored Program' then mode='SASJS';
|
||||
if mode ne 'SASJS' then put '>>weboutBEGIN<<';
|
||||
put '{"SYSDATE" : "' "&SYSDATE" '"';
|
||||
put ',"SYSTIME" : "' "&SYSTIME" '"';
|
||||
put ',"sasjsAbort" : [{';
|
||||
put ' "MSG":' msg ;
|
||||
put ' ,"MAC": "' "&mac" '"}]';
|
||||
put ",""SYSUSERID"" : ""&sysuserid"" ";
|
||||
put ',"_DEBUG":' debug ;
|
||||
if symexist('_metauser') then do;
|
||||
_METAUSER=quote(trim(symget('_METAUSER')));
|
||||
put ",""_METAUSER"": " _METAUSER;
|
||||
_METAPERSON=quote(trim(symget('_METAPERSON')));
|
||||
put ',"_METAPERSON": ' _METAPERSON;
|
||||
end;
|
||||
if symexist('SYS_JES_JOB_URI') then do;
|
||||
SYS_JES_JOB_URI=quote(trim(symget('SYS_JES_JOB_URI')));
|
||||
put ',"SYS_JES_JOB_URI": ' SYS_JES_JOB_URI;
|
||||
end;
|
||||
_PROGRAM=quote(trim(resolve(symget('_PROGRAM'))));
|
||||
put ',"_PROGRAM" : ' _PROGRAM ;
|
||||
put ",""SYSCC"" : ""&syscc"" ";
|
||||
syserrortext=quote(trim(symget('syserrortext')));
|
||||
put ",""SYSERRORTEXT"" : " syserrortext;
|
||||
put ",""SYSHOSTNAME"" : ""&syshostname"" ";
|
||||
put ",""SYSJOBID"" : ""&sysjobid"" ";
|
||||
put ",""SYSSCPL"" : ""&sysscpl"" ";
|
||||
put ",""SYSSITE"" : ""&syssite"" ";
|
||||
sysvlong=quote(trim(symget('sysvlong')));
|
||||
put ',"SYSVLONG" : ' sysvlong;
|
||||
syswarningtext=quote(trim(symget('syswarningtext')));
|
||||
put ",""SYSWARNINGTEXT"" : " syswarningtext;
|
||||
put ',"END_DTTM" : "' "%sysfunc(datetime(),E8601DT26.6)" '" ';
|
||||
put "}" ;
|
||||
if mode ne 'SASJS' then put '>>weboutEND<<';
|
||||
run;
|
||||
|
||||
%put _all_;
|
||||
|
||||
%if "&sysprocessmode " = "SAS Stored Process Server " %then %do;
|
||||
data _null_;
|
||||
putlog 'stpsrvset program err and syscc';
|
||||
rc=stpsrvset('program error', 0);
|
||||
call symputx("syscc",0,"g");
|
||||
run;
|
||||
%if &sysscp=WIN
|
||||
and "%substr(%str(&sysvlong ),1,8)"="9.04.01M"
|
||||
and "%substr(%str(&sysvlong ),9,1)">"5" %then %do;
|
||||
/* skip approach (below) does not work in windows m6+ envs */
|
||||
endsas;
|
||||
%end;
|
||||
%else %do;
|
||||
/**
|
||||
* endsas kills 9.4m3 deployments by orphaning multibridges.
|
||||
* Abort variants are ungraceful (non zero return code)
|
||||
@@ -243,28 +270,29 @@
|
||||
run;
|
||||
%inc skip;
|
||||
%end;
|
||||
%else %if "&sysprocessmode " = "SAS Compute Server " %then %do;
|
||||
/* endsas kills the session making it harder to fetch results */
|
||||
data _null_;
|
||||
syswarningtext=symget('syswarningtext');
|
||||
syserrortext=symget('syserrortext');
|
||||
abort_msg=symget('msg');
|
||||
syscc=symget('syscc');
|
||||
sysuserid=symget('sysuserid');
|
||||
iftrue=symget('iftrue');
|
||||
put (_all_)(/=);
|
||||
call symputx('syscc',0);
|
||||
abort cancel nolist;
|
||||
run;
|
||||
%end;
|
||||
%else %do;
|
||||
%abort cancel;
|
||||
%end;
|
||||
%end;
|
||||
%else %if "&sysprocessmode " = "SAS Compute Server " %then %do;
|
||||
/* endsas kills the session making it harder to fetch results */
|
||||
data _null_;
|
||||
syswarningtext=symget('syswarningtext');
|
||||
syserrortext=symget('syserrortext');
|
||||
abort_msg=symget('msg');
|
||||
syscc=symget('syscc');
|
||||
sysuserid=symget('sysuserid');
|
||||
iftrue=symget('iftrue');
|
||||
put (_all_)(/=);
|
||||
call symputx('syscc',0);
|
||||
abort cancel nolist;
|
||||
run;
|
||||
%end;
|
||||
%else %do;
|
||||
%put _all_;
|
||||
%abort cancel;
|
||||
%end;
|
||||
%end;
|
||||
%else %do;
|
||||
%put _all_;
|
||||
%abort cancel;
|
||||
%end;
|
||||
%mend mp_abort;
|
||||
|
||||
/** @endcond */
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
@cond
|
||||
**/
|
||||
|
||||
%macro mp_ds2cards(base_ds=, tgt_ds=
|
||||
%macro mp_ds2cards(base_ds, tgt_ds=
|
||||
,cards_file="%sysfunc(pathname(work))/cardgen.sas"
|
||||
,maxobs=max
|
||||
,random_sample=NO
|
||||
@@ -254,6 +254,7 @@ data _null_;
|
||||
;
|
||||
%end;
|
||||
put ";";
|
||||
put 'missing a b c d e f g h i j k l m n o p q r s t u v w x y z _;';
|
||||
put "datalines4;";
|
||||
end;
|
||||
end;
|
||||
|
||||
@@ -231,7 +231,7 @@
|
||||
%do i=1 %to &numcols;
|
||||
%if &i>1 %then "," ;
|
||||
%if &action=OBJ %then """&&name&i"":" ;
|
||||
&&name&i
|
||||
"&&name&i"n /* name literal for reserved variable names */
|
||||
%end;
|
||||
%if &action=ARR %then "]" ; %else "}" ; ;
|
||||
/* now write the long strings to _webout 1 byte at a time */
|
||||
@@ -263,7 +263,7 @@
|
||||
do i=1 to &numcols;
|
||||
name=quote(trim(symget(cats('name',i))));
|
||||
format=quote(trim(symget(cats('fmt',i))));
|
||||
label=quote(trim(symget(cats('label',i))));
|
||||
label=quote(prxchange('s/\\/\\\\/',-1,trim(symget(cats('label',i)))));
|
||||
length=quote(trim(symget(cats('length',i))));
|
||||
type=quote(trim(symget(cats('typelong',i))));
|
||||
if i>1 then put "," @@;
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
@file mm_adduser2group.sas
|
||||
@brief Adds a user to a group
|
||||
@details Adds a user to a metadata group. The macro first checks whether the
|
||||
user is in that group, and if not, the user is added.
|
||||
user is in that group, and if not, the user is added.
|
||||
|
||||
Note that the macro does not check inherited group memberships - it looks at
|
||||
direct members only.
|
||||
|
||||
Usage:
|
||||
|
||||
@@ -12,10 +15,10 @@
|
||||
|
||||
@param user= the user name (not displayname)
|
||||
@param group= the group to which to add the user
|
||||
@param mdebug= set to 1 to show debug info in log
|
||||
@param mdebug= (0) set to 1 to show debug info in log
|
||||
|
||||
@warning the macro does not check inherited group memberships - it looks at
|
||||
direct members only
|
||||
<h4> Related Files </h4>
|
||||
@li ms_adduser2group.sas
|
||||
|
||||
@version 9.3
|
||||
@author Allan Bowe
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
/**
|
||||
@file mm_createdataset.sas
|
||||
@brief Create a dataset from a metadata definition
|
||||
@file
|
||||
@brief Create an empty dataset from a metadata definition
|
||||
@details This macro was built to support viewing empty tables in
|
||||
https://datacontroller.io - a free evaluation copy is available by
|
||||
contacting the author (Allan Bowe).
|
||||
https://datacontroller.io
|
||||
|
||||
The table can be retrieved using LIBRARY.DATASET reference, or directly
|
||||
using the metadata URI.
|
||||
The table can be retrieved using LIBRARY.DATASET reference, or directly
|
||||
using the metadata URI.
|
||||
|
||||
The dataset is written to the WORK library.
|
||||
The dataset is written to the WORK library.
|
||||
|
||||
usage:
|
||||
Usage:
|
||||
|
||||
%mm_createdataset(libds=metlib.some_dataset)
|
||||
%mm_createdataset(libds=metlib.some_dataset)
|
||||
|
||||
or
|
||||
or
|
||||
|
||||
%mm_createdataset(tableuri=G5X8AFW1.BE00015Y)
|
||||
%mm_createdataset(tableuri=G5X8AFW1.BE00015Y)
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mm_getlibs.sas
|
||||
@@ -26,9 +25,9 @@
|
||||
@param libds= library.dataset metadata source. Note - table names in metadata
|
||||
can be longer than 32 chars (just fyi, not an issue here)
|
||||
@param tableuri= Metadata URI of the table to be created
|
||||
@param outds= The dataset to create, default is `work.mm_createdataset`.
|
||||
The table name needs to be 32 chars or less as per SAS naming rules.
|
||||
@param mdebug= set DBG to 1 to disable DEBUG messages
|
||||
@param outds= (work.mm_createdataset) The dataset to create. The table name
|
||||
needs to be 32 chars or less as per SAS naming rules.
|
||||
@param mdebug= (0) Set to 1 to enable DEBUG messages
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
@@ -54,14 +53,23 @@
|
||||
%mm_gettables(uri=&liburi,outds=&tempds2)
|
||||
data _null_;
|
||||
set &tempds2;
|
||||
if upcase(tablename)="%upcase(%scan(&libds,2,.))";
|
||||
where upcase(tablename)="%upcase(%scan(&libds,2,.))";
|
||||
&dbg putlog tableuri=;
|
||||
call symputx('tableuri',tableuri);
|
||||
run;
|
||||
%end;
|
||||
|
||||
data;run;%let tempds3=&syslast;
|
||||
data;run;
|
||||
%let tempds3=&syslast;
|
||||
%mm_getcols(tableuri=&tableuri,outds=&tempds3)
|
||||
|
||||
%if %mf_nobs(&tempds3)=0 %then %do;
|
||||
%put &libds (&tableuri) has no columns defined!!;
|
||||
data &outds;
|
||||
run;
|
||||
%return;
|
||||
%end;
|
||||
|
||||
data _null_;
|
||||
set &tempds3 end=last;
|
||||
if _n_=1 then call execute('data &outds;');
|
||||
|
||||
@@ -264,7 +264,7 @@ data _null_;
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &i>1 %then "," ; ';
|
||||
put ' %if &action=OBJ %then """&&name&i"":" ; ';
|
||||
put ' &&name&i ';
|
||||
put ' "&&name&i"n /* name literal for reserved variable names */ ';
|
||||
put ' %end; ';
|
||||
put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
|
||||
put ' /* now write the long strings to _webout 1 byte at a time */ ';
|
||||
@@ -296,7 +296,7 @@ data _null_;
|
||||
put ' do i=1 to &numcols; ';
|
||||
put ' name=quote(trim(symget(cats(''name'',i)))); ';
|
||||
put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
|
||||
put ' label=quote(trim(symget(cats(''label'',i)))); ';
|
||||
put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
|
||||
put ' length=quote(trim(symget(cats(''length'',i)))); ';
|
||||
put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
|
||||
put ' if i>1 then put "," @@; ';
|
||||
@@ -315,18 +315,19 @@ data _null_;
|
||||
put '%end; ';
|
||||
put '%mend mp_jsonout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put '%macro mf_getuser( ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' %local user; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
put ' %else %if %symexist(&metavar) %then %do; ';
|
||||
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
|
||||
put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
|
||||
put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
|
||||
put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
put ' %end; ';
|
||||
put ' %else %if %symexist(_metaperson) %then %do; ';
|
||||
put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
|
||||
put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
|
||||
put ' /* but be sure to quote in case of usernames with commas */ ';
|
||||
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
|
||||
put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
|
||||
put ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
|
||||
@@ -8,17 +8,15 @@
|
||||
|
||||
Usage:
|
||||
|
||||
options ps=max nonotes nosource;
|
||||
%mm_getfoldertree(root=/My/Meta/Path, outds=iwantthisdataset)
|
||||
options notes source;
|
||||
options ps=max nonotes nosource;
|
||||
%mm_getfoldertree(root=/My/Meta/Path, outds=iwantthisdataset)
|
||||
options notes source;
|
||||
|
||||
@param [in] root= the parent folder under which to return all contents
|
||||
@param [out] outds= the dataset to create that contains the list of
|
||||
directories
|
||||
@param [in] mDebug= set to 1 to show debug messages in the log
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
|
||||
@version 9.4
|
||||
@author Allan Bowe
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mp_abort.sas
|
||||
|
||||
@author Allan Bowe
|
||||
|
||||
@@ -70,11 +71,10 @@ data _null_;
|
||||
else put (_all_)(=);
|
||||
run;
|
||||
|
||||
%if &tsuri=stopifempty %then %do;
|
||||
%put %str(WARN)ING: &tree&name.(StoredProcess) not found!;
|
||||
%return;
|
||||
%end;
|
||||
|
||||
%mp_abort(iftrue= (&tsuri=stopifempty)
|
||||
,mac=mm_getstpcode
|
||||
,msg=%str(&tree&name.(StoredProcess) not found!)
|
||||
)
|
||||
|
||||
/**
|
||||
* Now we can extract the textstore
|
||||
|
||||
@@ -8,17 +8,18 @@
|
||||
|
||||
%mm_getusers()
|
||||
|
||||
Optionally, filter for a user (useful to get the uri):
|
||||
|
||||
%mm_getusers(user=&_metaperson)
|
||||
|
||||
@param outds the dataset to create that contains the list of libraries
|
||||
|
||||
@returns outds dataset containing all users, with the following columns:
|
||||
- uri
|
||||
- name
|
||||
|
||||
@warning The following filenames are created and then de-assigned:
|
||||
|
||||
filename sxlemap clear;
|
||||
filename response clear;
|
||||
libname _XML_ clear;
|
||||
@param user= (0) Set to a metadata user to filter on that user
|
||||
@param outds= (work.mm_getusers) The output table to create
|
||||
|
||||
@version 9.3
|
||||
@author Allan Bowe
|
||||
@@ -26,23 +27,49 @@
|
||||
**/
|
||||
|
||||
%macro mm_getusers(
|
||||
outds=work.mm_getusers
|
||||
outds=work.mm_getusers,
|
||||
user=0
|
||||
)/*/STORE SOURCE*/;
|
||||
|
||||
filename response temp;
|
||||
proc metadata in= '<GetMetadataObjects>
|
||||
<Reposid>$METAREPOSITORY</Reposid>
|
||||
<Type>Person</Type>
|
||||
<NS>SAS</NS>
|
||||
<Flags>0</Flags>
|
||||
<Options>
|
||||
<Templates>
|
||||
<Person Name=""/>
|
||||
</Templates>
|
||||
</Options>
|
||||
</GetMetadataObjects>'
|
||||
out=response;
|
||||
run;
|
||||
%if %superq(user)=0 %then %do;
|
||||
proc metadata in= '<GetMetadataObjects>
|
||||
<Reposid>$METAREPOSITORY</Reposid>
|
||||
<Type>Person</Type>
|
||||
<NS>SAS</NS>
|
||||
<Flags>0</Flags>
|
||||
<Options>
|
||||
<Templates>
|
||||
<Person Name=""/>
|
||||
</Templates>
|
||||
</Options>
|
||||
</GetMetadataObjects>'
|
||||
out=response;
|
||||
run;
|
||||
%end;
|
||||
%else %do;
|
||||
filename inref temp;
|
||||
data _null_;
|
||||
file inref;
|
||||
put "<GetMetadataObjects>";
|
||||
put "<Reposid>$METAREPOSITORY</Reposid>";
|
||||
put "<Type>Person</Type>";
|
||||
put "<NS>SAS</NS>";
|
||||
put "<!-- Specify the OMI_XMLSELECT (128) flag -->";
|
||||
put "<Flags>128</Flags>";
|
||||
put "<Options>";
|
||||
put "<Templates>";
|
||||
put '<Person Name=""/>';
|
||||
put "</Templates>";
|
||||
length string $10000;
|
||||
string=cats('<XMLSELECT search="Person[@Name=',"'&user'",']"/>');
|
||||
put string;
|
||||
put "</Options>";
|
||||
put "</GetMetadataObjects>";
|
||||
run;
|
||||
proc metadata in=inref out=response;
|
||||
run;
|
||||
%end;
|
||||
|
||||
filename sxlemap temp;
|
||||
data _null_;
|
||||
|
||||
@@ -67,7 +67,7 @@
|
||||
},
|
||||
{
|
||||
"name": "server",
|
||||
"serverUrl": "https://sas.analytium.co.uk:5007",
|
||||
"serverUrl": "https://sas.4gl.io",
|
||||
"serverType": "SASJS",
|
||||
"httpsAgentOptions": {
|
||||
"allowInsecureRequests": false
|
||||
@@ -107,4 +107,4 @@
|
||||
"contextName": "SAS Job Execution compute context"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
122
server/ms_adduser2group.sas
Normal file
122
server/ms_adduser2group.sas
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
@file
|
||||
@brief Adds a user to a group on SASjs Server
|
||||
@details Adds a user to a group based on userid and groupid. Both user and
|
||||
group must already exist.
|
||||
|
||||
Examples:
|
||||
|
||||
%ms_adduser2group(uid=1,gid=1)
|
||||
|
||||
|
||||
@param [in] uid= (0) The User ID to be added
|
||||
@param [in] gid= (0) The Group ID to contain the new user
|
||||
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
|
||||
@param [out] outds= (work.ms_adduser2group) This output dataset will contain
|
||||
the new list of group members, eg:
|
||||
|DISPLAYNAME:$18.|USERNAME:$10.|ID:best.|
|
||||
|---|---|---|
|
||||
|`Super Admin `|`secretuser `|`1`|
|
||||
|`Sabir Hassan`|`sabir`|`2`|
|
||||
|`Mihajlo Medjedovic `|`mihajlo `|`3`|
|
||||
|`Ivor Townsend `|`ivor `|`4`|
|
||||
|`New User `|`newuser `|`5`|
|
||||
|
||||
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
@li mp_abort.sas
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li ms_creategroup.sas
|
||||
@li ms_createuser.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_adduser2group(uid=0
|
||||
,gid=0
|
||||
,outds=work.ms_adduser2group
|
||||
,mdebug=0
|
||||
);
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_adduser2group.sas
|
||||
,msg=%str(syscc=&syscc on macro entry)
|
||||
)
|
||||
|
||||
%local fref0 fref1 fref2 libref optval rc msg;
|
||||
%let fref0=%mf_getuniquefileref();
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let libref=%mf_getuniquelibref();
|
||||
|
||||
/* avoid sending bom marker to API */
|
||||
%let optval=%sysfunc(getoption(bomfile));
|
||||
options nobomfile;
|
||||
|
||||
data _null_;
|
||||
file &fref0 lrecl=1000;
|
||||
infile "&_sasjs_tokenfile" lrecl=1000;
|
||||
input;
|
||||
if _n_=1 then put "accept: application/json";
|
||||
put _infile_;
|
||||
run;
|
||||
|
||||
%if &mdebug=1 %then %do;
|
||||
%put _local_;
|
||||
data _null_;
|
||||
infile &fref0;
|
||||
input;
|
||||
put _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
proc http method='POST' headerin=&fref0 out=&fref1
|
||||
url="&_sasjs_apiserverurl/SASjsApi/group/&gid/&uid";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=1;
|
||||
%end;
|
||||
run;
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_adduser2group.sas
|
||||
,msg=%str(Issue submitting query to SASjsApi/group)
|
||||
)
|
||||
|
||||
libname &libref JSON fileref=&fref1;
|
||||
|
||||
data &outds;
|
||||
set &libref..users;
|
||||
drop ordinal_root ordinal_users;
|
||||
%if &mdebug=1 %then %do;
|
||||
putlog _all_;
|
||||
%end;
|
||||
run;
|
||||
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_creategroup.sas
|
||||
,msg=%str(Issue reading response JSON)
|
||||
)
|
||||
|
||||
/* reset options */
|
||||
options &optval;
|
||||
|
||||
%if &mdebug=0 %then %do;
|
||||
filename &fref0 clear;
|
||||
filename &fref1 clear;
|
||||
libname &libref clear;
|
||||
%end;
|
||||
%else %do;
|
||||
data _null_;
|
||||
infile &fref1;
|
||||
input;
|
||||
putlog _infile_;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%mend ms_adduser2group;
|
||||
@@ -266,7 +266,7 @@ data _null_;
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &i>1 %then "," ; ';
|
||||
put ' %if &action=OBJ %then """&&name&i"":" ; ';
|
||||
put ' &&name&i ';
|
||||
put ' "&&name&i"n /* name literal for reserved variable names */ ';
|
||||
put ' %end; ';
|
||||
put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
|
||||
put ' /* now write the long strings to _webout 1 byte at a time */ ';
|
||||
@@ -298,7 +298,7 @@ data _null_;
|
||||
put ' do i=1 to &numcols; ';
|
||||
put ' name=quote(trim(symget(cats(''name'',i)))); ';
|
||||
put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
|
||||
put ' label=quote(trim(symget(cats(''label'',i)))); ';
|
||||
put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
|
||||
put ' length=quote(trim(symget(cats(''length'',i)))); ';
|
||||
put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
|
||||
put ' if i>1 then put "," @@; ';
|
||||
@@ -317,18 +317,19 @@ data _null_;
|
||||
put '%end; ';
|
||||
put '%mend mp_jsonout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put '%macro mf_getuser( ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' %local user; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
put ' %else %if %symexist(&metavar) %then %do; ';
|
||||
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
|
||||
put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
|
||||
put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
|
||||
put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
put ' %end; ';
|
||||
put ' %else %if %symexist(_metaperson) %then %do; ';
|
||||
put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
|
||||
put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
|
||||
put ' /* but be sure to quote in case of usernames with commas */ ';
|
||||
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
|
||||
put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
|
||||
put ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
|
||||
@@ -2,13 +2,24 @@
|
||||
@file
|
||||
@brief Fetches the list of groups from SASjs Server
|
||||
@details Fetches the list of groups from SASjs Server and writes them to an
|
||||
output dataset.
|
||||
output dataset. Provide a username to filter for the groups for a particular
|
||||
user.
|
||||
|
||||
Example:
|
||||
|
||||
%ms_getgroups(outds=userlist)
|
||||
|
||||
With filter on username:
|
||||
|
||||
%ms_getgroups(outds=userlist, user=James)
|
||||
|
||||
With filter on userid:
|
||||
|
||||
%ms_getgroups(outds=userlist, uid=1)
|
||||
|
||||
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
|
||||
@param [in] user= (0) Provide the username on which to filter
|
||||
@param [in] uid= (0) Provide the userid on which to filter
|
||||
@param [out] outds= (work.ms_getgroups) This output dataset will contain the
|
||||
list of groups. Format:
|
||||
|NAME:$32.|DESCRIPTION:$64.|GROUPID:best.|
|
||||
@@ -25,22 +36,38 @@
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li ms_creategroup.sas
|
||||
@li ms_getusers.test.sas
|
||||
@li ms_getgroups.test.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_getgroups(
|
||||
outds=work.ms_getgroups
|
||||
,mdebug=0
|
||||
);
|
||||
user=0,
|
||||
uid=0,
|
||||
outds=work.ms_getgroups,
|
||||
mdebug=0
|
||||
);
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getusers.sas
|
||||
,mac=ms_getgroups.sas
|
||||
,msg=%str(syscc=&syscc on macro entry)
|
||||
)
|
||||
|
||||
%local fref0 fref1 libref optval rc msg;
|
||||
%local fref0 fref1 libref optval rc msg url;
|
||||
|
||||
%if %sysget(MODE)=desktop %then %do;
|
||||
/* groups api does not exist in desktop mode */
|
||||
data &outds;
|
||||
length NAME $32 DESCRIPTION $64. GROUPID 8;
|
||||
name="&sysuserid";
|
||||
description="&sysuserid (group - desktop mode)";
|
||||
groupid=1;
|
||||
output;
|
||||
stop;
|
||||
run;
|
||||
%return;
|
||||
%end;
|
||||
|
||||
%let fref0=%mf_getuniquefileref();
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let libref=%mf_getuniquelibref();
|
||||
@@ -65,8 +92,13 @@ run;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%if "&user" ne "0" %then %let url=/SASjsApi/user/by/username/&user;
|
||||
%else %if "&uid" ne "0" %then %let url=/SASjsApi/user/&uid;
|
||||
%else %let url=/SASjsApi/group;
|
||||
|
||||
|
||||
proc http method='GET' headerin=&fref0 out=&fref1
|
||||
url="&_sasjs_apiserverurl/SASjsApi/group";
|
||||
url="&_sasjs_apiserverurl.&url";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=1;
|
||||
%end;
|
||||
@@ -75,21 +107,31 @@ run;
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getgroups.sas
|
||||
,msg=%str(Issue submitting GET query to SASjsApi/group)
|
||||
,msg=%str(Issue submitting GET query to SASjsApi)
|
||||
)
|
||||
|
||||
libname &libref JSON fileref=&fref1;
|
||||
|
||||
data &outds;
|
||||
length NAME $32 DESCRIPTION $64. GROUPID 8;
|
||||
if _n_=1 then call missing(of _all_);
|
||||
set &libref..root;
|
||||
drop ordinal_root;
|
||||
run;
|
||||
%if "&user"="0" and "&uid"="0" %then %do;
|
||||
data &outds;
|
||||
length NAME $32 DESCRIPTION $64. GROUPID 8;
|
||||
if _n_=1 then call missing(of _all_);
|
||||
set &libref..root;
|
||||
drop ordinal_root;
|
||||
run;
|
||||
%end;
|
||||
%else %do;
|
||||
data &outds;
|
||||
length NAME $32 DESCRIPTION $64. GROUPID 8;
|
||||
if _n_=1 then call missing(of _all_);
|
||||
set &libref..groups;
|
||||
drop ordinal_:;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getusers.sas
|
||||
,mac=ms_getgroups.sas
|
||||
,msg=%str(Issue reading response JSON)
|
||||
)
|
||||
|
||||
|
||||
@@ -2,16 +2,26 @@
|
||||
@file
|
||||
@brief Fetches the list of users from SASjs Server
|
||||
@details Fetches the list of users from SASjs Server and writes them to an
|
||||
output dataset.
|
||||
output dataset. Can also be filtered, for a particular group.
|
||||
|
||||
Example:
|
||||
|
||||
%ms_getusers(outds=userlist)
|
||||
|
||||
Filtering for a group by group name:
|
||||
|
||||
%ms_getusers(outds=work.groupmembers, group=GROUPNAME)
|
||||
|
||||
Filtering for a group by group id:
|
||||
|
||||
%ms_getusers(outds=work.groupmembers, gid=1)
|
||||
|
||||
@param [in] mdebug= (0) Set to 1 to enable DEBUG messages
|
||||
@param [in] group= (0) Set to a group name to filter members for that group
|
||||
@param [in] gid= (0) Set to a group id to filter members for that group
|
||||
@param [out] outds= (work.ms_getusers) This output dataset will contain the
|
||||
list of user accounts. Format:
|
||||
|DISPLAYNAME:$18.|USERNAME:$10.|ID:best.|
|
||||
|DISPLAYNAME:$60.|USERNAME:$30.|ID:best.|
|
||||
|---|---|---|
|
||||
|`Super Admin `|`secretuser `|`1`|
|
||||
|`Sabir Hassan`|`sabir`|`2`|
|
||||
@@ -20,7 +30,6 @@
|
||||
|`New User `|`newuser `|`5`|
|
||||
|
||||
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquefileref.sas
|
||||
@li mf_getuniquelibref.sas
|
||||
@@ -28,14 +37,17 @@
|
||||
|
||||
<h4> Related Files </h4>
|
||||
@li ms_createuser.sas
|
||||
@li ms_getgroups.sas
|
||||
@li ms_getusers.test.sas
|
||||
|
||||
**/
|
||||
|
||||
%macro ms_getusers(
|
||||
outds=work.ms_getusers
|
||||
,mdebug=0
|
||||
);
|
||||
outds=work.ms_getusers,
|
||||
group=0,
|
||||
gid=0,
|
||||
mdebug=0
|
||||
);
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
@@ -43,11 +55,24 @@
|
||||
,msg=%str(syscc=&syscc on macro entry)
|
||||
)
|
||||
|
||||
%local fref0 fref1 libref optval rc msg;
|
||||
%local fref0 fref1 libref optval rc msg url;
|
||||
%let fref0=%mf_getuniquefileref();
|
||||
%let fref1=%mf_getuniquefileref();
|
||||
%let libref=%mf_getuniquelibref();
|
||||
|
||||
%if %sysget(MODE)=desktop %then %do;
|
||||
/* users api does not exist in desktop mode */
|
||||
data &outds;
|
||||
length DISPLAYNAME $60 USERNAME:$30 ID 8;
|
||||
USERNAME="&sysuserid";
|
||||
DISPLAYNAME="&sysuserid (desktop mode)";
|
||||
ID=1;
|
||||
output;
|
||||
stop;
|
||||
run;
|
||||
%return;
|
||||
%end;
|
||||
|
||||
/* avoid sending bom marker to API */
|
||||
%let optval=%sysfunc(getoption(bomfile));
|
||||
options nobomfile;
|
||||
@@ -68,26 +93,40 @@ run;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%if "&group" ne "0" %then %let url=/SASjsApi/group/by/groupname/&group;
|
||||
%else %if "&gid" ne "0" %then %let url=/SASjsApi/group/&gid;
|
||||
%else %let url=/SASjsApi/user;
|
||||
|
||||
proc http method='GET' headerin=&fref0 out=&fref1
|
||||
url="&_sasjs_apiserverurl/SASjsApi/user";
|
||||
url="&_sasjs_apiserverurl.&url";
|
||||
%if &mdebug=1 %then %do;
|
||||
debug level=1;
|
||||
%end;
|
||||
run;
|
||||
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
,mac=ms_getusers.sas
|
||||
,msg=%str(Issue submitting GET query to SASjsApi/user)
|
||||
,msg=%str(Issue submitting API query)
|
||||
)
|
||||
|
||||
libname &libref JSON fileref=&fref1;
|
||||
|
||||
data &outds;
|
||||
set &libref..root;
|
||||
drop ordinal_root;
|
||||
run;
|
||||
|
||||
%if "&group"="0" and "&gid"="0" %then %do;
|
||||
data &outds;
|
||||
length DISPLAYNAME $60 USERNAME:$30 ID 8;
|
||||
set &libref..root;
|
||||
drop ordinal_root;
|
||||
run;
|
||||
%end;
|
||||
%else %do;
|
||||
data &outds;
|
||||
length DISPLAYNAME $60 USERNAME:$30 ID 8;
|
||||
set &libref..users;
|
||||
drop ordinal_root ordinal_users;
|
||||
run;
|
||||
%end;
|
||||
|
||||
%mp_abort(
|
||||
iftrue=(&syscc ne 0)
|
||||
|
||||
52
tests/serveronly/ms_adduser2group.test.sas
Normal file
52
tests/serveronly/ms_adduser2group.test.sas
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
@file
|
||||
@brief Testing ms_adduser2group.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquename.sas
|
||||
@li mp_assert.sas
|
||||
@li mp_assertscope.sas
|
||||
@li ms_adduser2group.sas
|
||||
@li ms_creategroup.sas
|
||||
|
||||
**/
|
||||
|
||||
/* first, create an empty group */
|
||||
%let group=%substr(%mf_getuniquename(),1,8);
|
||||
%ms_creategroup(&group, desc=The description,mdebug=&sasjs_mdebug,outds=test1a)
|
||||
%let groupid=0;
|
||||
data _null_;
|
||||
set work.test1a;
|
||||
call symputx('groupid',groupid);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&groupid>0),
|
||||
desc=Checking that group was created with an ID,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
/* now add a user (user 1 always exists) */
|
||||
|
||||
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%ms_adduser2group(uid=1,gid=&groupid,mdebug=&sasjs_mdebug,outds=test1)
|
||||
%mp_assertscope(COMPARE
|
||||
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADPNUM MCLIB0_JADVLEN
|
||||
)
|
||||
|
||||
/* check the user is in the output list */
|
||||
%let checkid=0;
|
||||
data _null_;
|
||||
set work.test1;
|
||||
if id=1 then call symputx('checkid',1);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&checkid=1),
|
||||
desc=Checking that user was created in the new group,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ run;
|
||||
%let checkid=0;
|
||||
data _null_;
|
||||
set work.test2;
|
||||
where name="&group";
|
||||
where upcase(name)="%upcase(&group)";
|
||||
call symputx('checkid',groupid);
|
||||
run;
|
||||
%mp_assert(
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
data _null_;
|
||||
set work.test1;
|
||||
call symputx('id',id);
|
||||
putlog (_all_)(=);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&id>0),
|
||||
@@ -35,7 +36,8 @@ run;
|
||||
%let checkid=0;
|
||||
data _null_;
|
||||
set work.test2;
|
||||
where username="&user";
|
||||
if _n_<20 then putlog (_all_)(=);
|
||||
if upcase(username)="%upcase(&user)";
|
||||
call symputx('checkid',id);
|
||||
run;
|
||||
%mp_assert(
|
||||
|
||||
@@ -3,21 +3,64 @@
|
||||
@brief Testing ms_getgroups.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getuniquename.sas
|
||||
@li ms_adduser2group.sas
|
||||
@li ms_creategroup.sas
|
||||
@li ms_getgroups.sas
|
||||
@li mp_assert.sas
|
||||
@li mp_assertdsobs.sas
|
||||
@li mp_assertscope.sas
|
||||
|
||||
**/
|
||||
|
||||
/* create a group */
|
||||
%let group=%substr(%mf_getuniquename(),1,8);
|
||||
%ms_creategroup(&group, desc=The description,mdebug=&sasjs_mdebug,outds=test1)
|
||||
|
||||
/* get groups */
|
||||
%mp_assertscope(SNAPSHOT)
|
||||
%ms_getgroups(outds=work.test1,mdebug=&sasjs_mdebug)
|
||||
%mp_assertscope(COMPARE
|
||||
,ignorelist=MCLIB0_JADP1LEN MCLIB0_JADPNUM MCLIB0_JADVLEN
|
||||
)
|
||||
|
||||
/* check the group was created */
|
||||
%mp_assertdsobs(work.test1,test=ATLEAST 1)
|
||||
|
||||
%let test2=0;
|
||||
%put &=group;
|
||||
data _null_;
|
||||
set work.test1;
|
||||
putlog (_all_)(=);
|
||||
if upcase(name)="%upcase(&group)" then do;
|
||||
putlog "&group found!";
|
||||
call symputx('test2',1);
|
||||
call symputx('gid',groupid); /* used in next test */
|
||||
end;
|
||||
run;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=("&test2"="1"),
|
||||
desc=Checking group was created,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
/* now check if the filter for the groups for a user works */
|
||||
|
||||
/* add a member */
|
||||
%ms_adduser2group(uid=1,gid=&gid)
|
||||
|
||||
%ms_getgroups(user=secretuser,outds=work.test3)
|
||||
|
||||
%let test3=0;
|
||||
data _null_;
|
||||
set work.test3;
|
||||
if groupid=&gid then call symputx('test3',1);
|
||||
run;
|
||||
|
||||
%mp_assert(
|
||||
iftrue=("&test3"="1"),
|
||||
desc=Checking group list was returned for a user,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
@brief Testing ms_getusers.sas macro
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li ms_creategroup.sas
|
||||
@li ms_adduser2group.sas
|
||||
@li ms_getusers.sas
|
||||
@li mp_assertdsobs.sas
|
||||
@li mp_assertscope.sas
|
||||
@@ -18,6 +20,39 @@
|
||||
|
||||
%mp_assertdsobs(work.test1,test=ATLEAST 1)
|
||||
|
||||
/**
|
||||
* test the extraction of group members
|
||||
*/
|
||||
|
||||
/* create a group */
|
||||
%let group=%substr(%mf_getuniquename(),1,8);
|
||||
%ms_creategroup(&group, desc=some desc,mdebug=&sasjs_mdebug,outds=work.group)
|
||||
%let gid=0;
|
||||
data _null_;
|
||||
set work.group;
|
||||
call symputx('gid',groupid);
|
||||
run;
|
||||
|
||||
/* add a member */
|
||||
%ms_adduser2group(uid=1,gid=&gid)
|
||||
|
||||
/* extract the members */
|
||||
%ms_getusers(group=&group,outds=test2)
|
||||
|
||||
/* check the user is in the output list */
|
||||
%let checkid=0;
|
||||
data _null_;
|
||||
set work.test2;
|
||||
if id=1 then call symputx('checkid',1);
|
||||
run;
|
||||
%mp_assert(
|
||||
iftrue=(&checkid=1),
|
||||
desc=Checking that admin user was created in the new group,
|
||||
outds=work.test_results
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ options mprint;
|
||||
)
|
||||
%mp_assertscope(COMPARE)
|
||||
|
||||
libname webeen json (weboot);
|
||||
libname webeen json fileref=weboot;
|
||||
|
||||
data _null_;
|
||||
infile weboot;
|
||||
|
||||
@@ -10,7 +10,12 @@
|
||||
**/
|
||||
|
||||
filename ft15f001 temp;
|
||||
parmcards4;
|
||||
data _null_;
|
||||
file ft15f001;
|
||||
infile cards;
|
||||
input;
|
||||
put _infile_;
|
||||
cards4;
|
||||
%put Initialising sendObj: ;
|
||||
%put _all_;
|
||||
%webout(FETCH)
|
||||
@@ -27,6 +32,7 @@ parmcards4;
|
||||
%mend x; %x()
|
||||
%webout(CLOSE)
|
||||
;;;;
|
||||
run;
|
||||
%put creating web service: &mcTestAppLoc/services;
|
||||
%ms_createwebservice(
|
||||
path=&mcTestAppLoc/services,
|
||||
|
||||
@@ -20,7 +20,7 @@ run;
|
||||
%ms_webout(OBJ,datasets,fref=&fref)
|
||||
%ms_webout(CLOSE,fref=&fref)
|
||||
|
||||
libname test JSON (&fref);
|
||||
libname test JSON fileref=&fref;
|
||||
data root;
|
||||
set test.root;
|
||||
call symputx('checkval',sysvlong);
|
||||
|
||||
@@ -408,7 +408,7 @@ data _null_;
|
||||
put ' %do i=1 %to &numcols; ';
|
||||
put ' %if &i>1 %then "," ; ';
|
||||
put ' %if &action=OBJ %then """&&name&i"":" ; ';
|
||||
put ' &&name&i ';
|
||||
put ' "&&name&i"n /* name literal for reserved variable names */ ';
|
||||
put ' %end; ';
|
||||
put ' %if &action=ARR %then "]" ; %else "}" ; ; ';
|
||||
put ' /* now write the long strings to _webout 1 byte at a time */ ';
|
||||
@@ -440,7 +440,7 @@ data _null_;
|
||||
put ' do i=1 to &numcols; ';
|
||||
put ' name=quote(trim(symget(cats(''name'',i)))); ';
|
||||
put ' format=quote(trim(symget(cats(''fmt'',i)))); ';
|
||||
put ' label=quote(trim(symget(cats(''label'',i)))); ';
|
||||
put ' label=quote(prxchange(''s/\\/\\\\/'',-1,trim(symget(cats(''label'',i))))); ';
|
||||
put ' length=quote(trim(symget(cats(''length'',i)))); ';
|
||||
put ' type=quote(trim(symget(cats(''typelong'',i)))); ';
|
||||
put ' if i>1 then put "," @@; ';
|
||||
@@ -459,18 +459,19 @@ data _null_;
|
||||
put '%end; ';
|
||||
put '%mend mp_jsonout; ';
|
||||
put ' ';
|
||||
put '%macro mf_getuser(type=META ';
|
||||
put '%macro mf_getuser( ';
|
||||
put ')/*/STORE SOURCE*/; ';
|
||||
put ' %local user metavar; ';
|
||||
put ' %if &type=OS %then %let metavar=_secureusername; ';
|
||||
put ' %else %let metavar=_metaperson; ';
|
||||
put ' %local user; ';
|
||||
put ' ';
|
||||
put ' %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
put ' %else %if %symexist(&metavar) %then %do; ';
|
||||
put ' %if %length(&&&metavar)=0 %then %let user=&sysuserid; ';
|
||||
put ' %if %symexist(_sasjs_username) %then %let user=&_sasjs_username; ';
|
||||
put ' %else %if %symexist(SYS_COMPUTE_SESSION_OWNER) %then %do; ';
|
||||
put ' %let user=&SYS_COMPUTE_SESSION_OWNER; ';
|
||||
put ' %end; ';
|
||||
put ' %else %if %symexist(_metaperson) %then %do; ';
|
||||
put ' %if %length(&_metaperson)=0 %then %let user=&sysuserid; ';
|
||||
put ' /* sometimes SAS will add @domain extension - remove for consistency */ ';
|
||||
put ' /* but be sure to quote in case of usernames with commas */ ';
|
||||
put ' %else %let user=%unquote(%scan(%quote(&&&metavar),1,@)); ';
|
||||
put ' %else %let user=%unquote(%scan(%quote(&_metaperson),1,@)); ';
|
||||
put ' %end; ';
|
||||
put ' %else %let user=&sysuserid; ';
|
||||
put ' ';
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
@file mx_createwebservice.sas
|
||||
@brief Create a web service in SAS 9, Viya or SASjs
|
||||
@details Creates a SASJS ready Stored Process in SAS 9, a Job Execution
|
||||
Service in SAS Viya, and a Stored Program on SASjs Server
|
||||
Service in SAS Viya, or a Stored Program on SASjs Server - depending on the
|
||||
executing environment.
|
||||
|
||||
Usage:
|
||||
|
||||
@@ -24,7 +25,9 @@ Usage:
|
||||
%webout(OBJ,example2) * Object format, easier to work with ;
|
||||
%webout(CLOSE)
|
||||
;;;;
|
||||
%mp_createwebservice(path=/Public/app/common,name=appInit,replace=YES)
|
||||
|
||||
%* create the service (including webout macro and dependencies);
|
||||
%mx_createwebservice(path=/Public/app/common,name=appInit,replace=YES)
|
||||
|
||||
<h4> SAS Macros </h4>
|
||||
@li mf_getplatform.sas
|
||||
@@ -43,7 +46,6 @@ Usage:
|
||||
location
|
||||
@param [in] mDebug= (0) set to 1 to show debug messages in the log
|
||||
|
||||
@version 9.2
|
||||
@author Allan Bowe
|
||||
|
||||
**/
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
%if &platform=SASJS %then %do;
|
||||
%ms_getfile(&loc..sas, outref=&outref)
|
||||
%end;
|
||||
%else %if &platform=SAS9 %then %do;
|
||||
%mm_getstpcode(tree=&loc,outloc=&outref)
|
||||
%else %if &platform=SAS9 or &platform=SASMETA %then %do;
|
||||
%mm_getstpcode(tree=&loc,outref=&outref)
|
||||
%end;
|
||||
%else %if &platform=SASVIYA %then %do;
|
||||
/* extract name & path from &loc */
|
||||
|
||||
Reference in New Issue
Block a user