-signatures,-async_await;
use
Mojo::JSON
qw(encode_json decode_json from_json)
;
has
service
=>
'default'
;
my
%allow
= (
getBaseConfig
=> 1,
login
=> 1,
logout
=> 1,
ping
=> 1,
getUserConfig
=> 2,
getPluginConfig
=> 3,
validatePluginData
=> 3,
processPluginData
=> 3,
getPluginData
=> 3,
getSessionCookie
=> 2
);
has
config
=>
sub
(
$self
) {
$self
->app->config;
},
weak
=> 1;
has
user
=>
sub
(
$self
) {
my
$obj
=
$self
->app->userObject->new(
app
=>
$self
->app,
controller
=>
$self
,
log
=>
$self
->
log
);
return
$obj
;
};
has
pluginMap
=>
sub
(
$self
) {
my
$map
=
$self
->config->cfgHash->{PLUGIN};
return
$map
;
},
weak
=> 1;
sub
allow_rpc_access (
$self
,
$method
) {
if
(not
$self
->req->method eq
'POST'
) {
$self
->
log
->error(
"refused "
.
$self
->req->method.
" request"
);
return
0;
}
if
(not
exists
$allow
{
$method
}){
return
0;
}
for
(
$allow
{
$method
}){
/1/ &&
return
1;
return
1
if
(
$self
->user->isUserAuthenticated);
/3/ &&
do
{
my
$plugin
=
$self
->rpcParams->[0];
if
(
$self
->config->instantiatePlugin(
$plugin
,
$self
->user)->mayAnonymous){
return
1;
}
};
}
return
0;
};
has
passMatch
=>
sub
(
$self
) {
qr{(?i)(?:password|_pass)}
;
};
sub
perMethodCleaner (
$self
,
$method
=
undef
) {
$method
or
return
;
return
{
login
=>
sub
{
my
$data
=
shift
;
if
(
ref
$data
eq
'ARRAY'
){
$data
->[1] =
'xxx'
;
}
return
;
}
}->{
$method
};
};
sub
dataCleaner (
$self
,
$data
,
$method
=
undef
) {
if
(
my
$perMethodCleaner
=
$self
->perMethodCleaner(
$method
)){
return
$perMethodCleaner
->(
$data
);
}
my
$match
=
$self
->passMatch;
my
$type
=
ref
$data
;
for
(
$type
) {
/ARRAY/ &&
do
{
$self
->dataCleaner(
$_
)
for
@$data
;
};
/HASH/ &&
do
{
for
my
$key
(
keys
%$data
) {
my
$value
=
$data
->{
$key
};
if
(
$key
=~ /
$match
/){
$data
->{
$key
} =
'xxx'
;
}
elsif
(
ref
$value
){
$self
->dataCleaner(
$value
);
}
}
}
}
}
sub
logRpcCall {
my
$self
=
shift
;
if
(
$ENV
{CALLBACKERY_RPC_LOG}){
my
$method
=
shift
;
my
$data
=
shift
;
$self
->dataCleaner(
$data
,
$method
);
my
$userId
=
eval
{
$self
->user->loginName } //
'*UNKNOWN*'
;
my
$remoteAddr
=
$self
->tx->remote_address;
$self
->
log
->debug(
"[$userId|$remoteAddr] CALL $method("
.encode_json(
$data
).
")"
);
}
else
{
$self
->SUPER::logRpcCall(
@_
);
}
}
sub
logRpcReturn {
my
$self
=
shift
;
if
(
$ENV
{CALLBACKERY_RPC_LOG}){
my
$data
=
shift
;
$self
->dataCleaner(
$data
);
my
$userId
=
eval
{
$self
->user->loginName } //
'*UNKNOWN*'
;
my
$remoteAddr
=
$self
->tx->remote_address;
$self
->
log
->debug(
"[$userId|$remoteAddr] RETURN "
.encode_json(
$data
).
")"
);
}
else
{
$self
->SUPER::logRpcReturn(
@_
);
}
}
sub
ping {
return
'pong'
;
}
sub
getSessionCookie {
shift
->user->makeSessionCookie();
}
sub
getBaseConfig {
my
$self
=
shift
;
return
$self
->config->cfgHash->{FRONTEND};
}
async
sub
login {
my
$self
=
shift
;
my
$login
=
shift
;
my
$password
=
shift
;
my
$cfg
=
$self
->config->cfgHash->{BACKEND};
if
(
my
$ok
=
await
$self
->config->promisify(
$self
->user->login(
$login
,
$password
))){
return
{
sessionCookie
=>
$self
->user->makeSessionCookie()
}
}
else
{
return
;
}
}
sub
logout {
my
$self
=
shift
;
$self
->session(
expires
=>1);
}
async
sub
instantiatePlugin_p {
my
$self
=
shift
;
my
$name
=
shift
;
my
$args
=
shift
;
my
$user
=
$self
->user;
my
$plugin
= await
$self
->config->instantiatePlugin_p(
$name
,
$user
,
$args
);
$plugin
->
log
(
$self
->
log
);
return
$plugin
;
}
sub
instantiatePlugin {
my
$self
=
shift
;
my
$name
=
shift
;
my
$args
=
shift
;
my
$user
=
$self
->user;
my
$plugin
=
$self
->config->instantiatePlugin(
$name
,
$user
,
$args
);
$plugin
->
log
(
$self
->
log
);
return
$plugin
;
}
async
sub
processPluginData {
my
$self
=
shift
;
my
$plugin
=
shift
;
my
@args
=
@_
;
my
$instance
= await
$self
->instantiatePlugin_p(
$plugin
);
return
$instance
->processData(
@args
);
}
async
sub
validatePluginData {
my
$self
=
shift
;
my
$plugin
=
shift
;
my
@args
=
@_
;
return
(await
$self
->instantiatePlugin_p(
$plugin
))
->validateData(
@args
);
}
async
sub
getPluginData {
my
$self
=
shift
;
my
$plugin
=
shift
;
my
@args
=
@_
;
return
(await
$self
->instantiatePlugin_p(
$plugin
))
->getData(
@args
);
}
async
sub
getUserConfig {
my
$self
=
shift
;
my
$args
=
shift
;
my
@plugins
;
for
my
$plugin
(
$self
->pluginMap->{list}->@*){
try
{
my
$obj
= await
$self
->instantiatePlugin_p(
$plugin
,
$args
);
push
@plugins
, {
tabName
=>
$obj
->tabName,
name
=>
$obj
->name,
instantiationMode
=>
$obj
->instantiationMode
};
}
catch
(
$error
) {
warn
"$error"
;
}
}
my
$userConfig
= await
$self
->config->promisify(
$self
->user->userInfo);
return
{
userInfo
=>
$userConfig
,
plugins
=> \
@plugins
,
};
}
async
sub
getPluginConfig {
my
$self
=
shift
;
my
$plugin
=
shift
;
my
$args
=
shift
;
my
$obj
= await
$self
->instantiatePlugin_p(
$plugin
,
$args
);
return
$obj
->filterHashKey(
$obj
->screenCfg,
'backend'
);
}
sub
runEventActions {
my
$self
=
shift
;
my
$event
=
shift
;
my
@args
=
@_
;
for
my
$obj
(@{
$self
->config->configPlugins}){
if
(
my
$action
=
$obj
->eventActions->{
$event
}){
$action
->(
@args
)
}
}
}
my
$runPreDestroyActions
=
sub
{
my
$self
=
shift
;
my
$actions
=
$self
->{preDestroyActions} // {};
$self
->
log
->debug(
'destroying controller'
);
for
my
$key
(
keys
%$actions
){
$self
->
log
->debug(
'running preDestroyAction '
.
$key
);
eval
{
$actions
->{
$key
}->();
};
if
($@){
$self
->
log
->error(
"preDestoryAction $key: "
.$@);
}
delete
$actions
->{
$key
};
}
delete
$self
->{preDestroyActions}
};
sub
setPreDestroyAction {
my
$self
=
shift
;
my
$key
=
shift
;
my
$cb
=
shift
;
if
(not
$self
->{preDestroyActions}){
Mojo::IOLoop->timer(
"0.2"
=>
sub
{
$self
->
$runPreDestroyActions
});
}
$self
->{preDestroyActions}{
$key
} =
$cb
;
}
async
sub
handleUpload {
my
$self
=
shift
;
$self
->render_later;
if
(not
$self
->user->isUserAuthenticated){
return
$self
->render(
json
=> {
exception
=>{
message
=>trm(
'Access Denied'
),
code
=>4922}});
}
my
$name
=
$self
->req->param(
'name'
);
if
(not
$name
){
return
$self
->render(
json
=> {
exception
=>{
message
=>trm(
'Plugin Name missing'
),
code
=>3934}});
}
my
$upload
=
$self
->req->upload(
'file'
);
if
(not
$upload
){
return
$self
->render(
json
=> {
exception
=>{
message
=>trm(
'Upload Missing'
),
code
=>9384}});
}
my
$obj
= await
$self
->instantiatePlugin_p(
$name
);
my
$form
;
if
(
my
$formData
=
$self
->req->param(
'formData'
)){
$form
=
eval
{ decode_json(
$formData
) };
if
($@){
return
$self
->render(
json
=>{
exception
=>{
message
=>trm(
'Data Decoding Problem %1'
,$@),
code
=>7932}});
}
}
$form
->{uploadObj} =
$upload
;
my
$return
;
try
{
$return
= await
$self
->config->promisify(
$obj
->processData({
key
=>
$self
->req->param(
'key'
),
formData
=>
$form
,
}));
}
catch
(
$error
) {
if
(blessed
$error
){
if
(
$error
->isa(
'CallBackery::Exception'
)){
return
$self
->render(
json
=>{
exception
=>{
message
=>
$error
->message,
code
=>
$error
->code}});
}
elsif
(
$error
->isa(
'Mojo::Exception'
)){
return
$self
->render(
json
=>{
exception
=>{
message
=>
$error
->message,
code
=>9999}});
}
}
return
$self
->render(
json
=>{
exception
=>{
message
=>
$error
,
code
=>9999}});
}
return
$self
->render(
json
=>
$return
);
}
async
sub
handleDownload {
my
$self
=
shift
;
if
(not
$self
->user->isUserAuthenticated){
return
$self
->render(
json
=>{
exception
=>{
message
=>trm(
'Access Denied'
),
code
=>3928}});
}
my
$name
=
$self
->param(
'name'
);
my
$key
=
$self
->param(
'key'
);
if
(not
$name
){
return
$self
->render(
json
=>{
exception
=>{
message
=>trm(
'Plugin Name missing'
),
code
=>3923}});
}
$self
->render_later;
my
$obj
= await
$self
->instantiatePlugin_p(
$name
);
my
$form
;
if
(
my
$formData
=
$self
->req->param(
'formData'
)){
$form
=
eval
{ from_json(
$formData
) };
if
($@){
return
$self
->render(
json
=>{
exception
=>{
message
=>trm(
'Data Decoding Problem %1'
,$@),
code
=>3923}});
}
}
my
$map
;
try
{
$map
= await
$self
->config->promisify(
$obj
->processData({
key
=>
$key
,
formData
=>
$form
,
}));
}
catch
(
$error
) {
if
(blessed
$error
){
if
(
$error
->isa(
'CallBackery::Exception'
)){
return
$self
->render(
json
=>{
exception
=>{
message
=>
$error
->message,
code
=>
$error
->code}});
}
elsif
(
$error
->isa(
'Mojo::Exception'
)){
return
$self
->render(
json
=>{
exception
=>{
message
=>
$error
->message,
code
=>9999}});
}
}
return
$self
->render(
json
=>{
exception
=>{
message
=>
$error
,
code
=>9999}});
}
$self
->res->headers->content_type(
$map
->{type}.
';name='
.
$map
->{filename});
if
(not
$self
->param(
'display'
)) {
$self
->res->headers->content_disposition(
'attachment;filename='
.
$map
->{filename});
}
$self
->res->content->asset(
$map
->{asset});
$self
->rendered(200);
}
sub
DESTROY (
$self
) {
my
$class
=
ref
(
$self
) //
"child of "
. __PACKAGE__;
if
(${^GLOBAL_PHASE} ne
'DESTRUCT'
) {
return
;
}
if
(blessed
$self
&&
ref
$self
->
log
){
$self
->
log
->debug(
"late destruction of $class object during global destruction"
);
return
;
}
warn
"extra late destruction of $class object during global destruction\n"
;
}
1;