Questions and discussion about developing processes and programming in PHP, JavaScript, web services & REST API.

Moderator: amosbatto

Forum rules: Please search to see if a question has already asked before creating a new topic. Please don't post the same question in multiple forums.
#823569
Hi,
I am trying to call the PMFCreateUser () from within my endpoint class that i created
Code: Select all
 
/**
 * @url POST /save/client
*/
public function saveUser(){
            //Get values of the posted input
            $first_name = $_POST['first_name'];
            $last_name = $_POST['last_name'];
            $password = $_POST['password'];
            $rPassword = $_POST['rpassword'];
            $email = $_POST['email'];
            $court_address = $_POST['court_address'];
            $lawyer_level = $_POST['lawyer_level'];
            $lawyer_number = $_POST['lawyer_number'];     
            isset($_POST['pmUid'])  ? $pmUid = $_POST['pmUid']  :  $pmUid = "";  
            PMFCreateUser($lawyer_number, $password, $first_name, $last_name, $email, "LAWYER_CLIENT");
  }
Code: Select all
[2019-03-26 23:48:13] production.ERROR: Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function initRBAC() on null in /opt/processmaker/workflow/engine/classes/WsBase.php:1111
Stack trace:
#0 /opt/processmaker/workflow/engine/classes/class.pmFunctions.php(2209): WsBase->createUser('55555', 'xc', 'wxc', '[email protected]', 'LAWYER_CLIENT', '55555', NULL, NULL)
#1 /opt/plugins/estamp/estamp/src/Services/Api/Estamp/Client.php(165): PMFCreateUser('55555', '55555', 'xc', 'wxc', '[email protected]', 'LAWYER_CLIENT')
#2 [internal function]: Services\Api\Estamp\Client->saveUser()
#3 /opt/processmaker/framework/src/Maveriks/Extension/Restler.php(169): call_user_func_array(Array, Array)
#4 /opt/processmaker/vendor/luracast/restler/vendor/Luracast/Restler/Restler.php(278): Maveriks\Extension\Restler->call()
#5 /opt/processmaker/framework/src/Maveriks/WebApplication.php(245): Luracast\Restler\Restler->handle()
#6 /opt/processmaker/framework/src/Maveriks/WebApplication.php(158): Maveriks\WebApplication->dispatchApiRequest('/estamp/save/cl...', '1.0')
#7 /opt/processmaker/workflow/public_html/app.php(49): Maveriks\WebApplication->run('service.api')
#8 {main} 
I read in another post that this is due to a login problem, but I thought that once we are authenticated to call rest endpoints it should work just fine.

How we can fix this
Last edited by yasiralqaisi on Fri Mar 29, 2019 2:41 am, edited 1 time in total.
#823580
Unfortunately, we didn't do a good job of documenting how to create a REST plugin. At some point I am going to find the time to improve the documentation.

If you want a user to be logged-in, then you need to add the following line to the header of your function:
Code: Select all
     * @access protected
Then, you can get the ID of the logged-in user with this code in your function:
Code: Select all
            $loggedUserId = $this->getUserId();
Here is an example taken from my extraRest plugin:
Code: Select all
   /**
     * Generate a specified Output Document for a given case, meaning that a PDF, 
     * a DOC or both files (depending on options selected in the definition of the 
     * Output Document) will be created, inserting any variables in the template. 
     * If the Output Document already exists, then it will be regenerated. 
     * If versioning is enabled, then the regenerated files will be given a new 
     * version number and document index number, but if versioning is NOT enabled, 
     * then the existing files will be overwritten with the same version number 
     * and document index number. 
     * 
     * Unlike the official endpoint POST /{app_uid}/{del_index}/output-document/{out_doc_uid}, 
     * this endpoint will look up the delegation index if not specified and allows 
     * Process Supervisors to generate Output Documents for another user assigned to the case. 
     * 
     * @url POST /case/:app_uid/output-document/:out_doc_uid
     * 
     * @param string  $app_uid     Unique ID of open case where the Output Document will be generated. 
     *                             {@min 32}{@max 32}
     * @param string  $out_doc_uid Unique ID of the Output Document definition. {@min 32}{@max 32}
     * @param int     $del_index   Optional. Open delegation index where Output Document will be generated. 
     *                             {@from body}{@min 0} 
     * @param string  $usr_uid     Optional. Unique ID of user who will generate the Output Document. 
     *                             Note that the logged-in user needs to be a Supervisor to the case's process to 
     *                             generate for another user. {@from body}{@max 32}
     *                            
     * @return object
     * @throws RestException 
     * 
     * @access protected
     * @class AccessControl {@permission PM_CASES}
     */
    public function postGenerateOutputDocument($app_uid, $out_doc_uid, $del_index=0, $usr_uid='')
    {
        try {
            $loggedUserId = $this->getUserId();
            
            if (empty($usr_uid)) {
                $usr_uid = $loggedUserId;
            }
            
            $oCase = new \Cases();
            
            if (empty($del_index)) {
               $del_index = $oCase->getCurrentDelegation($app_uid, $usr_uid, true);
            }

            $oAppDel = new \AppDelegation();
            $aDelegation = $oAppDel->load($app_uid, $del_index);

            if ($aDelegation['USR_UID'] != $usr_uid) {
                throw new \Exception("The task is assigned to another user with ID '{$aDelegation['USR_UID']}'."); 
            }
            
            if ($usr_uid != $loggedUserId) {
                //check whether the user exists and has the PM_SUPERVISOR permission in role.
                $rbac = \RBAC::getSingleton();
                $rbac->initRBAC();
            
                if ($rbac->verifyUserId($usr_uid) != 1) {
                    throw new \Exception("User with ID '$usr_uid' does not exist.");
                }
            
                if ($this->userCanAccess('PM_SUPERVISOR') == 0) {
                    throw new \Exception("Logged-in user lacks the PM_SUPERVISOR permission in role.");
                }
                
                //check if logged-in user is assigned as a process supervisor to the process
                $oSuper = new \ProcessMaker\BusinessModel\ProcessSupervisor();
                $aSupervisorList = $oSuper->getProcessSupervisors($aDelegation['PRO_UID'], 'ASSIGNED');
                
                if (!isset($aSupervisorList['data']) or !is_array($aSupervisorList['data'])) {
                    throw new \Exception("Unable to retrieve list of supervisors for process.");
                }
                $isSuperForProcess = false;
                
                foreach ($aSupervisorList['data'] as $aSupervisorInfo) {
                    if ($aSupervisorInfo['usr_uid'] == $loggedUserId) {
                        $isSuperForProcess = true;
                        break;
                    }
                }
                
                if ($isSuperForProcess === false) {
                    throw new \Exception("User '$loggedUserId' must be assigned as a Supervisor for process '".
                       $aDelegation['PRO_UID']."'.");
                }      
            }

            //$case = new \ProcessMaker\BusinessModel\Cases();
            $outputDocument = new \ProcessMaker\BusinessModel\Cases\OutputDocument();
            $outputDocument->throwExceptionIfCaseNotIsInInbox($app_uid, $del_index, $usr_uid);
            $outputDocument->throwExceptionIfOuputDocumentNotExistsInSteps($app_uid, $del_index, $out_doc_uid);
            
            return $outputDocument->addCasesOutputDocument($app_uid, $out_doc_uid, $usr_uid);
        } 
        catch (\Exception $e) {
            throw new RestException(Api::STAT_APP_EXCEPTION, $e->getMessage());
        }
    }
If want to use PMFCreateUser() in your plugin, you can import the workflow/engine/classes/class.pmFunctions.php file which defines that function this way:
Code: Select all
$g = new \G();
$g->LoadClass("pmFunctions");
PMFCreateUser(...);
See: https://wiki.processmaker.com/3.0/Inter ... lass.28.29
#823587
Thanks for the replay
If want to use PMFCreateUser() in your plugin, you can import the workflow/engine/classes/class.pmFunctions.php file which defines that function this way:
CODE: SELECT ALL
$g = new \G();
$g->LoadClass("pmFunctions");
PMFCreateUser(...);
See: https://wiki.processmaker.com/3.0/Inter ... lass.28.29
I used the code above it doesn't work, it gives me the same error, but for more information when I use PMFUserList() it works just fine even without using the G class, it returns the proper data.
#823613
Change your code from:
MFCreateUser($lawyer_number, $password, $first_name, $last_name, $email, "LAWYER_CLIENT");

To:
PMFCreateUser($lawyer_number, $password, $first_name, $last_name, $email, "LAWYER_CLIENT");

(You are missing a "P".)

Was that the problem?
Also make sure that the logged-in user has the PM_USERS permission in his role.
#823642
I investigated this a little more.
The problem is that PMFCreateUser() is calling WsBase::createUser() which is defined in workflow/engine/classes/WsBase.php (or class.wsBase.php in older versions). Here is where it fails on RBAC::initRBAC():
Code: Select all
public function createUser(
        $userName,
        $firstName,
        $lastName,
        $email,
        $role,
        $password,
        $dueDate = null,
        $status = null
    )
    {
        try {
            global $RBAC;

            $RBAC->initRBAC();
It seems that plugins don't have access to the global $RBAC variable and I can't figure out how to correctly initialize it in a plugin.

The only solution that I can think of is for you to use the createUser() web service or REST's POST /user, which means that you need to add code to your plugin to login using web services or oAuth2 for REST. What version of ProcessMaker do you have?
#823643
Stealing some code from workflow/engine/src/ProcessMaker/BusinessModel/User.php, try this:
Code: Select all
    
function MyCreateUser($arrayData) { 
                $rbac = new \RBAC();
                $user = new \Users();

                $rbac->initRBAC();

                $arrayData["USR_PASSWORD"] = \Bootstrap::hashPassword($arrayData["USR_NEW_PASS"]);

                $arrayData["USR_BIRTHDAY"] = (isset($arrayData["USR_BIRTHDAY"])) ? $arrayData["USR_BIRTHDAY"] : date("Y-m-d");
                $arrayData["USR_LOGGED_NEXT_TIME"] = (isset($arrayData["USR_LOGGED_NEXT_TIME"])) ? $arrayData["USR_LOGGED_NEXT_TIME"] : 0;
                $arrayData["USR_CREATE_DATE"] = date("Y-m-d H:i:s");
                $arrayData["USR_UPDATE_DATE"] = date("Y-m-d H:i:s");

                $userUid = $rbac->createUser($arrayData, $arrayData["USR_ROLE"]);

                //Create in workflow
                $arrayData["USR_UID"] = $userUid;
                $arrayData["USR_PASSWORD"] = "00000000000000000000000000000000";

                $result = $user->create($arrayData);

                //User Properties
                $userProperty = new \UsersProperties();

                $aUserProperty = $userProperty->loadOrCreateIfNotExists($arrayData["USR_UID"],
                    array("USR_PASSWORD_HISTORY" => serialize(array(Bootstrap::hashPassword($arrayData["USR_PASSWORD"])))));
                $aUserProperty["USR_LOGGED_NEXT_TIME"] = $arrayData["USR_LOGGED_NEXT_TIME"];

                $userProperty->update($aUserProperty);
}
The array that you need to pass to MyCreateUser() is like the parameters for POST /user.

I haven't had time to test it yet, but it should be something like that.
#823650
Thanks for your replay and your effort to solve the problem, I already utilized web service to create, update user but I thought it would be created to use this function rather create new code and new dependencies: workaround to achieve the same work.
#824036
I solved this problem with help from colleagues
You try to apply this way:

/**
* @url POST /save/client
*/
public function saveUser(){
//Get values of the posted input
$first_name = $_POST['first_name'];
$last_name = $_POST['last_name'];
$password = $_POST['password'];
$rPassword = $_POST['rpassword'];
$email = $_POST['email'];
$court_address = $_POST['court_address'];
$lawyer_level = $_POST['lawyer_level'];
$lawyer_number = $_POST['lawyer_number'];
isset($_POST['pmUid']) ? $pmUid = $_POST['pmUid'] : $pmUid = "";

global $RBAC;
$RBAC = $RBAC ?: \RBAC::getSingleton();


PMFCreateUser($lawyer_number, $password, $first_name, $last_name, $email, "LAWYER_CLIENT");
}
Suggest box not filtering

Thank you so much for your reply. I had the same t[…]

thanks for info

Dear Amosbatto, I managed to connect rest api via[…]

This is a very nice blog to watch out for and we p[…]