The release of the new version of the module modLivestreet 0.3.0-rc

    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 :-) The module has been rewritten from scratch.
    1. The LiveStreet request processing logic has been seriously changed (improved).
    2. Added synchronized user registration in MODX and LiveStreet. Now registering the user through the MODX admin panel, the user is automatically created in LiveStreet, and when processing the request for LiveStreet to register the user, registration passes through MODX, which in turn also provides simultaneous user registration in both engines.
    This function can be disabled through the setting.

    Under the cut-off, MODX work schemes (simplified) in the standard version and with the modLivestreet module and a more detailed description of how users are simultaneously registered in MODX and Livestreet (I will post the scheme of how the registration in MODX changed later), as well as source codes.

    UPD: building the package on github: github.com/Fi1osof/modx-livestreet

    Promised MODX workflows in standard assembly and with modLivestreet module



    So how does this module work?

    1. The most important 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 access to static Livestreet files and its individual modules (such as Captcha).
    In the second case, another task is performed: if, while processing the request, MODX found the landing page, then the onPageNotFound event will not work in principle, and the LiveStreet will not be processed if the livestreet.run snippet is explicitly called in the MODX document and executes the request for the LiveStreet. This approach allows us not to tie MODX only on LiveStreet. That is, we can make a completely independent site on MODX, but create a / forum / section (or a separate forum.site.ru subdomain), define an incoming page there, write a snippet call [[! Livestreet.ru]] in it (to provide the root site), in the settings specify livestreet.url_perfix '/ forum /' and that's it. All requests for the /forum/.* mask will be executed with a call to LiveStreet and we will get our blog. Here you can add verification of rights or calling only a specific blog thread, etc.
    If the document is not found and the onPageNotFound event is raised, and the URL matches the Livestreet section, then a request for Livestreet is already executed. There is a small caveat: if this is a request to register a Livestreet user, then the registration snippet is called snippet.livestreet.ajax-registration.php

    Here is the plugin listing
    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 "
    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, d m y h: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 big for such functionality. So anyone will figure it out if he wants to modify it to fit his needs.

    2. Snippet.livestreet.run snippet is used to execute requests for LiveStreet

    Listing
    getOption('livestreet.livestreet_path').$modx->getOption('livestreet.index_file'); 
        $output = ob_get_contents();
    ob_end_clean();
    return $output;

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

    There is a reservation again. In Livestreet, the content output class does not work correctly. In the output mode of Ajax results, LS does stupidly exit () ;, which breaks the operation of the entire module. Therefore, in LS, you need to do a little manipulation:
    In the file components / livestreet / docs / forLiveStreet / source / engine / modules / viewer / Viewer.class.php
    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 the
    if ($this->sResponseAjax) {
    	$this->DisplayAjax($this->sResponseAjax);
            return;
    }

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

    3. Snippet livestreet.ajax-registration.
    This snippet processes the registration request for a Livestreet user.

    Listing
    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 '
    ';
    	//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 it is a direct request for user registration in Livestreet, then the request is sent to Livestreet and that’s all.
    If synchronous registration is enabled, the request is sent not to Livestreet, but to register the user in MODX (the processor core / components / livestreet / processors / security / user / ajaxCreate.class.php is called, where the extended class modUserCreateProcessor is called). The essence of calling this processor is simple - to call the base processor to create the 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, since it checks for the right to create new users, and this is not an unauthorized user’s right. Therefore, in this class, we simply overwrite the verification of this right (For a tip on this technique, special thanks to bezumkin ).

    Listing
    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 the user is registered in MODX, we hang our livestreet_users plugin on the OnBeforeUserFormSave event.

    Listing
    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 moment of registration of the MODX user, after all checks (if everything is OK), the plug-in is executed and an attempt is made to register the user in LiveStreet. If the attempt breaks off, we return LiveStreet errors and terminate the registration of the MODX user. If everything is ok, then finally register the user in MODX.
    Thus, we ensure that users can be registered both through the MODX admin panel, and through FrontEnd, and there and there, we will see all possible errors and get user registration in both MODX and LiveStreet. And in the future, if necessary, we can link these users by email (since in LS the email is a unique key).

    That's all :-)
    That's why I love MODX :-) We seriously changed the operation 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 a great social network, but it does not provide such an API as MODX. They do not even have an admin as such.
    But together, these engines can give a great product! I will continue to develop this module.

    UPD 2: A new release came out: modlivestreet-0.4.1-rc.transport.zip
    New:
    1. All elements and settings now have the modLivestreet prefix, so unfortunately the new module does not have backward compatibility with the previous version. But for sure this will not be a problem for anyone. It is enough to remove the old module and install the new one and change it to
    2. on the main page . Added a check for the extension of downloaded files from the directories / templates /, / uploads /, etc., so that they do not download .php, etc.
    Of course, such files should not be there, but at least there is such a file in / skin / config /.

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

    Also popular now: