⬆️ ⬇️

Release of the new version of the modLivestreet 0.3.0-rc module

Continuing our topic about the MODX and Livestreet bundle module, I present a new version of the modLivestreet module: livestreet-0.3.0-rc.transport.zip



What's new? Yes, almost everything :-) Module rewritten from scratch.

1. Significantly changed (improved) the logic of processing requests for LiveStreet.

2. Added synchronized user registration in MODX and LiveStreet. Now registering a user through the MODX admin panel, the user is automatically created in LiveStreet, and processing a request for LiveStreet to register a user, registration passes through MODX, which in turn also provides simultaneous user registration in both engines.

This feature can be disabled through the setting.



Under the cut of the work scheme (simplified) MODX in the standard version and with the modLivestreet module and a more detailed description of how synchronous registration of users in MODX and Livestreet takes place (Scheme, how registration has changed in MODX will be posted later), as well as the source code.

')

UPD: build a package on github: github.com/Fi1osof/modx-livestreet



Promised MODX operation schemes in standard assembly and with modLivestreet module






So how does this module work?



1. The main plugin in this module is triggered by two events - onHandleRequest and onPageNotFound.

In the first case, there is a check for requests to Livestreet in principle (and initialization of Livestreet variables), as well as a check for accessing static Livestreet files and its individual modules (such as Captcha).

In the second case, another task is performed: if the MODX found the target page when processing the request, then the onPageNotFound event basically does not work, and LiveStreet will not be processed, unless the livestreet.run snippet is explicitly called in the MODX document, which performs the LiveStreet request. This approach allows us not to tie MODX only on LiveStreet. That is, we can make a completely independent site on MODX, but make a section / forum / (or a separate subdomain of forum.site.ru), define the incoming page there, register a call to the snippet [[! Livestreet.ru]]] (to provide the root site), in the settings specify the livestreet.url_perfix '/ forum /' and all. All requests for the mask /forum/.* will be executed with the LiveStreet call and we get our blog. Here you can add a verification of rights or call only a specific branch of the blog, etc.

In the case, if the document is not found and the onPageNotFound event is raised, and the URL corresponds to the Livestreet section, then the Livestreet request is already executed. There is a small disclaimer: if this is a request for registering a Livestreet user, then a snippet registration user snippet.livestreet.ajax-registration.php is called



Here is the listing of the plugin
<?php switch($modx->context->key){ case 'web': break; default: return; } switch($modx->event->name){ //          LiveStreet case 'OnHandleRequest': //   - livestreet_path/config/ define('IN_MODX', true); define('LIVESTREET_WEB', $modx->getOption('site_url')); define('LIVESTREET_PATH', $modx->getOption('livestreet.livestreet_path')); define('LIVESTREET_INDEX_FILE', $modx->getOption('livestreet.index_file')); define('LIVESTREET_URL_PREFIXE', $modx->getOption('livestreet.url_prefix')); $request = false; //print "<br />REQUEST_URI:" . $_SERVER['REQUEST_URI']; //      LiveStreet if($_SERVER['REQUEST_URI'] == LIVESTREET_URL_PREFIXE || $_SERVER['REQUEST_URI']."/" == LIVESTREET_URL_PREFIXE){ $request = '/'; } else{ //     LiveStreet,  $preg = str_replace('/', '\/', LIVESTREET_URL_PREFIXE); if(!preg_match("/^{$preg}/", $_SERVER['REQUEST_URI']."/")){ return; } $request = preg_replace("/^{$preg}/", '', $_SERVER['REQUEST_URI']); } if( substr( $request, 0, 1) != '/') $request = '/'. $request; //    LS define('LIVESTREET_REQUEST_URI', $request); //   ,    ,    if(!$modx->checkSiteStatus()){ return; } $file = LIVESTREET_INDEX_FILE; /*$t = $modx->invokeEvent('onLivestreetUserSave', array('sdfsdf')); print_r($this->processEventResponse($t)); exit;*/ //      LiveStreet $preg = str_replace('/', '\/', "(/templates/|/uploads/|/engine/lib/external/jquery)"); if(preg_match("/^{$preg}/", LIVESTREET_REQUEST_URI)){ $file = LIVESTREET_REQUEST_URI; $file = preg_replace('/\?+.*/', '', $file); $fullpath = str_replace('//','/', LIVESTREET_PATH.$file); if(!file_exists($fullpath)){ die('File Not Found'); } $fsize = filesize($fullpath); $pi = pathinfo( $file); $ext = $pi['extension']; switch ($ext) { case "css": $ctype="text/css; charset=utf-8"; break; case "js": $ctype="application/x-javascript; charset=utf-8"; break; case "pdf": $ctype="application/pdf"; break; case "exe": $ctype="application/octet-stream"; break; case "zip": $ctype="application/zip"; break; case "doc": $ctype="application/msword"; break; case "xls": $ctype="application/vnd.ms-excel"; break; case "ppt": $ctype="application/vnd.ms-powerpoint"; break; case "gif": $ctype="image/gif"; break; case "png": $ctype="image/png"; break; case "jpeg": case "jpg": $ctype="image/jpg"; break; default: $ctype="application/force-download"; } header("Content-type: {$ctype}", true); header("Content-Length: ".$fsize); header("last-modified: ". gmdate("d, dmyh:i:s", filemtime($fullpath) )." GMT"); header("Pragma: public"); header("Expires: 0"); readfile($fullpath); exit; } /* *    -   */ //  $preg = str_replace('/', '\/', "/engine/lib/external/kcaptcha/"); if(preg_match("/^{$preg}/", LIVESTREET_REQUEST_URI)){ $file = 'engine/lib/external/kcaptcha/index.php'; require_once LIVESTREET_PATH.$file; exit; } break; case 'OnPageNotFound': // if not LiveStreet request, stop if(!defined('LIVESTREET_REQUEST_URI')){ return; } $_SERVER['REQUEST_URI'] = LIVESTREET_REQUEST_URI; // Registration if(LIVESTREET_REQUEST_URI == $modx->getOption('livestreet.registration_url', null, '/registration/ajax-registration/')){ // if not in sync mode if($modx->getOption('livestreet.sync_users') == true){ print $modx->runSnippet('livestreet.ajax-registration'); exit; } } print $modx->runSnippet('livestreet.run'); exit; break; default: $modx->event->output( 'true'); ; } 


In principle, as you can see, the plugin is not at all great for such functionality. So anyone will understand if he wants to modify it to fit his needs.



2. To execute requests for LiveStreet snippet snippet.livestreet.run is used.



Listing
 <?php if($request_uri){ $_SERVER['REQUEST_URI'] = $request_uri; } ob_start(); @include $modx->getOption('livestreet.livestreet_path').$modx->getOption('livestreet.index_file'); $output = ob_get_contents(); ob_end_clean(); return $output; 


He is quite small. We bluntly call LiveStreet, buffer it and return the result. Thus, it is possible to process both the content before output and the results of Ajax requests to process the execution check (this is especially important when registering users, since in the case of synchronous registration of users in MODX and LiveSteet, it is necessary to interrupt registration in case of checking the registration of the user as in MODX, so in Livestreet).



There is again a reservation. In Livestreet, the content rendering class is not quite competent. In the Ajax output mode, LS makes a stupid exit (); that breaks the work of the entire module. Therefore, in LS it is necessary to make a small manipulation:

In the components / livestreet / docs / forLiveStreet / source / engine / modules / viewer / Viewer.class.php file

in the DisplayAjax method ($ sType = 'json'), replace exit (); on return;

and in the Display method ($ sTemplate) replace
 if ($this->sResponseAjax) { $this->DisplayAjax($this->sResponseAjax); } 
on
 if ($this->sResponseAjax) { $this->DisplayAjax($this->sResponseAjax); return; } 


In principle, this will not change the independent work of Livesreet, but will give us the opportunity to process the results of Ajax requests and continue our logic.



3. Snippet livestreet.ajax-registration.

This snippet handles a Livestreet user registration request.



Listing
 <?php // if not in sync mode if($modx->getOption('livestreet.sync_users') != true){ return; } $path = $modx->getObject('modNamespace', array( 'name' => 'livestreet' )) -> getCorePath()."processors/"; // print $path; // exit; $response = $modx->runProcessor('security/user/ajaxCreate', array( 'username' => $_POST['login'], 'email' => $_POST['mail'], 'passwordnotifymethod' => 'false', 'passwordgenmethod' => 'false', 'specifiedpassword' => $_POST['password'], 'confirmpassword' => $_POST['password_confirm'], ), array( 'processors_path' => $path )); $bStateError = false; $sMsgTitle = null; $sMsg = null; $errors = array(); if($response->isError()){ // print '<pre>'; //print_r($modx->error->errors); $errorsArray = (array)$modx->error->errors; // processEventResponse // $error = $response->getMessage(); if($errMessageArr = (array)explode("\n", $response->getMessage())){ foreach($errMessageArr as $message){ if(!$message = trim($message))continue; if(!$errArr = explode('::', $message) OR count($errArr) != 2){ $sMsg = $message; } else{ $errorsArray[] = array( 'id' => $errArr[0], 'msg' => $errArr[1], ); } } } foreach($errorsArray as $err){ // LiveStreet Errors if($name = $err['id']){ switch($name){ case 'username': $name = 'login'; break; case 'specifiedpassword': $name = 'password'; break; case 'confirmpassword': $name = 'password_confirm'; break; default: continue; } $errors[$name][0] = $err['msg']; } // MODX errors else{ $sMsg = current($err); } } if(!$errors && !$sMsg){ $sMsg = '  '; } if($sMsg){ $sMsgTitle = 'Error'; $bStateError = true; } $response = array( 'sMsgTitle' => $sMsgTitle, 'sMsg' => $sMsg, 'bStateError' => $bStateError, 'aErrors' => $errors ); } else{ // Success $response = array( 'sMsgTitle' => null, 'sMsg' => '!   !', 'bStateError' => false, 'sUrlRedirect' => $_POST['return-path'], ); } return json_encode($response); 


If synchronous registration is disabled in the settings, then the snippet is not executed, and if this is a direct request to register a user in Livestreet, then the request is sent to Livestreet and that's it.

If synchronous registration is enabled, the request is sent not to Livestreet, but to register the user in MODX (the core / components / livestreet / processors / security / user / ajaxCreate.class.php processor is called, where the extended modUserCreateProcessor class is called). The essence of calling this processor is simple - call the base processor to create a MODX user through the system processor modx / processors / security / user / create.class.php

The reason for this call is that we cannot directly call this processor, because it checks for the right to create new users, and an unauthorized user does not have this right. Therefore, in this class, we simply overwrite the verification of this right (For a hint on this technique, special thanks bezumkin ).



Listing
 <?php $file = MODX_PROCESSORS_PATH.'security/user/create.class.php'; if(!file_exists($file)){ class modLivestreetUserCreateErrorProcessor extends modProcessor { public function process() { $err = 'processor security/user/create not found'; $this->modx->log(modX::LOG_LEVEL_ERROR, $err); return $this->failure($err); } } return 'modLivestreetUserCreateErrorProcessor'; } require_once $file; class modLivestreetUserCreateProcessor extends modUserCreateProcessor { public $permission = ''; } return 'modLivestreetUserCreateProcessor'; 




Well, when a user is registered in MODX, we post our plug-in livestreet_users for the OnBeforeUserFormSave event.



Listing
 <?php /* * Synchronized registration MODX and Livestreet users */ switch($modx->event->name){ case 'OnBeforeUserFormSave': switch($scriptProperties['mode']){ // Register new user case 'new': // if not in sync mode if($modx->getOption('livestreet.sync_users') != true){ return; } // Using for LiveStreet ModuleSecurity::GenerateSessionKey // check password method if($scriptProperties['data']['passwordgenmethod'] == 'g'){ $len = $modx->getOption('password_generated_length',null,8); $password = $password_confirm = modUserValidation::generatePassword($len); /* * note then newPassword in createProcessor will not be overwrited !!! * in backend will see wron new passrowd */ $scriptProperties['user']->set('password', $password); } else{ $password = $scriptProperties['data']['specifiedpassword']; $password_confirm = $scriptProperties['data']['confirmpassword']; } $_REQUEST['password'] = $password; $_REQUEST['password_confirm'] = $password_confirm; $_REQUEST['login'] = $scriptProperties['data']['username']; $_REQUEST['mail'] = $scriptProperties['data']['email']; $_REQUEST['login'] = $scriptProperties['data']['username']; if($modx->context->key == 'mgr'){ $captcha = time(); $_SESSION['captcha_keystring'] = $captcha; $_REQUEST['captcha'] = $captcha; $_SESSION['user_id'] = ''; $_REQUEST['security_ls_key'] = md5( session_id(). $modx->getOption('livestreet.module.security.hash', null, 'livestreet_security_key')); } $response = $modx->runSnippet('livestreet.run', array( 'request_uri' => $modx->getOption('livestreet.registration_url') )); $response = json_decode($response); if(!is_object($response)){ $modx->event->output('  '); } elseif($response->aErrors){ $errors = ''; $errors__ = array(); foreach((array)$response->aErrors as $f => $val){ $errors .= "$f:: ". $val[0]."\n"; } $modx->event->_output = $errors; } return; break; default:; } break; default:$modx->log(modX::LOG_LEVEL_ERROR, "Wrong Event: ". $modx->event->name); } 


At the time of registration of a MODX user, after all checks (if everything is OK), a plugin is executed and an attempt is made to register a user in LiveStreet. If the attempt fails, we return LiveStreet errors and interrupt the registration of a MODX user. If everything is ok, then we finally register the user in MODX.

Thus, we achieve that users can be registered through the MODX admin area, and through FrontEnd, and there and there we will see all possible errors, and we will get user registration in MODX, and in LiveStreet. And in the future, these users, if necessary, can be linked by email (as in LS, email is a unique key).



That's all :-)

That's what I love MODX for::) We have seriously changed the work of the engine, without affecting the byte of the code of the engine itself.

But under MODX there is no social module.

But Livestreet is an excellent social application, but it does not provide such an API as MODX. They even have no admin as such.

But together these engines can give a great product! I will continue to develop this module.



UPD 2: New release released: modlivestreet-0.4.1-rc.transport.zip

New:

1. All elements and settings now have the modLivestreet prefix, because unfortunately the new module is not backward compatible with the previous version. But surely this will not be a problem for anyone. It is enough to remove the old module and put a new one and on the main page change to

2. Added check for the extension of downloaded files from the / templates /, / uploads / directories, etc., in order not to download .php, etc.

Of course, there shouldn't be such files there, but at least in / skin / config / there is such a file.



UPD 3: Security Note: modxlivestreet.ru/blog/modLivestreet_security/7.html

Source: https://habr.com/ru/post/155063/



All Articles