浏览代码

Ticket #5019 - Contexts: Improve invite/join.

AntonLV 1 年之前
父节点
当前提交
3a58926be9

+ 26 - 6
modules/boonex/invites/classes/BxInvConfig.php

@@ -12,11 +12,11 @@
 class BxInvConfig extends BxBaseModGeneralConfig
 {
     protected $_oDb;
+    protected $_oSession;
 
     protected $_iCountPerUser;
     protected $_sKeyCode;
     protected $_iKeyLifetime;
-    protected $_sRedirectCode;
     protected $_bRequestInvite;
     protected $_sRequestsEmail;
     protected $_bRegistrationByInvitation;
@@ -28,6 +28,8 @@ class BxInvConfig extends BxBaseModGeneralConfig
     {
         parent::__construct($aModule);
 
+        $this->_oSession = BxDolSession::getInstance();
+
         $this->CNF = array (
             'URL_INVITE' => 'page.php?i=invites-invite',
             'URL_REQUEST' => 'page.php?i=invites-request',
@@ -59,7 +61,6 @@ class BxInvConfig extends BxBaseModGeneralConfig
         $this->_iCountPerUser = 0;
         $this->_sKeyCode = 'icode';
         $this->_iKeyLifetime = 86400;
-        $this->_sRedirectCode = 'iredirect';
         $this->_bRequestInvite = true;
         $this->_sRequestsEmail = '';
         $this->_bRegistrationByInvitation = true;
@@ -72,10 +73,14 @@ class BxInvConfig extends BxBaseModGeneralConfig
         );
 
         $sHtmlPrefix = str_replace('_', '-', $this->_sName);
-        $this->_aHtmlIds = array(
+        $this->_aHtmlIds = [
             'link_popup' => $sHtmlPrefix . '-link-popup',
             'link_input' => $sHtmlPrefix . '-link-input',
-        );
+
+            'code_popup' => $sHtmlPrefix . '-code-popup',
+            'code_input' => $sHtmlPrefix . '-code-input',
+            'code_link_input' => $sHtmlPrefix . '-code-link-input'            
+        ];
     }
 
     public function init(&$oDb)
@@ -106,9 +111,24 @@ class BxInvConfig extends BxBaseModGeneralConfig
         return $this->_iKeyLifetime;
     }
 
-    public function getRedirectCode()
+    public function setKey($sKey)
+    {
+        return $this->_oSession->setValue($this->_sKeyCode, $sKey);
+    }
+
+    public function getKey()
+    {
+        return $this->_oSession->getValue($this->_sKeyCode);
+    }
+
+    public function getUnsetKey()
+    {
+        return $this->_oSession->getUnsetValue($this->_sKeyCode);
+    }
+
+    public function unsetKey()
     {
-        return $this->_sRedirectCode;
+        return $this->_oSession->unsetValue($this->_sKeyCode);
     }
 
     public function isRequestInvite()

+ 17 - 7
modules/boonex/invites/classes/BxInvDb.php

@@ -107,6 +107,16 @@ class BxInvDb extends BxDolModuleDb
                 $sWhereClause = "AND `{$this->_sTableInvites}`.`key`=:key ";
                 $sLimitClause = "LIMIT 1";
                 break;
+            
+            case 'by_joined_account_id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1] = [
+                    'account_id' => $aParams['account_id']
+                ];
+
+                $sWhereClause = "AND `{$this->_sTableInvites}`.`joined_account_id`=:account_id ";
+                $sLimitClause = "LIMIT 1";
+                break;
 
             case 'all':
                 $aMethod['name'] = 'getAll';
@@ -155,22 +165,22 @@ class BxInvDb extends BxDolModuleDb
      
     public function attachAccountIdToInvite($iAccountId, $sKey)
     {
-        $aBindings = array(
+        $this->query("UPDATE `{$this->_sTableInvites}` SET `joined_account_id`=:joined_account_id, `date_joined`=:date_joined WHERE `key`=:keyvalue", [
             'joined_account_id' => $iAccountId,
             'keyvalue' => $sKey,
             'date_joined' => time(),
-        );
-        $this->query("UPDATE `{$this->_sTableInvites}` SET `joined_account_id`=:joined_account_id, `date_joined`=:date_joined WHERE `key`=:keyvalue", $aBindings);
+        ]);
+
         $this->updateRequestStatusByInviteCode(3, $sKey);
     }
-    
+
     public function updateDateSeenForInvite($sKey)
     {
-        $aBindings = array(
+        $this->query("UPDATE `{$this->_sTableInvites}` SET `date_seen`=:date_seen WHERE `key`=:keyvalue", [
             'date_seen' => time(),
             'keyvalue' => $sKey
-        );
-        $this->query("UPDATE `{$this->_sTableInvites}` SET `date_seen`=:date_seen WHERE `key`=:keyvalue", $aBindings);
+        ]);
+
         $this->updateRequestStatusByInviteCode(2, $sKey);
     }
 

+ 55 - 19
modules/boonex/invites/classes/BxInvGridInvites.php

@@ -27,7 +27,9 @@ class BxInvGridInvites extends BxTemplGrid
 
         $this->_sModule = 'bx_invites';
         $this->_oModule = BxDolModule::getInstance($this->_sModule);
-       
+
+        $this->_sDefaultSortingOrder = 'DESC';
+
         $this->_sFilter1Name = 'filter1';
         $this->_aFilter1Values = array(
             '' => _t('_bx_invites_invites_status_for_filter_all'),
@@ -165,37 +167,63 @@ class BxInvGridInvites extends BxTemplGrid
         $oForm = new BxTemplFormView(array());
         return $oForm->genRow($aInputModules);
     }
-    
-    protected function _getCellDate($mixedValue, $sKey, $aField, $aRow)
+
+    protected function _getCellEmail($mixedValue, $sKey, $aField, $aRow)
     {
-        if($this->_bIsApi)
-            return ['type' => 'time', 'data' => $mixedValue];
+        if((int)$aRow['email_use'] != 0) {
+            $sTitle = bx_html_attribute(_t('_bx_invites_txt_email_use'));
+
+            $mixedValue .= $this->_oModule->_oTemplate->parseIconInline('ui-alert.svg', ['alt' => $sTitle, 'title' => $sTitle]);
+        }
 
-        return parent::_getCellDefault(bx_time_js($mixedValue), $sKey, $aField, $aRow);
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
     }
-    
-    protected function _getCellDateSeen($mixedValue, $sKey, $aField, $aRow)
+
+    protected function _getCellMulti($mixedValue, $sKey, $aField, $aRow)
     {
-        if($this->_bIsApi)
-            return ['type' => 'time', 'data' => (int)$mixedValue];
+        return parent::_getCellDefault(_t((int)$mixedValue != 0 ? '_Yes' : '_No'), $sKey, $aField, $aRow);
+    }
 
-        if($mixedValue == 'undefined')
-            return parent::_getCellDefault('', $sKey, $aField, $aRow);
+    protected function _getCellAj($mixedValue, $sKey, $aField, $aRow)
+    {
+        switch($aRow['aj_action']) {
+            case 'redirect':
+                $mixedValue = $this->_getAjLink($aRow['aj_action'], BxDolPermalinks::getInstance()->permalink($aRow['aj_params']));
+                break;
+
+            case 'invite_to_context':
+                $mixedValue = '#';
+                if(($oContext = BxDolProfile::getInstanceMagic((int)$aRow['aj_params'])) !== false)
+                    $mixedValue = $oContext->getUrl();
 
-        return parent::_getCellDefault(bx_time_js($mixedValue), $sKey, $aField, $aRow);
+                $mixedValue = $this->_getAjLink($aRow['aj_action'], $mixedValue);
+                break;
+
+            default:
+                $mixedValue = '';
+        }
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
     }
     
-    protected function _getCellDateJoined($mixedValue, $sKey, $aField, $aRow)
+    protected function _getCellDate($mixedValue, $sKey, $aField, $aRow)
     {
         if($this->_bIsApi)
             return ['type' => 'time', 'data' => (int)$mixedValue];
 
-        if($mixedValue == 'undefined')
-            return parent::_getCellDefault('', $sKey, $aField, $aRow);
+        return parent::_getCellDefault($mixedValue && $mixedValue != 'undefined' ? bx_time_js($mixedValue) : '', $sKey, $aField, $aRow);
+    }
 
-        return parent::_getCellDefault(bx_time_js($mixedValue), $sKey, $aField, $aRow);
+    protected function _getCellDateSeen($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellDate($mixedValue, $sKey, $aField, $aRow);
     }
-    
+
+    protected function _getCellDateJoined($mixedValue, $sKey, $aField, $aRow)
+    {
+        return $this->_getCellDate($mixedValue, $sKey, $aField, $aRow);
+    }
+
     protected function _getCellWhoSend($mixedValue, $sKey, $aField, $aRow)
     {
         if(($oProfile = BxDolProfile::getInstanceMagic($aRow['profile_id'])) !== false) {
@@ -274,7 +302,7 @@ class BxInvGridInvites extends BxTemplGrid
 
         return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
     }
-    
+
     protected function _getManageAccountUrl($sFilter = '')
     {
     	$sModuleAccounts = 'bx_accounts';
@@ -295,6 +323,14 @@ class BxInvGridInvites extends BxTemplGrid
         return $sLink;
     }
 
+    protected function _getAjLink($sAction, $sLink)
+    {
+        return $this->_oModule->_oTemplate->parseHtmlByName('invite_aj_link.html', [
+            'href' => $sLink,
+            'content' => _t('_bx_invites_invites_aj_' . $sAction)
+        ]);
+    }
+
     protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
     {
         $CNF = $this->_oModule->_oConfig->CNF;

+ 1 - 1
modules/boonex/invites/classes/BxInvGridRequests.php

@@ -159,7 +159,7 @@ class BxInvGridRequests extends BxTemplGrid
             if(empty($aRequest) || !is_array($aRequest))
                 continue;
             
-            $mixedResult = $this->_oModule->invite(BX_INV_TYPE_FROM_SYSTEM, [$aRequest['email']], $sText, false);
+            $mixedResult = $this->_oModule->invite(BX_INV_TYPE_FROM_SYSTEM, [$aRequest['email']], $sText);
             if(empty($mixedResult) || !is_array($mixedResult))
                 continue;
 

+ 202 - 78
modules/boonex/invites/classes/BxInvModule.php

@@ -16,22 +16,67 @@ define('BX_INV_TYPE_FROM_SYSTEM', 'from_system');
 
 class BxInvModule extends BxDolModule
 {
+    protected $_bIsApi;
+
     /**
      * Constructor
      */
-    function __construct($aModule)
+    public function __construct($aModule)
     {
         parent::__construct($aModule);
 
+        $this->_bIsApi = bx_is_api();
+
         $this->_oConfig->init($this->_oDb);
     }
 
     /**
      * ACTION METHODS
      */
-    function serviceGetLink()
+    public function serviceGetCode($aParams)
+    {
+        $iProfileId = $this->getProfileId();
+        $iAccountId = $this->getAccountId($iProfileId);
+
+        $mixedAllowed = $this->isAllowedInvite($iProfileId);
+        if($mixedAllowed !== true)
+            return echoJson(['message' => $mixedAllowed]);
+
+        $bContextAdmin = false;
+        if(isset($aParams['aj_action'], $aParams['aj_params']) && $aParams['aj_action'] == 'invite_to_context' && ($iContextPid = (int)$aParams['aj_params']) != 0)
+            $bContextAdmin = ($oContext = BxDolProfile::getInstance($iContextPid)) !== false && bx_srv($oContext->getModule(), 'is_admin', [$iContextPid, $iProfileId]);
+
+        if(!isAdmin($iAccountId) && !$bContextAdmin && $this->_oConfig->getCountPerUser() <= 0)
+            return $this->_bIsApi ? [bx_api_get_msg(_t('_bx_invites_err_limit_reached'))] : echoJson(['message' => _t('_bx_invites_err_limit_reached')]);
+
+        $oKeys = BxDolKey::getInstance();
+        if(!$oKeys)
+            return $this->_bIsApi ? [bx_api_get_msg(_t('_bx_invites_err_not_available'))] : echoJson(['message' => _t('_bx_invites_err_not_available')]);
+
+        $sKey = $oKeys->getNewKey(false, $this->_oConfig->getKeyLifetime());
+
+        $this->getFormObjectInvite()->insert(array_merge([
+            'account_id' => $iAccountId,
+            'profile_id' => $iProfileId,
+            'key' => $sKey,
+            'multi' => 1,
+            'date' => time()
+        ], $aParams));
+        $this->onInvite($iProfileId);
+
+        $sLink = $this->getJoinLink($sKey);
+
+        if($this->_bIsApi)
+            return [
+                'code' => $sKey,
+                'link' => bx_api_get_relative_url($sLink)
+            ];
+
+        echoJson(['popup' => $this->_oTemplate->getCodePopup($sKey, $sLink)]);
+    }
+
+    function serviceGetLink($aParams)
     {
-        
         $iProfileId = $this->getProfileId();
         $iAccountId = $this->getAccountId($iProfileId);
 
@@ -41,43 +86,43 @@ class BxInvModule extends BxDolModule
 
         if(!isAdmin($iAccountId)) {
             if($this->_oConfig->getCountPerUser() <= 0)
-                return bx_is_api() ? [bx_api_get_msg(_t('_bx_invites_err_limit_reached'))] : echoJson(array('message' => _t('_bx_invites_err_limit_reached')));
+                return $this->_bIsApi ? [bx_api_get_msg(_t('_bx_invites_err_limit_reached'))] : echoJson(array('message' => _t('_bx_invites_err_limit_reached')));
         }
 
         $oKeys = BxDolKey::getInstance();
         if(!$oKeys)
-            return bx_is_api() ? [bx_api_get_msg(_t('_bx_invites_err_not_available'))] : echoJson(array('message' => _t('_bx_invites_err_not_available')));
-
-        $sKey = $oKeys->getNewKey(false, $this->_oConfig->getKeyLifetime());       
+            return $this->_bIsApi ? [bx_api_get_msg(_t('_bx_invites_err_not_available'))] : echoJson(array('message' => _t('_bx_invites_err_not_available')));
 
-        $sRedirectUrl = '';
-        $sRedirectCode = $this->_oConfig->getRedirectCode();
-        if(($oSession = BxDolSession::getInstance()) && $oSession->isValue($sRedirectCode))
-            $sRedirectUrl = $oSession->getValue($sRedirectCode);
+        $sKey = $oKeys->getNewKey(false, $this->_oConfig->getKeyLifetime());
 
-        $oForm = $this->getFormObjectInvite();
-        $oForm->insert(array(
+        $this->getFormObjectInvite()->insert(array_merge([
             'account_id' => $iAccountId,
             'profile_id' => $iProfileId,
             'key' => $sKey,
-            'redirect' => $sRedirectUrl,
-            'email' => '',
             'date' => time()
-        ));
+        ], $aParams));
         $this->onInvite($iProfileId);
 
-        if (bx_is_api()){
-            return ['link' => bx_api_get_relative_url($this->getJoinLink($sKey))];
-        }
-        
-        echoJson(array('popup' => $this->_oTemplate->getLinkPopup(
-            $this->getJoinLink($sKey)
-        )));
+        $sLink = $this->getJoinLink($sKey);
+
+        if($this->_bIsApi)
+            return ['link' => bx_api_get_relative_url($sLink)];
+
+        echoJson(['popup' => $this->_oTemplate->getLinkPopup($sLink)]);
     }
-    
-    function actionGetLink()
+
+    public function actionGetCode()
+    {
+        $aParams = $this->_prepareParamsGet();
+
+        $this->serviceGetCode($aParams);
+    }
+
+    public function actionGetLink()
     {
-        $this->serviceGetLink();
+        $aParams = $this->_prepareParamsGet();
+
+        $this->serviceGetLink($aParams);
     }
     
     public function actionSetSeenMark($Code)
@@ -95,6 +140,7 @@ class BxInvModule extends BxDolModule
     {
         return array (
             'GetBlockInvite' => '',
+            'GetBlockInviteToContext' => '',
             'GetBlockFormInvite' => '',
             'GetBlockFormRequest' => '',
             'GetLink' => '',
@@ -131,7 +177,7 @@ class BxInvModule extends BxDolModule
      * 
      * @code bx_srv('bx_invites', 'get_block_invite', [...]); @endcode
      * 
-     * Get page block for member's Dashboard which displays invitations related info and action(s).
+     * Get page block which displays invitations related info and action(s).
      *
      * @return an array describing a block to display on the site or empty string if something is wrong. All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
      * 
@@ -143,17 +189,61 @@ class BxInvModule extends BxDolModule
     public function serviceGetBlockInvite($bRedirect = false)
     {
         $iProfileId = $this->getProfileId();
+        if(($mixedAllowed = $this->isAllowedInvite($iProfileId)) !== true)
+            return '';
+
         $iAccountId = $this->getAccountId($iProfileId);
+        if(!isAdmin($iAccountId) && $this->_oConfig->getCountPerUser() <= 0)
+            return '';
 
-        $mixedAllowed = $this->isAllowedInvite($iProfileId);
-        if($mixedAllowed !== true)
+        return [
+            'content' => $this->_oTemplate->getBlockInvite($iAccountId, $iProfileId, [
+                'redirect' => (bool)$bRedirect
+            ])
+        ];
+    }
+
+    /**
+     * @page service Service Calls
+     * @section bx_invites Invitations
+     * @subsection bx_invites-page_blocks Page Blocks
+     * @subsubsection bx_invites-get_block_invite get_block_invite_to_context
+     * 
+     * @code bx_srv('bx_invites', 'get_block_invite_to_context', [...]); @endcode
+     * 
+     * Get page block which displays invitations related info and action(s). It's similar to BxInvModule::serviceGetBlockInvite 
+     * but should be used on View Context page (should receive Context Profile ID). It invites to the context after joining the site.
+     *
+     * @return an array describing a block to display on the site or empty string if something is wrong. 
+     * All necessary CSS and JS files are automatically added to the HEAD section of the site HTML.
+     * 
+     * @see BxInvModule::serviceGetBlockInviteToContext
+     */
+    /** 
+     * @ref bx_invites-get_block_invite_to_context "get_block_invite_to_context"
+     */
+    public function serviceGetBlockInviteToContext($iContextPid)
+    {
+        $oContext = false;
+        if(!$iContextPid || !($oContext = BxDolProfile::getInstance($iContextPid)))
             return '';
 
-        if(!isAdmin($iAccountId) && $this->_oConfig->getCountPerUser() <= 0)
+        $sContext = $oContext->getModule();
+        if(!bx_srv('system', 'is_module_context', [$sContext]))
+            return '';
+
+        $iProfileId = $this->getProfileId();
+        if(($mixedAllowed = $this->isAllowedInvite($iProfileId)) !== true)
+            return '';
+
+        $iAccountId = $this->getAccountId($iProfileId);
+        if(!isAdmin($iAccountId) && !bx_srv($sContext, 'is_admin', [$iContextPid, $iProfileId]) && $this->_oConfig->getCountPerUser() <= 0)
             return '';
 
         return [
-            'content' => $this->_oTemplate->getBlockInvite($iAccountId, $iProfileId, (bool)$bRedirect)
+            'content' => $this->_oTemplate->getBlockInvite($iAccountId, $iProfileId, [
+                'context' => (int)$iContextPid
+            ])
         ];
     }
 
@@ -174,25 +264,34 @@ class BxInvModule extends BxDolModule
     /** 
      * @ref bx_invites-get_block_form_invite "get_block_form_invite"
      */
-    public function serviceGetBlockFormInvite()
+    public function serviceGetBlockFormInvite($aParams = [])
     {
+        if(!isset($aParams['aj_action'], $aParams['aj_params']))
+            $aParams = array_merge($aParams, $this->_prepareParamsGet());
+
         $oForm = $this->getFormObjectInvite();
+
         $oForm->aInputs['text']['value'] = _t('_bx_invites_msg_invitation');
 
-       
-        
+        foreach(['aj_action', 'aj_params'] as $sKey)
+            if(!empty($aParams[$sKey]))
+                $oForm->aInputs[$sKey] = [
+                    'name' => $sKey,
+                    'type' => 'hidden',
+                    'value' => $aParams[$sKey]
+                ];
+
         $sResult = '';
         $oForm->initChecker();
         if($oForm->isSubmittedAndValid()){
             $sResult = MsgBox($this->processFormObjectInvite($oForm));
-            if (bx_is_api()){
+            if($this->_bIsApi)
                 return [bx_api_get_msg($sResult)];
-            }
         }
 
-        if (bx_is_api())
+        if($this->_bIsApi)
             return [bx_api_get_block('form', $oForm->getCodeAPI(), ['ext' => ['name' => $this->getName(), 'request' => ['url' => '/api.php?r=' . $this->getName() . '/get_block_form_invite', 'immutable' => true]]])];
-        
+
         return [
             'content' => $sResult . $oForm->getCode()
         ];
@@ -219,7 +318,7 @@ class BxInvModule extends BxDolModule
     {
         $mixedResult = $this->_oTemplate->getBlockFormRequest();
         
-        if (bx_is_api())
+        if ($this->_bIsApi)
             return $mixedResult;
         
         if(is_array($mixedResult)) {
@@ -319,26 +418,25 @@ class BxInvModule extends BxDolModule
     {
         $sReturn = '';
 
-        $oSession = BxDolSession::getInstance();
-        $sKeyCode = $this->_oConfig->getKeyCode();
-
-        $bKey = bx_get($sKeyCode) !== false;
+        $sKey = bx_get($this->_oConfig->getKeyCode());
+        $bKey = $sKey !== false;
         if($bKey) {
-            $sKey = bx_process_input(bx_get($sKeyCode));
+            $sKey = bx_process_input($sKey);
 
             $oKeys = BxDolKey::getInstance();
-            if($oKeys && $oKeys->isKeyExists($sKey))
-                $oSession->setValue($sKeyCode, $sKey);
+            if($oKeys->isKeyExists($sKey))
+                $this->_oConfig->setKey($sKey);
+            else
+                $this->_oConfig->unsetKey();
         }
 
-        $sKey = $oSession->getValue($sKeyCode);
-        if($sKey !== false)
+        if($this->_oConfig->getKey() !== false)
             return $sReturn;
 
         if($bKey)
             $sReturn .= MsgBox(_t('_bx_invites_err_used'));
-        
-        if ($this->_oConfig->isRegistrationByInvitation())
+
+        if($this->_oConfig->isRegistrationByInvitation())
             $sReturn .= $this->_oTemplate->getBlockRequest();
 
         return $sReturn;
@@ -397,8 +495,8 @@ class BxInvModule extends BxDolModule
     {
         $this->_oDb->attachAccountIdToInvite($iAccountId, $sKey);
     }
-    
-    public function invite($sType, $aEmails, $sText, $mixedLimit)
+
+    public function invite($sType, $aEmails, $sText, $aParams = [])
     {
         if(empty($aEmails) || !is_array($aEmails))
             return false;
@@ -409,11 +507,6 @@ class BxInvModule extends BxDolModule
 
         $iKeyLifetime = $this->_oConfig->getKeyLifetime();
 
-        $sRedirectUrl = '';
-        $sRedirectCode = $this->_oConfig->getRedirectCode();
-        if(($oSession = BxDolSession::getInstance()) && $oSession->isValue($sRedirectCode))
-            $sRedirectUrl = $oSession->getValue($sRedirectCode);
-
         $sEmailTemplate = '';
         switch($sType) {
             case BX_INV_TYPE_FROM_MEMBER:
@@ -432,11 +525,11 @@ class BxInvModule extends BxDolModule
             'text' => $sText
         ), $iAccountId, $iProfileId);
 
+        $iEmailUse = !empty($aParams['email_use']) ? (int)$aParams['email_use'] : 0;
+        $bLimit = !empty($aParams['limit']) && is_numeric($aParams['limit']);
+
         $aResults = [];
         foreach($aEmails as $sEmail) {
-            if($mixedLimit !== false && (int)$mixedLimit <= 0)
-                break;
-
             $sEmail = trim($sEmail);
             if(empty($sEmail))
                 continue;
@@ -452,16 +545,18 @@ class BxInvModule extends BxDolModule
                     'account_id' => $iAccountId, 
                     'profile_id' => $iProfileId, 
                     'key' => $sKey, 
-                    'redirect' => $sRedirectUrl,
                     'email' => $sEmail, 
+                    'email_use' => $iEmailUse,
+                    'aj_action' => !empty($aParams['aj_action']) ? $aParams['aj_action'] : '',
+                    'aj_params' => !empty($aParams['aj_params']) ? $aParams['aj_params'] : '',
                     'date' => $iDate
                 ]);
 
                 $this->onInvite($iProfileId);
 
                 $aResults[$iInviteId] = $sEmail;
-                if($mixedLimit !== false)
-                    $mixedLimit -= 1;
+                if($bLimit && count($aResults) == (int)$aParams['limit'])
+                    break;
             }
         }
 
@@ -477,19 +572,25 @@ class BxInvModule extends BxDolModule
         if($mixedAllowed !== true)
             return $mixedAllowed;
 
-        $mixedInvites = false;
-        if(!isAdmin($iAccountId)) {
-            if(($mixedInvites = $this->_oConfig->getCountPerUser()) <= 0)
-                return _t('_bx_invites_err_limit_reached');
-        }
+        $aInviteParams = [];
+        if(!isAdmin($iAccountId) && ($aInviteParams['limit'] = $this->_oConfig->getCountPerUser()) <= 0)
+            return _t('_bx_invites_err_limit_reached');
 
         $sEmails = bx_process_input($oForm->getCleanValue('emails'));
         $aEmails = preg_split("/[\s\n,;]+/", $sEmails);
 
+        $aInviteParams['email_use'] = (int)$oForm->getCleanValue('email_use');
+
+        if(($sA = 'aj_action') && ($$sA = $oForm->getCleanValue($sA)) && ($sP = 'aj_params') && ($$sP = $oForm->getCleanValue($sP))) 
+            $aInviteParams = array_merge($aInviteParams, [
+                $sA => $$sA,
+                $sP => $$sP
+            ]);
+
         $sText = bx_process_pass($oForm->getCleanValue('text'));
 
         $sResult = _t('_bx_invites_err_not_available');
-        if(($aEmailsSent = $this->invite(BX_INV_TYPE_FROM_MEMBER, $aEmails, $sText, $mixedInvites)) !== false) {
+        if(($aEmailsSent = $this->invite(BX_INV_TYPE_FROM_MEMBER, $aEmails, $sText, $aInviteParams)) !== false) {
             $sEmailsResult = '';
             if(count($aEmails) != count($aEmailsSent))
                 $sEmailsResult = implode('; ', array_diff($aEmails, $aEmailsSent));
@@ -589,24 +690,23 @@ class BxInvModule extends BxDolModule
     
     protected function getBlockManage($sType)
     {
-        $this->_oTemplate->addJs('jquery.form.min.js');
-        $this->_oTemplate->addJs('main.js');
         $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_' . $sType));
         if(!$oGrid)
             return '';
         
-        if (bx_is_api())
+        if($this->_bIsApi)
             return [
                 bx_api_get_block('grid', $oGrid->getCodeAPI())
             ];
 
-        $this->_oTemplate->addCss(array('main.css'));
-        $this->_oTemplate->addJsTranslation(array('_sys_grid_search'));
-       
-        return array(
+        $this->_oTemplate->addCss(['main.css']);
+        $this->_oTemplate->addJs(['jquery.form.min.js', 'main.js']);
+        $this->_oTemplate->addJsTranslation(['_sys_grid_search']);
+
+        return [
            'menu' => $this->_oTemplate->getMenuForManageBlocks($sType),
-           'content' => $this->_oTemplate->getJsCode('main', array('grid' => $sType)) . $oGrid->getCode()
-       );
+           'content' => $this->_oTemplate->getJsCode('main', ['grid' => $sType]) . $oGrid->getCode()
+        ];
     }
 
     public function onInvite($iProfileId)
@@ -638,6 +738,30 @@ class BxInvModule extends BxDolModule
         return  BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'SetSeenMark/' . $sKey . "/";
     }
 
+    protected function _prepareParamsGet()
+    {
+        $sAjAction = bx_get('aja');
+        if(!$sAjAction || !($sAjAction = bx_process_input($sAjAction)) || !in_array($sAjAction, ['redirect', 'invite_to_context']))
+            return [];
+
+        $sAjParams = bx_get('ajp');
+        if(!$sAjParams)
+            return [];
+        
+        switch($sAjAction) {
+            case 'redirect':
+                $sAjParams = bx_process_input($sAjParams);
+                break;
+            case 'invite_to_context':
+                $sAjParams = bx_process_input($sAjParams, BX_DATA_INT);
+                break;
+        }
+        
+        return [
+            'aj_action' => $sAjAction, 
+            'aj_params' => $sAjParams
+        ]; 
+    }
 }
 
 /** @} */

+ 104 - 45
modules/boonex/invites/classes/BxInvResponse.php

@@ -36,24 +36,59 @@ class BxInvResponse extends BxDolAlertsResponse
         return $this->$sMethod($oAlert);
     }
 
+    protected function _processAccountAddFormCheck($oAlert)
+    {
+        $sKey = $this->_oModule->_oConfig->getKey();
+        if($sKey === false)
+            return;
+
+        $aInvite = $this->_oModule->_oDb->getInvites(['type' => 'by_key', 'key' => $sKey]);
+        if(!empty($aInvite) && is_array($aInvite) && (int)$aInvite['email_use'] != 0) {
+            $oForm = &$oAlert->aExtras['form_object'];
+            if($oForm->isSubmittedAndValid() && $oForm->aInputs['email']['value'] != $aInvite['email']) {
+                $oForm->aInputs['email']['error'] = _t('_bx_invites_err_wrong_email');
+
+                $oForm->setValid(false);
+            }
+        }
+    }
+
     protected function _processAccountAddForm($oAlert)
     {
         if(!($sCode = $this->_oModule->serviceAccountAddFormCheck())) {
-            $sKeyCode = $this->_oModule->_oConfig->getKeyCode();
-            $sKeyValue = BxDolSession::getInstance()->getValue($sKeyCode);
-
-            $aInvite = $this->_oModule->_oDb->getInvites(['type' => 'by_key', 'key' => $sKeyValue]);
-            if(!empty($aInvite) && is_array($aInvite) && !empty($aInvite['redirect'])) {
-                $oAlert->aExtras['form_object']->aInputs['relocate'] = [
-                    'name' => 'relocate',
-                    'type' => 'hidden',
-                    'value' => BxDolPermalinks::getInstance()->permalink($aInvite['redirect'])
-                ];
-
-                $oAlert->aExtras['form_code'] = $oAlert->aExtras['form_object']->getCode();
+            $aInvite = $this->_oModule->_oDb->getInvites([
+                'type' => 'by_key', 
+                'key' => $this->_oModule->_oConfig->getKey()
+            ]);
+
+            if(!empty($aInvite) && is_array($aInvite)) {
+                $bGetCode = false;
+
+                if(!empty($aInvite['email_use'])) {
+                    $oAlert->aExtras['form_object']->aInputs['email']['value'] = $aInvite['email'];
+
+                    if(!is_array($oAlert->aExtras['form_object']->aInputs['email']['attrs']))
+                        $oAlert->aExtras['form_object']->aInputs['email']['attrs'] = [];
+                    $oAlert->aExtras['form_object']->aInputs['email']['attrs']['readonly'] = 'readonly';
+
+                    $bGetCode = true;
+                }
+
+                if(!empty($aInvite['aj_action']) && $aInvite['aj_action'] == 'redirect' && !empty($aInvite['aj_params'])) {
+                    $oAlert->aExtras['form_object']->aInputs['relocate'] = [
+                        'name' => 'relocate',
+                        'type' => 'hidden',
+                        'value' => BxDolPermalinks::getInstance()->permalink($aInvite['aj_params'])
+                    ];
+
+                    $bGetCode = true;
+                }
+
+                if($bGetCode)
+                    $oAlert->aExtras['form_code'] = $oAlert->aExtras['form_object']->getCode();
             }
         }
-        else{
+        else {
             $oAlert->aExtras['form_code'] = $sCode;
             $oAlert->aExtras['form_object'] = false;
         }
@@ -61,13 +96,18 @@ class BxInvResponse extends BxDolAlertsResponse
 
     protected function _processAccountAdded($oAlert)
     {
-        $sKeyCode = $this->_oModule->_oConfig->getKeyCode();
-        $sKey = BxDolSession::getInstance()->getUnsetValue($sKeyCode);
+        $sKey = $this->_oModule->_oConfig->getUnsetKey();
         if($sKey === false)
             return;
 
         $this->_oModule->attachAccountIdToInvite($oAlert->iObject, $sKey);
 
+        /**
+         * Don't remove key if multi join invitation was used.
+         */
+        if(($aInvite = $this->_oModule->_oDb->getInvites(['type' => 'by_key', 'key' => $sKey])) && is_array($aInvite) && (int)$aInvite['multi'] != 0)
+            return;
+
         $aKeysToRemove = [$sKey];
         if(($sKeysToRemove = $this->_oModule->_oDb->getInvites(['type' => 'invites_code_by_single', 'value' => $sKey])))
             $aKeysToRemove = explode(',', $sKeysToRemove);  
@@ -80,39 +120,58 @@ class BxInvResponse extends BxDolAlertsResponse
 
     protected function _processProfileAdd($oAlert)
     {
-        if (getParam('bx_invites_automatically_befriend') != 'on')
+        $oProfile = BxDolProfile::getInstanceMagic($oAlert->iObject);
+        if(!$oProfile || !$oProfile->isActAsProfile())
             return;
+
+        $aInvite = $this->_oModule->_oDb->getInvites([
+            'type' => 'by_joined_account_id', 
+            'account_id' => $oProfile->getAccountId()
+        ]);
+        $bInvite = !empty($aInvite) && is_array($aInvite);
+
+        //--- Check 'invite_to_context'
+        if($bInvite && !empty($aInvite['aj_action']) && $aInvite['aj_action'] == 'invite_to_context' && ($iContextPid = (int)$aInvite['aj_params']) != 0) {
+            $oContext = BxDolProfile::getInstance($iContextPid);
+            if($oContext && ($sContext = $oContext->getModule()) && bx_srv('system', 'is_module_context', [$sContext]))
+                bx_srv($sContext, 'add_mutual_connection', [$iContextPid, $oAlert->iObject, true]);
+        }
+
+        //--- Check automatic befriending
+        if(getParam('bx_invites_automatically_befriend') == 'on') {
+            $bNeedToFriend = true;
+
+            /**
+             * @hooks
+             * @hookdef hook-bx_invites-add_friend 'bx_invites', 'add_friend' - hook on add friend on new user registred by invitaion
+             * - $unit_name - equals `add_friend`
+             * - $action - equals `invite` 
+             * - $object_id - not used
+             * - $sender_id - not used
+             * - $extra_params - array of additional params with the following array keys:
+             *      - `profile_id` - [int] profile_id for user registred by invitaion
+             *      - `override_result` - [bool] by ref, if true friend will be added, can be overridden in hook processing
+             * @hook @ref hook-bx_invites-add_friend
+             */
+            bx_alert($this->_sModule, 'add_friend', 0, 0, [
+                'profile_id' => $oAlert->iObject,
+                'override_result' => &$bNeedToFriend,
+            ]);
+
+            if($bNeedToFriend) {
+                $iProfileInvitor = $this->_oModule->_oDb->getInvites([
+                    'type' => 'profile_id_by_joined_account_id', 
+                    'value' => $oProfile->getAccountId()
+                ]);
+
+                if($iProfileInvitor && ($oConnection = BxDolConnection::getObjectInstance('sys_profiles_friends')) !== false){
+                    $oConnection->addConnection($oAlert->iObject, $iProfileInvitor);
+                    $oConnection->addConnection($iProfileInvitor, $oAlert->iObject);
+                }
+            }
+        }
         
-		$bNeedToFriend = true;
         
-        /**
-         * @hooks
-         * @hookdef hook-bx_invites-add_friend 'bx_invites', 'add_friend' - hook on add friend on new user registred by invitaion
-         * - $unit_name - equals `add_friend`
-         * - $action - equals `invite` 
-         * - $object_id - not used
-         * - $sender_id - not used
-         * - $extra_params - array of additional params with the following array keys:
-         *      - `profile_id` - [int] profile_id for user registred by invitaion
-         *      - `override_result` - [bool] by ref, if true friend will be added, can be overridden in hook processing
-         * @hook @ref hook-bx_invites-add_friend
-         */
-		bx_alert($this->_sModule, 'add_friend', 0, 0, [
-			'profile_id' => $oAlert->iObject,
-			'override_result' => &$bNeedToFriend,
-		]);
-		
-		if ($bNeedToFriend){
-			$oProfile = BxDolProfile::getInstanceMagic($oAlert->iObject);
-			if ($oProfile && $oProfile->isActAsProfile()){
-				$iProfileInvitor = $this->_oModule->_oDb->getInvites(array('type' => 'profile_id_by_joined_account_id', 'value' => $oProfile->getAccountId()));
-				if ($iProfileInvitor){
-					$oConnFrinds = BxDolConnection::getObjectInstance('sys_profiles_friends');
-					$oConnFrinds->addConnection($oAlert->iObject, $iProfileInvitor);
-					$oConnFrinds->addConnection($iProfileInvitor, $oAlert->iObject);
-				}
-			}  
-		}
     }
     
     protected function _processProfileDelete($oAlert)

+ 68 - 22
modules/boonex/invites/classes/BxInvTemplate.php

@@ -64,40 +64,71 @@ class BxInvTemplate extends BxBaseModGeneralTemplate
         return $this->parseHtmlByName('invite_info.html', $aVars);
     }
     
-    public function getBlockInvite($iAccountId, $iProfileId, $bRedirect = false)
+    public function getBlockInvite($iAccountId, $iProfileId, $aParams = [])
     {
-        $mInvitesRemain = $this->_oConfig->getCountPerUser();
-        if($mInvitesRemain === true)
-            $mInvitesRemain = _t('_bx_invites_txt_unlimited');
-        
-        $sUrl = bx_absolute_url(BxDolPermalinks::getInstance()->permalink($this->_oConfig->CNF['URL_INVITE']));
-
-        if($bRedirect) {
-            $sRedirectCode = $this->_oConfig->getRedirectCode();
+        $aRequestParams = [];
 
+        //-- Process 'redirect to URL'.
+        if(isset($aParams['redirect']) && $aParams['redirect'] === true) {
             list($sPageLink, $aPageParams) = bx_get_base_url_inline();
-            $sRedirectValue = bx_append_url_params($sPageLink, $aPageParams);
-            if($this->_bIsApi){
-                $sRedirectValue = $aPageParams['params'][0];
+
+            if(!$this->_bIsApi) {
+                if(isset($aPageParams['_q']))
+                    unset($aPageParams['_q']);
+
+                $sRedirect = bx_append_url_params($sPageLink, $aPageParams);
             }
+            else
+                $sRedirect = $aPageParams['params'][0];
 
-            $oSession = BxDolSession::getInstance();
-            if($oSession->isValue($sRedirectCode))
-                $oSession->unsetValue($sRedirectCode);
-            $oSession->setValue($sRedirectCode, $sRedirectValue);
+            $aRequestParams = array_merge($aRequestParams, [
+                'aja' => 'redirect',
+                'ajp' => $sRedirect
+            ]);
         }
-        
-        if($this->_bIsApi){
-            return [bx_api_get_block('invite', ['remain' => $mInvitesRemain, 'request_url' => 'bx_invites/get_link/'])];
+
+        $sJsObject = $this->_oConfig->getJsObject('main');
+        $sInviteUrl = BxDolPermalinks::getInstance()->permalink($this->_oConfig->CNF['URL_INVITE']);
+        $mInvitesRemain = $this->_oConfig->getCountPerUser();
+
+        $aTmplVarsShowByCode = isAdmin($iAccountId) ? ['js_object' => $sJsObject] : [];
+
+        //-- Process 'invite to context'.
+        if(isset($aParams['context']) && ($iContext = (int)$aParams['context']) != 0) {
+            $sInviteUrl = bx_append_url_params($sInviteUrl, ['aja' => 'invite_to_context', 'ajp' => $iContext]);
+
+            $aRequestParams = array_merge($aRequestParams, [
+                'aja' => 'invite_to_context',
+                'ajp' => $iContext
+            ]);
+
+            $sContext = BxDolProfile::getInstance($iContext)->getModule();
+            if(!$aTmplVarsShowByCode && bx_srv($sContext, 'is_admin', [$iContext, $iProfileId])) {
+                $mInvitesRemain = true;
+
+                $aTmplVarsShowByCode = ['js_object' => $sJsObject];
+            }
         }
 
+        if($mInvitesRemain === true)
+            $mInvitesRemain = _t('_bx_invites_txt_unlimited');
+
+        if($this->_bIsApi)
+            return [bx_api_get_block('invite', ['remain' => $mInvitesRemain, 'request_url' => 'bx_invites/get_link/'])];
+
         $this->getCssJs();
         return $this->parseHtmlByName('block_invite.html', [
             'style_prefix' => $this->_oConfig->getPrefix('style'),
-            'js_object' => $this->_oConfig->getJsObject('main'),
+            'js_object' => $sJsObject,
             'text' => _t('_bx_invites_txt_invite_block_text', $mInvitesRemain),
-            'url' => $sUrl,
-            'js_code' => $this->getJsCode('main')
+            'url' => bx_absolute_url($sInviteUrl),
+            'bx_if:show_by_code' => [
+                'condition' => !empty($aTmplVarsShowByCode),
+                'content' => $aTmplVarsShowByCode
+            ],
+            'js_code' => $this->getJsCode('main', [
+                'oRequestParams' => $aRequestParams
+            ])
         ]);
     }
 
@@ -189,6 +220,21 @@ class BxInvTemplate extends BxBaseModGeneralTemplate
         return $this->_bIsApi ? [bx_api_get_msg(_t('_bx_invites_msg_request_sent'))] : array('content' => MsgBox(_t('_bx_invites_msg_request_sent')), 'content_id' => $sFormId, 'eval' => $sEval);
     }
 
+    public function getCodePopup($sKey, $sLink)
+    {
+        $sId = $this->_oConfig->getHtmlIds('code_popup');
+        $sTitle = _t('_bx_invites_txt_code_popup_title');
+        $sContent = $this->parseHtmlByName('popup_code.html', [
+            'style_prefix' => $this->_oConfig->getPrefix('style'),
+            'html_id_code' => $this->_oConfig->getHtmlIds('code_input'),
+            'html_id_code_link' => $this->_oConfig->getHtmlIds('code_link_input'),
+            'code' => $sKey,
+            'link' => $sLink
+        ]);
+
+        return BxTemplFunctions::getInstance()->popupBox($sId, $sTitle, $sContent, true);
+    }
+
     public function getLinkPopup($sLink)
     {
         $sId = $this->_oConfig->getHtmlIds('link_popup');

+ 146 - 136
modules/boonex/invites/install/langs/en.xml

@@ -1,63 +1,66 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources name="en" flag="gb" title="English">
 
-	<string name="_bx_invites"><![CDATA[Invitations]]></string>
-
-	<!-- Forms -->
-	<string name="_bx_invites_form_invite"><![CDATA[Invite]]></string>
-	<string name="_bx_invites_form_invite_display_send"><![CDATA[Send]]></string>
-	<string name="_bx_invites_form_invite_input_sys_emails"><![CDATA[Emails]]></string>
-	<string name="_bx_invites_form_invite_input_emails"><![CDATA[Emails]]></string>
-	<string name="_bx_invites_form_invite_input_emails_inf"><![CDATA[Use semicolon to separate emails.]]></string>
-	<string name="_bx_invites_form_invite_input_emails_err"><![CDATA[You need to use correct emails and enter at least one email.]]></string>
-	<string name="_bx_invites_form_invite_input_sys_text"><![CDATA[Text]]></string>
-	<string name="_bx_invites_form_invite_input_text"><![CDATA[Text]]></string>
-	<string name="_bx_invites_form_invite_input_text_err"><![CDATA[You need to type the text which will be added to invitation email.]]></string>
-	<string name="_bx_invites_form_invite_input_sys_do_submit"><![CDATA[Send]]></string>
-	<string name="_bx_invites_form_invite_input_do_submit"><![CDATA[Send]]></string>
-
-	<string name="_bx_invites_form_request"><![CDATA[Request Invitation]]></string>
-	<string name="_bx_invites_form_request_display_send"><![CDATA[Send]]></string>
-	<string name="_bx_invites_form_request_input_sys_name"><![CDATA[Your Name]]></string>
-	<string name="_bx_invites_form_request_input_name"><![CDATA[Your Name]]></string>
-	<string name="_bx_invites_form_request_input_name_err"><![CDATA[You need to type your name.]]></string>
-	<string name="_bx_invites_form_request_input_sys_email"><![CDATA[Your email]]></string>
-	<string name="_bx_invites_form_request_input_email"><![CDATA[Your email]]></string>
-	<string name="_bx_invites_form_request_input_email_err"><![CDATA[You need to type the correct email.]]></string>
-	<string name="_bx_invites_form_request_input_sys_text"><![CDATA[Text]]></string>
-	<string name="_bx_invites_form_request_input_text"><![CDATA[Why do you want to join?]]></string>
-	<string name="_bx_invites_form_request_input_text_err"><![CDATA[You need to briefly describe why you want to join our site.]]></string>
-	<string name="_bx_invites_form_request_input_sys_do_submit"><![CDATA[Send]]></string>
-	<string name="_bx_invites_form_request_input_do_submit"><![CDATA[Send]]></string>
-
-
-	<!-- Grids -->
-	<string name="_bx_invites_grid_column_title_name"><![CDATA[Name]]></string>
-	<string name="_bx_invites_grid_column_title_email"><![CDATA[Email]]></string>
-	<string name="_bx_invites_grid_column_title_nip"><![CDATA[IP]]></string>
-	<string name="_bx_invites_grid_column_title_date"><![CDATA[Date]]></string>
-
-  <string name="_bx_invites_grid_column_title_date_invite"><![CDATA[Date invite]]></string>
-  <string name="_bx_invites_grid_column_title_date_seen"><![CDATA[Date seen]]></string>
-  <string name="_bx_invites_grid_column_title_date_joined"><![CDATA[Date joined]]></string>
-  <string name="_bx_invites_grid_column_title_joined_account"><![CDATA[Joined]]></string>
-  <string name="_bx_invites_grid_column_title_status"><![CDATA[Status]]></string>
-
-	<string name="_bx_invites_grid_action_title_adm_info"><![CDATA[Info]]></string>
-  <string name="_bx_invites_grid_action_title_adm_invite_info"><![CDATA[Invitation info]]></string>
-  <string name="_bx_invites_grid_action_title_adm_invite"><![CDATA[Invite]]></string>
-	<string name="_bx_invites_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
-  <string name="_bx_invites_grid_action_title_adm_add"><![CDATA[Send invitations]]></string>
-
-  <string name="_bx_invites_grid_invites_column_title_email"><![CDATA[Email]]></string>
-  <string name="_bx_invites_grid_invites_column_title_date"><![CDATA[Date]]></string>
-  <string name="_bx_invites_grid_invites_column_title_who_sent"><![CDATA[Who sent]]></string>
-  <string name="_bx_invites_grid_invites_column_title_date_seen"><![CDATA[Date seen]]></string>
-  <string name="_bx_invites_grid_invites_column_title_joined_account"><![CDATA[Joined account]]></string>
-  <string name="_bx_invites_grid_invites_column_title_date_joined"><![CDATA[Date joined]]></string>
-  <string name="_bx_invites_grid_invites_column_title_request"><![CDATA[Request]]></string>
-  <string name="_bx_invites_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
-  <string name="_bx_invites_grid_txt_view_request"><![CDATA[View request]]></string>
+    <string name="_bx_invites"><![CDATA[Invitations]]></string>
+
+    <!-- Forms -->
+    <string name="_bx_invites_form_invite"><![CDATA[Invite]]></string>
+    <string name="_bx_invites_form_invite_display_send"><![CDATA[Send]]></string>
+    <string name="_bx_invites_form_invite_input_sys_emails"><![CDATA[Emails]]></string>
+    <string name="_bx_invites_form_invite_input_emails"><![CDATA[Emails]]></string>
+    <string name="_bx_invites_form_invite_input_emails_inf"><![CDATA[Use semicolon to separate emails.]]></string>
+    <string name="_bx_invites_form_invite_input_emails_err"><![CDATA[You need to use correct emails and enter at least one email.]]></string>
+    <string name="_bx_invites_form_invite_input_sys_email_use"><![CDATA[Emails mandatory use]]></string>
+    <string name="_bx_invites_form_invite_input_email_use"><![CDATA[Mandatory use of the specified emails]]></string>
+    <string name="_bx_invites_form_invite_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_invites_form_invite_input_text"><![CDATA[Text]]></string>
+    <string name="_bx_invites_form_invite_input_text_err"><![CDATA[You need to type the text which will be added to invitation email.]]></string>
+    <string name="_bx_invites_form_invite_input_sys_do_submit"><![CDATA[Send]]></string>
+    <string name="_bx_invites_form_invite_input_do_submit"><![CDATA[Send]]></string>
+
+    <string name="_bx_invites_form_request"><![CDATA[Request Invitation]]></string>
+    <string name="_bx_invites_form_request_display_send"><![CDATA[Send]]></string>
+    <string name="_bx_invites_form_request_input_sys_name"><![CDATA[Your Name]]></string>
+    <string name="_bx_invites_form_request_input_name"><![CDATA[Your Name]]></string>
+    <string name="_bx_invites_form_request_input_name_err"><![CDATA[You need to type your name.]]></string>
+    <string name="_bx_invites_form_request_input_sys_email"><![CDATA[Your email]]></string>
+    <string name="_bx_invites_form_request_input_email"><![CDATA[Your email]]></string>
+    <string name="_bx_invites_form_request_input_email_err"><![CDATA[You need to type the correct email.]]></string>
+    <string name="_bx_invites_form_request_input_sys_text"><![CDATA[Text]]></string>
+    <string name="_bx_invites_form_request_input_text"><![CDATA[Why do you want to join?]]></string>
+    <string name="_bx_invites_form_request_input_text_err"><![CDATA[You need to briefly describe why you want to join our site.]]></string>
+    <string name="_bx_invites_form_request_input_sys_do_submit"><![CDATA[Send]]></string>
+    <string name="_bx_invites_form_request_input_do_submit"><![CDATA[Send]]></string>
+
+    <!-- Grids -->
+    <string name="_bx_invites_grid_column_title_name"><![CDATA[Name]]></string>
+    <string name="_bx_invites_grid_column_title_email"><![CDATA[Email]]></string>
+    <string name="_bx_invites_grid_column_title_nip"><![CDATA[IP]]></string>
+    <string name="_bx_invites_grid_column_title_date"><![CDATA[Date]]></string>
+
+    <string name="_bx_invites_grid_column_title_date_invite"><![CDATA[Date invite]]></string>
+    <string name="_bx_invites_grid_column_title_date_seen"><![CDATA[Date seen]]></string>
+    <string name="_bx_invites_grid_column_title_date_joined"><![CDATA[Date joined]]></string>
+    <string name="_bx_invites_grid_column_title_joined_account"><![CDATA[Joined]]></string>
+    <string name="_bx_invites_grid_column_title_status"><![CDATA[Status]]></string>
+
+    <string name="_bx_invites_grid_action_title_adm_info"><![CDATA[Info]]></string>
+    <string name="_bx_invites_grid_action_title_adm_invite_info"><![CDATA[Invitation info]]></string>
+    <string name="_bx_invites_grid_action_title_adm_invite"><![CDATA[Invite]]></string>
+    <string name="_bx_invites_grid_action_title_adm_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_invites_grid_action_title_adm_add"><![CDATA[Send invitations]]></string>
+
+    <string name="_bx_invites_grid_invites_column_title_email"><![CDATA[Email]]></string>
+    <string name="_bx_invites_grid_invites_column_title_date"><![CDATA[Date]]></string>
+    <string name="_bx_invites_grid_invites_column_title_who_sent"><![CDATA[Who sent]]></string>
+    <string name="_bx_invites_grid_invites_column_title_multi"><![CDATA[Reusable]]></string>
+    <string name="_bx_invites_grid_invites_column_title_aj"><![CDATA[After Join]]></string>
+    <string name="_bx_invites_grid_invites_column_title_date_seen"><![CDATA[Date seen]]></string>
+    <string name="_bx_invites_grid_invites_column_title_joined_account"><![CDATA[Joined account]]></string>
+    <string name="_bx_invites_grid_invites_column_title_date_joined"><![CDATA[Date joined]]></string>
+    <string name="_bx_invites_grid_invites_column_title_request"><![CDATA[Request]]></string>
+    <string name="_bx_invites_grid_txt_account_manager"><![CDATA[Redirect to manage account.]]></string>
+    <string name="_bx_invites_grid_txt_view_request"><![CDATA[View request]]></string>
 
     <!-- Pages and Blocks -->
     <string name="_bx_invites_page_title_sys_invite"><![CDATA[Invite]]></string>
@@ -80,33 +83,33 @@
     <string name="_bx_invites_page_title_requests"><![CDATA[Manage Requests]]></string>
     <string name="_bx_invites_page_block_title_requests"><![CDATA[Manage Requests]]></string>
 
-	<!-- Menus -->
-	<string name="_bx_invites_menu_item_title_system_admt_requests"><![CDATA[Invitation requests]]></string>
-	<string name="_bx_invites_menu_item_title_admt_requests"><![CDATA[Invitations]]></string>
-	<string name="_bx_invites_menu_item_title_requests"><![CDATA[Requests]]></string>
-  <string name="_bx_invites_menu_dashboard_manage_tools_addon_counter1_caption"><![CDATA[awaiting]]></string>
-  <string name="_bx_invites_menu_item_title_manage_requests"><![CDATA[Manage requests]]></string>
-  <string name="_bx_invites_menu_item_title_manage_invites"><![CDATA[Manage invites]]></string>
-
-  <!-- Options -->
-  <string name="_bx_invites_option_automatically_befriend"><![CDATA[Enable automatically befriend inviter and invited]]></string>
-	<string name="_bx_invites_option_key_lifetime"><![CDATA[Invitation key lifetime (in days)]]></string>
-	<string name="_bx_invites_option_enable_request_invite"><![CDATA[Enable invitation requests by email]]></string>
-  <string name="_bx_invites_option_requests_notifications"><![CDATA[Enable invitation requests in notifications]]></string>
-  <string name="_bx_invites_option_requests_email"><![CDATA[Emails to send invitation requests to (comma separated)]]></string>
-	<string name="_bx_invites_option_enable_reg_by_inv"><![CDATA[Enable registration by invitation only]]></string>
-
-
-	<!-- ACL -->
-	<string name="_bx_invites_acl_action_invite"><![CDATA[Invite]]></string>
-	<string name="_bx_invites_acl_action_request"><![CDATA[Request Invitation]]></string>
-	<string name="_bx_invites_acl_action_delete_request"><![CDATA[Delete invitation requests]]></string>
-  <string name="_bx_invites_acl_action_delete_invite"><![CDATA[Delete invite]]></string>
-
-	<!-- Email Templates -->
-	<string name="_bx_invites_et_invite_form_message"><![CDATA[Invite form message.]]></string>
-	<string name="_bx_invites_et_invite_form_message_subject"><![CDATA[Invitation from {site_name}.]]></string>
-	<string name="_bx_invites_et_invite_form_message_body"><![CDATA[{email_header}
+    <!-- Menus -->
+    <string name="_bx_invites_menu_item_title_system_admt_requests"><![CDATA[Invitation requests]]></string>
+    <string name="_bx_invites_menu_item_title_admt_requests"><![CDATA[Invitations]]></string>
+    <string name="_bx_invites_menu_item_title_requests"><![CDATA[Requests]]></string>
+    <string name="_bx_invites_menu_dashboard_manage_tools_addon_counter1_caption"><![CDATA[awaiting]]></string>
+    <string name="_bx_invites_menu_item_title_manage_requests"><![CDATA[Manage requests]]></string>
+    <string name="_bx_invites_menu_item_title_manage_invites"><![CDATA[Manage invites]]></string>
+
+    <!-- Options -->
+    <string name="_bx_invites_option_automatically_befriend"><![CDATA[Enable automatically befriend inviter and invited]]></string>
+    <string name="_bx_invites_option_key_lifetime"><![CDATA[Invitation key lifetime (in days)]]></string>
+    <string name="_bx_invites_option_enable_request_invite"><![CDATA[Enable invitation requests by email]]></string>
+    <string name="_bx_invites_option_requests_notifications"><![CDATA[Enable invitation requests in notifications]]></string>
+    <string name="_bx_invites_option_requests_email"><![CDATA[Emails to send invitation requests to (comma separated)]]></string>
+    <string name="_bx_invites_option_enable_reg_by_inv"><![CDATA[Enable registration by invitation only]]></string>
+
+
+    <!-- ACL -->
+    <string name="_bx_invites_acl_action_invite"><![CDATA[Invite]]></string>
+    <string name="_bx_invites_acl_action_request"><![CDATA[Request Invitation]]></string>
+    <string name="_bx_invites_acl_action_delete_request"><![CDATA[Delete invitation requests]]></string>
+    <string name="_bx_invites_acl_action_delete_invite"><![CDATA[Delete invite]]></string>
+
+    <!-- Email Templates -->
+    <string name="_bx_invites_et_invite_form_message"><![CDATA[Invite form message.]]></string>
+    <string name="_bx_invites_et_invite_form_message_subject"><![CDATA[Invitation from {site_name}.]]></string>
+    <string name="_bx_invites_et_invite_form_message_body"><![CDATA[{email_header}
 <p><b>Dear Friend</b>,</p>
 <p>{profile_name} invites you to join to <a href="{site_url}">{site_name}</a> community site.<br />Message from {profile_name}:</p>
 <hr />
@@ -115,9 +118,9 @@
 <p>Click the following link to join: <a href="{join_url}">{join_url}</a></p>
 {email_footer}]]></string>
 
-	<string name="_bx_invites_et_invite_by_request_message"><![CDATA[Invite by request message.]]></string>
-	<string name="_bx_invites_et_invite_by_request_message_subject"><![CDATA[Invitation from {site_name}.]]></string>
-	<string name="_bx_invites_et_invite_by_request_message_body">
+    <string name="_bx_invites_et_invite_by_request_message"><![CDATA[Invite by request message.]]></string>
+    <string name="_bx_invites_et_invite_by_request_message_subject"><![CDATA[Invitation from {site_name}.]]></string>
+    <string name="_bx_invites_et_invite_by_request_message_body">
   <![CDATA[{email_header}
 <p><b>Dear Friend</b>,</p>
 <p>You are welcome to join <a href="{site_url}">{site_name}</a> community site.</p>
@@ -125,59 +128,66 @@
 <img src="{seen_image_url}" width="1" height="1">
 {email_footer}]]></string>
 
-	<string name="_bx_invites_et_request_form_message"><![CDATA[Request Invitation form message.]]></string>
-	<string name="_bx_invites_et_request_form_message_subject"><![CDATA[Request invitation.]]></string>
-	<string name="_bx_invites_et_request_form_message_body"><![CDATA[{email_header}
+    <string name="_bx_invites_et_request_form_message"><![CDATA[Request Invitation form message.]]></string>
+    <string name="_bx_invites_et_request_form_message_subject"><![CDATA[Request invitation.]]></string>
+    <string name="_bx_invites_et_request_form_message_body"><![CDATA[{email_header}
 <p><b>Dear Administrator</b>,</p>
 <p>{sender_name} (<a href="mailto:{sender_email}">{sender_email}</a>; IP {sender_ip}) requested an invitation to join <b>{site_name}</b> site.</p>
 <p><a href="{manage_url}">Click here</a> to manage requests.</p>
 {email_footer}]]></string>
 
 
-	<!-- Common Texts -->
-	<string name="_bx_invites_txt_link_popup_title"><![CDATA[Invitation Link]]></string>
-	<string name="_bx_invites_txt_invite_block_text"><![CDATA[You can invite your friends to join. You have <b>{0}</b> invites to share.]]></string>
-	<string name="_bx_invites_txt_request_block_text"><![CDATA[Registration is by invitation only.]]></string>
-	<string name="_bx_invites_txt_unlimited"><![CDATA[unlimited]]></string>
-	
-	<string name="_bx_invites_btn_invite_email"><![CDATA[Invite By Email]]></string>
-	<string name="_bx_invites_btn_invite_link"><![CDATA[Get Invitation Link]]></string>
-	<string name="_bx_invites_btn_copy"><![CDATA[Copy]]></string>
-	<string name="_bx_invites_btn_request"><![CDATA[Request Invitation]]></string>
-	<string name="_bx_invites_msg_invitation"><![CDATA[Hello! This site might be interesting for you.]]></string>
-	<string name="_bx_invites_msg_invitation_sent"><![CDATA[Invitation message was queued to send to {0} email addresses from the list.]]></string>
-	<string name="_bx_invites_msg_request_sent"><![CDATA[Invitation request received. We'll send an invite when it's your turn.]]></string>
-	<string name="_bx_invites_err_cannot_perform"><![CDATA[An error appeared. Please report.]]></string>
-	<string name="_bx_invites_err_limit_reached"><![CDATA[The number of invitations sent by you reached the limit.]]></string>
-	<string name="_bx_invites_err_not_available"><![CDATA[The feature is not available now. Please, try again later.]]></string>
-	<string name="_bx_invites_err_invite"><![CDATA[Cannot send an invitation on request.]]></string>
-	<string name="_bx_invites_err_delete_invite"><![CDATA[Cannot delete the invite.]]></string>
-  <string name="_bx_invites_err_delete_request"><![CDATA[Cannot delete the request.]]></string>
-	<string name="_bx_invites_err_used"><![CDATA[The invitation link isn't available or already used.]]></string>
-  <string name="_bx_invites_err_already_send"><![CDATA[The request already sent for this email.]]></string>
-  <string name="_bx_invites_err_already_registed"><![CDATA[User with this email already registered. Please use  <a href="{0}">forgot password</a> to restore access to your account.]]></string>
-  <string name="_bx_invites_request_status_new"><![CDATA[New]]></string>
-  <string name="_bx_invites_request_status_invited"><![CDATA[Invited]]></string>
-  <string name="_bx_invites_request_status_seen"><![CDATA[Seen]]></string>
-  <string name="_bx_invites_request_status_joined"><![CDATA[Joined]]></string>
-  <string name="_bx_invites_request_status_for_filter_all"><![CDATA[All requests]]></string>
-  <string name="_bx_invites_request_status_for_filter_new"><![CDATA[New requests]]></string>
-  <string name="_bx_invites_request_status_for_filter_invited"><![CDATA[Requests with invites]]></string>
-  <string name="_bx_invites_request_status_for_filter_seen"><![CDATA[Invite seen]]></string>
-  <string name="_bx_invites_request_status_for_filter_joined"><![CDATA[Joined]]></string>
-
-  <string name="_bx_invites_invites_status_for_filter_all"><![CDATA[All invites]]></string>
-  <string name="_bx_invites_invites_status_for_filter_accepted"><![CDATA[Accepted invites]]></string>
-  <string name="_bx_invites_invites_status_for_filter_not_accepted"><![CDATA[Not accepted invites]]></string>
-
-  <string name="_bx_invites_title_date_invite_sent"><![CDATA[Date sent]]></string>
-  <string name="_bx_invites_title_date_invite_seen"><![CDATA[Date seen]]></string>
-
-  <string name="_bx_invites_reports_for_analytics_invited_total"><![CDATA[Invited - Total numbers]]></string>
-  <string name="_bx_invites_reports_for_analytics_invited_speed_grows"><![CDATA[Invited - Grows speed]]></string>
-  <string name="_bx_invites_reports_for_analytics_invitation_total"><![CDATA[Invitation - Total numbers]]></string>
-  <string name="_bx_invites_reports_for_analytics_invitation_speed_grows"><![CDATA[Invitation - Grows speed]]></string>
-
-  <string name="_bx_invites_alert_action_request"><![CDATA[<b class="bx-ntfs-content-profile">{entry_sample}</b> request invitation - <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
-  <string name="_bx_invites_alert_action_request_notify_personal"><![CDATA[New requests]]></string>
+    <!-- Common Texts -->
+    <string name="_bx_invites_txt_code_popup_title"><![CDATA[Invitation Code]]></string>
+    <string name="_bx_invites_txt_link_popup_title"><![CDATA[Invitation Link]]></string>
+    <string name="_bx_invites_txt_invite_block_text"><![CDATA[You can invite your friends to join. You have <b>{0}</b> invites to share.]]></string>
+    <string name="_bx_invites_txt_request_block_text"><![CDATA[Registration is by invitation only.]]></string>
+    <string name="_bx_invites_txt_unlimited"><![CDATA[unlimited]]></string>
+
+    <string name="_bx_invites_btn_invite_code"><![CDATA[Invite By Code]]></string>
+    <string name="_bx_invites_btn_invite_email"><![CDATA[Invite By Email]]></string>
+    <string name="_bx_invites_btn_invite_link"><![CDATA[Get Invitation Link]]></string>
+    <string name="_bx_invites_btn_copy"><![CDATA[Copy]]></string>
+    <string name="_bx_invites_btn_copy_as_link"><![CDATA[Copy as link]]></string>
+    <string name="_bx_invites_btn_request"><![CDATA[Request Invitation]]></string>
+    <string name="_bx_invites_msg_invitation"><![CDATA[Hello! This site might be interesting for you.]]></string>
+    <string name="_bx_invites_msg_invitation_sent"><![CDATA[Invitation message was queued to send to {0} email addresses from the list.]]></string>
+    <string name="_bx_invites_msg_request_sent"><![CDATA[Invitation request received. We'll send an invite when it's your turn.]]></string>
+    <string name="_bx_invites_err_cannot_perform"><![CDATA[An error appeared. Please report.]]></string>
+    <string name="_bx_invites_err_limit_reached"><![CDATA[The number of invitations sent by you reached the limit.]]></string>
+    <string name="_bx_invites_err_not_available"><![CDATA[The feature is not available now. Please, try again later.]]></string>
+    <string name="_bx_invites_err_invite"><![CDATA[Cannot send an invitation on request.]]></string>
+    <string name="_bx_invites_err_delete_invite"><![CDATA[Cannot delete the invite.]]></string>
+    <string name="_bx_invites_err_delete_request"><![CDATA[Cannot delete the request.]]></string>
+    <string name="_bx_invites_err_wrong_email"><![CDATA[Email address from invitation can be used only.]]></string>
+    <string name="_bx_invites_err_used"><![CDATA[The invitation link isn't available or already used.]]></string>
+    <string name="_bx_invites_err_already_send"><![CDATA[The request already sent for this email.]]></string>
+    <string name="_bx_invites_err_already_registed"><![CDATA[User with this email already registered. Please use  <a href="{0}">forgot password</a> to restore access to your account.]]></string>
+    <string name="_bx_invites_request_status_new"><![CDATA[New]]></string>
+    <string name="_bx_invites_request_status_invited"><![CDATA[Invited]]></string>
+    <string name="_bx_invites_request_status_seen"><![CDATA[Seen]]></string>
+    <string name="_bx_invites_request_status_joined"><![CDATA[Joined]]></string>
+    <string name="_bx_invites_request_status_for_filter_all"><![CDATA[All requests]]></string>
+    <string name="_bx_invites_request_status_for_filter_new"><![CDATA[New requests]]></string>
+    <string name="_bx_invites_request_status_for_filter_invited"><![CDATA[Requests with invites]]></string>
+    <string name="_bx_invites_request_status_for_filter_seen"><![CDATA[Invite seen]]></string>
+    <string name="_bx_invites_request_status_for_filter_joined"><![CDATA[Joined]]></string>
+
+    <string name="_bx_invites_invites_aj_redirect"><![CDATA[Redirect]]></string>
+    <string name="_bx_invites_invites_aj_invite_to_context"><![CDATA[Invite to context]]></string>
+    <string name="_bx_invites_invites_status_for_filter_all"><![CDATA[All invites]]></string>
+    <string name="_bx_invites_invites_status_for_filter_accepted"><![CDATA[Accepted invites]]></string>
+    <string name="_bx_invites_invites_status_for_filter_not_accepted"><![CDATA[Not accepted invites]]></string>
+
+    <string name="_bx_invites_title_date_invite_sent"><![CDATA[Date sent]]></string>
+    <string name="_bx_invites_title_date_invite_seen"><![CDATA[Date seen]]></string>
+    <string name="_bx_invites_txt_email_use"><![CDATA[Mandatory use during join.]]></string>
+
+    <string name="_bx_invites_reports_for_analytics_invited_total"><![CDATA[Invited - Total numbers]]></string>
+    <string name="_bx_invites_reports_for_analytics_invited_speed_grows"><![CDATA[Invited - Grows speed]]></string>
+    <string name="_bx_invites_reports_for_analytics_invitation_total"><![CDATA[Invitation - Total numbers]]></string>
+    <string name="_bx_invites_reports_for_analytics_invitation_speed_grows"><![CDATA[Invitation - Grows speed]]></string>
+
+    <string name="_bx_invites_alert_action_request"><![CDATA[<b class="bx-ntfs-content-profile">{entry_sample}</b> request invitation - <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_invites_alert_action_request_notify_personal"><![CDATA[New requests]]></string>
 </resources>

+ 14 - 9
modules/boonex/invites/install/sql/enable.sql

@@ -122,7 +122,7 @@ INSERT INTO `sys_acl_matrix` (`IDLevel`, `IDAction`, `AllowedCount`) VALUES
 -- GRIDS
 INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
 ('bx_invites_requests', 'Sql', 'SELECT `bx_inv_requests`.* FROM `bx_inv_requests` WHERE 1', 'bx_inv_requests', 'id', 'status, date', '', '', 20, NULL, 'start', '', 'bx_inv_requests`.`name, bx_inv_requests`.`email', '', 'like', '', '', 192, 'BxInvGridRequests', 'modules/boonex/invites/classes/BxInvGridRequests.php'),
-('bx_invites_invites', 'Sql', 'SELECT `bx_inv_invites`.* FROM `bx_inv_invites` WHERE 1', 'bx_inv_invites', 'id', 'date', '', '', 20, NULL, 'start', '', 'email', '', 'like', '', '', 192, 'BxInvGridInvites', 'modules/boonex/invites/classes/BxInvGridInvites.php');
+('bx_invites_invites', 'Sql', 'SELECT `bx_inv_invites`.* FROM `bx_inv_invites` WHERE 1', 'bx_inv_invites', 'id', 'date', '', '', 20, NULL, 'start', '', 'email', '', 'like', 'email,date,date_seen,date_joined', '', 192, 'BxInvGridInvites', 'modules/boonex/invites/classes/BxInvGridInvites.php');
 
 INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
 ('bx_invites_requests', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
@@ -135,14 +135,16 @@ INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable
 ('bx_invites_requests', 'actions', '', '20%', 0, '', '', 8),
 
 ('bx_invites_invites', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
-('bx_invites_invites', 'email', '_bx_invites_grid_invites_column_title_email', '15%', 1, '25', '', 2),
-('bx_invites_invites', 'who_send', '_bx_invites_grid_invites_column_title_who_sent', '15%', 0, '', '', 3),
-('bx_invites_invites', 'date', '_bx_invites_grid_invites_column_title_date', '10%', 0, '20', '', 4),
-('bx_invites_invites', 'date_seen', '_bx_invites_grid_invites_column_title_date_seen', '10%', 0, '20', '', 5),
-('bx_invites_invites', 'joined_account', '_bx_invites_grid_invites_column_title_joined_account', '15%', 0, '20', '', 6),
-('bx_invites_invites', 'date_joined', '_bx_invites_grid_invites_column_title_date_joined', '10%', 0, '20', '', 7),
-('bx_invites_invites', 'request', '_bx_invites_grid_invites_column_title_request', '13%', 0, '20', '', 8),
-('bx_invites_invites', 'actions', '', '20%', 0, '', '', 8);
+('bx_invites_invites', 'who_send', '_bx_invites_grid_invites_column_title_who_sent', '12%', 0, '', '', 2),
+('bx_invites_invites', 'multi', '_bx_invites_grid_invites_column_title_multi', '5%', 0, '16', '', 3),
+('bx_invites_invites', 'email', '_bx_invites_grid_invites_column_title_email', '15%', 1, '25', '', 4),
+('bx_invites_invites', 'aj', '_bx_invites_grid_invites_column_title_aj', '10%', 0, '16', '', 5),
+('bx_invites_invites', 'date', '_bx_invites_grid_invites_column_title_date', '8%', 0, '20', '', 6),
+('bx_invites_invites', 'date_seen', '_bx_invites_grid_invites_column_title_date_seen', '8%', 0, '20', '', 7),
+('bx_invites_invites', 'joined_account', '_bx_invites_grid_invites_column_title_joined_account', '12%', 0, '20', '', 8),
+('bx_invites_invites', 'date_joined', '_bx_invites_grid_invites_column_title_date_joined', '8%', 0, '20', '', 9),
+('bx_invites_invites', 'request', '_bx_invites_grid_invites_column_title_request', '8%', 0, '20', '', 10),
+('bx_invites_invites', 'actions', '', '12%', 0, '', '', 11);
 
 
 INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
@@ -173,11 +175,14 @@ INSERT INTO `sys_alerts_handlers`(`name`, `class`, `file`, `service_call`) VALUE
 SET @iHandler := LAST_INSERT_ID();
 
 INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
+('account', 'add_form_check', @iHandler),
 ('account', 'add_form', @iHandler),
 ('account', 'added', @iHandler),
 ('account', 'delete', @iHandler),
+
 ('profile', 'delete', @iHandler),
 ('profile', 'add', @iHandler),
+
 ('bx_analytics', 'get_modules', @iHandler),
 ('bx_analytics', 'get_reports', @iHandler),
 ('bx_analytics', 'get_chart_data_line', @iHandler);

+ 8 - 3
modules/boonex/invites/install/sql/install.sql

@@ -7,8 +7,11 @@ CREATE TABLE IF NOT EXISTS `bx_inv_invites` (
   `account_id` int(11) NOT NULL,
   `profile_id` int(11) NOT NULL,
   `key` varchar(128) NOT NULL,
-  `redirect` varchar(255) NOT NULL default '',
+  `multi` tinyint(4) DEFAULT '0',
   `email` varchar(128) NOT NULL,
+  `email_use` tinyint(4) DEFAULT '0',
+  `aj_action` varchar(32) NOT NULL default '',
+  `aj_params` varchar(255) NOT NULL default '',
   `date` int(11) NOT NULL default '0',
   `date_seen` int(11) DEFAULT NULL,
   `date_joined` int(11) DEFAULT NULL,
@@ -38,13 +41,15 @@ INSERT INTO `sys_form_displays` (`display_name`, `module`, `object`, `title`, `v
 
 INSERT INTO `sys_form_inputs` (`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES
 ('bx_invites_invite', @sName, 'emails', '', '', 0, 'textarea', '_bx_invites_form_invite_input_sys_emails', '_bx_invites_form_invite_input_emails', '_bx_invites_form_invite_input_emails_inf', 1, 0, 0, '', '', '', 'Emails', '', '_bx_invites_form_invite_input_emails_err', '', '', 0, 0),
+('bx_invites_invite', @sName, 'email_use', 1, '', 0, 'switcher', '_bx_invites_form_invite_input_sys_email_use', '_bx_invites_form_invite_input_email_use', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0),
 ('bx_invites_invite', @sName, 'text', '', '', 0, 'textarea', '_bx_invites_form_invite_input_sys_text', '_bx_invites_form_invite_input_text', '', 1, 0, 0, '', '', '', 'Length', 'a:2:{s:3:"min";i:10;s:3:"max";i:5000;}', '_bx_invites_form_invite_input_text_err', '', '', 0, 0),
 ('bx_invites_invite', @sName, 'ifi_do_submit', '_bx_invites_form_invite_input_do_submit', '', 0, 'submit', '_bx_invites_form_invite_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 0, 0);
 
 INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES
 ('bx_invites_invite_send', 'emails', 2147483647, 1, 1),
-('bx_invites_invite_send', 'text', 2147483647, 1, 2),
-('bx_invites_invite_send', 'ifi_do_submit', 2147483647, 1, 3);
+('bx_invites_invite_send', 'email_use', 2147483647, 1, 2),
+('bx_invites_invite_send', 'text', 2147483647, 1, 3),
+('bx_invites_invite_send', 'ifi_do_submit', 2147483647, 1, 4);
 
 
 INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES

+ 83 - 30
modules/boonex/invites/js/main.js

@@ -48,61 +48,114 @@ BxInvMain.prototype.showLinkPopup = function(oElement) {
         this._sActionsUrl + 'get_link/',
         this._getDefaultData(),
         function(oData) {
-        	$this.loadingInButton(oElement, false);
+            $this.loadingInButton(oElement, false);
 
-        	if(oData && oData.popup != undefined) {
-        		var oPopup = $(oData.popup);
-        		var sPopupId = oPopup.attr('id');
-        		var oClipboard = null;
+            if(oData && oData.popup != undefined) {
+                var oPopup = $(oData.popup);
+                var sPopupId = oPopup.attr('id');
+                var oClipboard = null;
 
-            	$('#' + sPopupId).remove();
+                $('#' + sPopupId).remove();
                 oPopup.hide().prependTo('body').dolPopup({
-                    fog: {
-        				color: '#fff',
-        				opacity: .7
+                    onShow: function () {
+                        oClipboard = new ClipboardJS('#' + $this._aHtmlIds['link_popup'] + ' .bx-btn[name = "clipboard"]', {
+                            target: function(oTrigger) {
+                                return $('#' + sPopupId).find('[name = "link"]').get(0);
+                            }
+                        });
+                        oClipboard.on('success', function(oObject) {
+                            $this.hideLinkPopup();
+                        });
                     },
+                    onHide: function () {
+                        if(oClipboard)
+                            oClipboard.destroy();
+                    }
+                });
+            }
+
+            if(oData && oData.message != undefined)
+                    bx_alert(oData.message);
+        },
+        'json'
+    );
+};
+
+BxInvMain.prototype.showCodePopup = function(oElement) {
+    var $this = this;
+
+    this.loadingInButton(oElement, true);
+
+    jQuery.get(
+        this._sActionsUrl + 'get_code/',
+        this._getDefaultData(),
+        function(oData) {
+            $this.loadingInButton(oElement, false);
+
+            if(oData && oData.popup != undefined) {
+                var oPopup = $(oData.popup);
+                var sPopupId = oPopup.attr('id');
+                var oClipboard = oClipboardLink = null;
+
+                $('#' + sPopupId).remove();
+                oPopup.hide().prependTo('body').dolPopup({
                     onShow: function () {
-                    	oClipboard = new ClipboardJS('#' + $this._aHtmlIds['link_popup'] + ' .bx-btn[name = "clipboard"]', {
-                    	    target: function(oTrigger) {
-                    	        return $('#' + sPopupId).find('[name = "link"]').get(0);
-                    	    }
-                    	});
-                    	oClipboard.on('success', function(oObject) {
-                    		$this.hideLinkPopup();
-                    	});
+                        oClipboard = new ClipboardJS('#' + $this._aHtmlIds['code_popup'] + ' .bx-btn[name = "clipboard"]', {
+                            target: function(oTrigger) {
+                                return $('#' + sPopupId).find('[name = "code"]').get(0);
+                            }
+                        });
+                        oClipboard.on('success', function(oObject) {
+                            $this.hideCodePopup();
+                        });
+                        
+                        oClipboardLink = new ClipboardJS('#' + $this._aHtmlIds['code_popup'] + ' .bx-btn[name = "clipboard_link"]', {
+                            target: function(oTrigger) {
+                                return $('#' + sPopupId).find('[name = "link"]').get(0);
+                            }
+                        });
+                        oClipboardLink.on('success', function(oObject) {
+                            $this.hideCodePopup();
+                        });
                     },
                     onHide: function () {
-                    	if(oClipboard)
-                    		oClipboard.destroy();
+                        if(oClipboard)
+                            oClipboard.destroy();
+                        if(oClipboardLink)
+                            oClipboardLink.destroy();
                     }
                 });
-        	}
+            }
 
-        	if(oData && oData.message != undefined)
-        		bx_alert(oData.message);
+            if(oData && oData.message != undefined)
+                bx_alert(oData.message);
         },
         'json'
     );
 };
 
 BxInvMain.prototype.hideLinkPopup = function() {
-	$('#' + this._aHtmlIds['link_popup']).dolPopupHide();	
+    $('#' + this._aHtmlIds['link_popup']).dolPopupHide();	
+};
+
+BxInvMain.prototype.hideCodePopup = function() {
+    $('#' + this._aHtmlIds['code_popup']).dolPopupHide();	
 };
 
 BxInvMain.prototype.loadingInButton = function(e, bShow) {
-	if($(e).length)
-		bx_loading_btn($(e), bShow);
-	else
-		bx_loading($('body'), bShow);	
+    if($(e).length)
+        bx_loading_btn($(e), bShow);
+    else
+        bx_loading($('body'), bShow);
 };
 
 BxInvMain.prototype._loading = function(e, bShow) {
-	var oParent = $(e).length ? $(e) : $('body'); 
-	bx_loading(oParent, bShow);
+    var oParent = $(e).length ? $(e) : $('body'); 
+    bx_loading(oParent, bShow);
 };
 
 BxInvMain.prototype._getDefaultData = function () {
-	var oDate = new Date();
+    var oDate = new Date();
     return jQuery.extend({}, this._oRequestParams, {_t:oDate.getTime()});
 };
 

+ 11 - 6
modules/boonex/invites/template/block_invite.html

@@ -1,10 +1,15 @@
 <div class="__style_prefix__-invite-text">__text__</div>
 <div class="__style_prefix__-invite-btn bx-def-margin-sec-top">
-	<a class="bx-btn bx-def-margin-thd" href="__url__">
-		<bx_text:_bx_invites_btn_invite_email />
-	</a>
-	<a class="bx-btn bx-def-margin-thd" href="javascript:void(0)" onclick="javascript:__js_object__.showLinkPopup(this)">
-		<bx_text:_bx_invites_btn_invite_link />
-	</a>
+    <a class="bx-btn bx-def-margin-thd" href="__url__">
+        <bx_text:_bx_invites_btn_invite_email />
+    </a>
+    <a class="bx-btn bx-def-margin-thd" href="javascript:void(0)" onclick="javascript:__js_object__.showLinkPopup(this)">
+        <bx_text:_bx_invites_btn_invite_link />
+    </a>
+    <bx_if:show_by_code>
+        <a class="bx-btn bx-def-margin-thd" href="javascript:void(0)" onclick="javascript:__js_object__.showCodePopup(this)">
+            <bx_text:_bx_invites_btn_invite_code />
+        </a>
+    </bx_if:show_by_code>
 </div>
 __js_code__

+ 19 - 10
modules/boonex/invites/template/css/main.css

@@ -1,34 +1,34 @@
 /*--- Invite block ---*/
 div.bx-inv-invite-btn  {
-	text-align: center;
+    text-align: center;
 }
 div.bx-inv-invite-btn .bx-btn {
-	float: none;
-	display: inline-block;
+    float: none;
+    display: inline-block;
 }
 
 
 /*--- Invitation Link popup ---*/
 div.bx-inv-link-actions {
-	text-align: center;
+    text-align: center;
 }
 div.bx-inv-link-actions .bx-btn {
-	float: none;
-	display: inline-block;
+    float: none;
+    display: inline-block;
 }
 
 
 /*--- Request Invite block ---*/
 div.bx-inv-request-btn  .bx-btn {
-	float: none;
-	display: inline-block;
+    float: none;
+    display: inline-block;
 }
 
 
 /*--- Manage Requests page ---*/
 div.bx-inv-request-text {
-	max-width: 400px;
-	max-width: 25rem;
+    max-width: 400px;
+    max-width: 25rem;
 }
 
 /*--- General ---*/
@@ -42,7 +42,16 @@ div.bx-grid-header div.bx-form-element-wrapper {
 div.bx-grid-header div#bx-form-element-filter1 {
     margin-right: 20px;
 }
+
 div.bx-grid-header div#bx-form-element-filter1,
 div.bx-grid-header div#bx-form-element-search {
     margin-top: 0px;
+}
+
+.bx-grid-table .bx-grid-cell.bx-gc-email {
+    white-space: nowrap;
+}
+.bx-grid-table .bx-grid-cell.bx-gc-email img {
+    display: inline-block;
+    margin-left: 0.5rem;
 }

+ 1 - 0
modules/boonex/invites/template/images/icons/ui-alert.svg

@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-triangle-alert-icon lucide-triangle-alert"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>

+ 1 - 0
modules/boonex/invites/template/invite_aj_link.html

@@ -0,0 +1 @@
+<a href="__href__" target="_blank">__content__</a>

+ 17 - 0
modules/boonex/invites/template/popup_code.html

@@ -0,0 +1,17 @@
+<div class="__style_prefix__-code bx-def-padding">
+    <div class="__style_prefix__-code-input bx-form-input-wrapper bx-form-input-wrapper-text">
+        <input id="__html_id_code__" class="bx-def-font-inputs bx-form-input-text" type="text" name="code" value="__code__" />
+        <input id="__html_id_code_link__" class="bx-def-font-inputs bx-form-input-text" type="hidden" name="link" value="__link__" />
+    </div>
+    <div class="__style_prefix__-code-actions bx-def-margin-top bx-clearfix">
+        <button class="bx-btn bx-def-margin-thd" type="button" name="clipboard">
+            <bx_text:_bx_invites_btn_copy />
+        </button>
+        <button class="bx-btn bx-def-margin-thd" type="button" name="clipboard_link">
+            <bx_text:_bx_invites_btn_copy_as_link />
+        </button>
+        <button class="bx-btn bx-def-margin-thd" type="button" onclick="javascript:$('.bx-popup-applied:visible').dolPopupHide()">
+            <bx_text:_Cancel />
+        </button>
+    </div>
+</div>

+ 147 - 138
modules/boonex/russian/data/langs/bx_invites/ru.xml

@@ -1,63 +1,67 @@
 <?xml version="1.0" encoding="utf-8"?>
 <resources name="ru" flag="ru" title="Russian">
 
-	<string name="_bx_invites"><![CDATA[Приглашения]]></string>
-
-	<!-- Forms -->
-	<string name="_bx_invites_form_invite"><![CDATA[Пригласить]]></string>
-	<string name="_bx_invites_form_invite_display_send"><![CDATA[Послать]]></string>
-	<string name="_bx_invites_form_invite_input_sys_emails"><![CDATA[Электронные адреса]]></string>
-	<string name="_bx_invites_form_invite_input_emails"><![CDATA[Электронные адреса]]></string>
-	<string name="_bx_invites_form_invite_input_emails_inf"><![CDATA[Для разделения адресов используйте точку с запятой.]]></string>
-	<string name="_bx_invites_form_invite_input_emails_err"><![CDATA[Нужно ввести как минимум один правильный электронный адрес.]]></string>
-	<string name="_bx_invites_form_invite_input_sys_text"><![CDATA[Текст]]></string>
-	<string name="_bx_invites_form_invite_input_text"><![CDATA[Текст]]></string>
-	<string name="_bx_invites_form_invite_input_text_err"><![CDATA[Нужно ввести текст, который будет добавлен в приглашение.]]></string>
-	<string name="_bx_invites_form_invite_input_sys_do_submit"><![CDATA[Послать]]></string>
-	<string name="_bx_invites_form_invite_input_do_submit"><![CDATA[Послать]]></string>
-
-	<string name="_bx_invites_form_request"><![CDATA[Запросить приглашение]]></string>
-	<string name="_bx_invites_form_request_display_send"><![CDATA[Послать]]></string>
-	<string name="_bx_invites_form_request_input_sys_name"><![CDATA[Ваше имя]]></string>
-	<string name="_bx_invites_form_request_input_name"><![CDATA[Ваше имя]]></string>
-	<string name="_bx_invites_form_request_input_name_err"><![CDATA[Нужно ввести своё имя.]]></string>
-	<string name="_bx_invites_form_request_input_sys_email"><![CDATA[Ваш эл. адрес]]></string>
-	<string name="_bx_invites_form_request_input_email"><![CDATA[Ваш эл. адрес]]></string>
-	<string name="_bx_invites_form_request_input_email_err"><![CDATA[Нужно ввести правильный электронный адрес.]]></string>
-	<string name="_bx_invites_form_request_input_sys_text"><![CDATA[Текст]]></string>
-	<string name="_bx_invites_form_request_input_text"><![CDATA[Почему Вы хотите зарегистрироваться?]]></string>
-	<string name="_bx_invites_form_request_input_text_err"><![CDATA[Нужно вкратце описать, почему Вы хотите зарегистрироваться на нашем сайте.]]></string>
-	<string name="_bx_invites_form_request_input_sys_do_submit"><![CDATA[Послать]]></string>
-	<string name="_bx_invites_form_request_input_do_submit"><![CDATA[Послать]]></string>
-
-
-	<!-- Grids -->
-	<string name="_bx_invites_grid_column_title_name"><![CDATA[Имя]]></string>
-	<string name="_bx_invites_grid_column_title_email"><![CDATA[Эл. адрес]]></string>
-	<string name="_bx_invites_grid_column_title_nip"><![CDATA[IP]]></string>
-	<string name="_bx_invites_grid_column_title_date"><![CDATA[Дата]]></string>
-
-  <string name="_bx_invites_grid_column_title_date_invite"><![CDATA[Дата приглашения]]></string>
-  <string name="_bx_invites_grid_column_title_date_seen"><![CDATA[Дата просмотра]]></string>
-  <string name="_bx_invites_grid_column_title_date_joined"><![CDATA[Дата присоединения]]></string>
-  <string name="_bx_invites_grid_column_title_joined_account"><![CDATA[Присоединился]]></string>
-  <string name="_bx_invites_grid_column_title_status"><![CDATA[Статус]]></string>
-
-  <string name="_bx_invites_grid_action_title_adm_info"><![CDATA[Инфо]]></string>
-  <string name="_bx_invites_grid_action_title_adm_invite_info"><![CDATA[Информация о приглашении]]></string>
-  <string name="_bx_invites_grid_action_title_adm_invite"><![CDATA[Пригласить]]></string>
-  <string name="_bx_invites_grid_action_title_adm_delete"><![CDATA[Удалить]]></string>
-  <string name="_bx_invites_grid_action_title_adm_add"><![CDATA[Отправить приглашения]]></string>
-
-  <string name="_bx_invites_grid_invites_column_title_email"><![CDATA[Эл. адрес]]></string>
-  <string name="_bx_invites_grid_invites_column_title_date"><![CDATA[Дата]]></string>
-  <string name="_bx_invites_grid_invites_column_title_who_sent"><![CDATA[Кто отправил]]></string>
-  <string name="_bx_invites_grid_invites_column_title_date_seen"><![CDATA[Дата отправки]]></string>
-  <string name="_bx_invites_grid_invites_column_title_joined_account"><![CDATA[Присоединившийся]]></string>
-  <string name="_bx_invites_grid_invites_column_title_date_joined"><![CDATA[Дата присоединения]]></string>
-  <string name="_bx_invites_grid_invites_column_title_request"><![CDATA[Запрос]]></string>
-  <string name="_bx_invites_grid_txt_account_manager"><![CDATA[К управлению аккаунтом]]></string>
-  <string name="_bx_invites_grid_txt_view_request"><![CDATA[Просмотреть запрос]]></string>
+    <string name="_bx_invites"><![CDATA[Приглашения]]></string>
+
+    <!-- Forms -->
+    <string name="_bx_invites_form_invite"><![CDATA[Пригласить]]></string>
+    <string name="_bx_invites_form_invite_display_send"><![CDATA[Послать]]></string>
+    <string name="_bx_invites_form_invite_input_sys_emails"><![CDATA[Электронные адреса]]></string>
+    <string name="_bx_invites_form_invite_input_emails"><![CDATA[Электронные адреса]]></string>
+    <string name="_bx_invites_form_invite_input_emails_inf"><![CDATA[Для разделения адресов используйте точку с запятой.]]></string>
+    <string name="_bx_invites_form_invite_input_emails_err"><![CDATA[Нужно ввести как минимум один правильный электронный адрес.]]></string>
+    <string name="_bx_invites_form_invite_input_sys_email_use"><![CDATA[Обязательное использование эл. адресов]]></string>
+    <string name="_bx_invites_form_invite_input_email_use"><![CDATA[Обязательное использование указанных эл. адресов]]></string>
+    <string name="_bx_invites_form_invite_input_sys_text"><![CDATA[Текст]]></string>
+    <string name="_bx_invites_form_invite_input_text"><![CDATA[Текст]]></string>
+    <string name="_bx_invites_form_invite_input_text_err"><![CDATA[Нужно ввести текст, который будет добавлен в приглашение.]]></string>
+    <string name="_bx_invites_form_invite_input_sys_do_submit"><![CDATA[Послать]]></string>
+    <string name="_bx_invites_form_invite_input_do_submit"><![CDATA[Послать]]></string>
+
+    <string name="_bx_invites_form_request"><![CDATA[Запросить приглашение]]></string>
+    <string name="_bx_invites_form_request_display_send"><![CDATA[Послать]]></string>
+    <string name="_bx_invites_form_request_input_sys_name"><![CDATA[Ваше имя]]></string>
+    <string name="_bx_invites_form_request_input_name"><![CDATA[Ваше имя]]></string>
+    <string name="_bx_invites_form_request_input_name_err"><![CDATA[Нужно ввести своё имя.]]></string>
+    <string name="_bx_invites_form_request_input_sys_email"><![CDATA[Ваш эл. адрес]]></string>
+    <string name="_bx_invites_form_request_input_email"><![CDATA[Ваш эл. адрес]]></string>
+    <string name="_bx_invites_form_request_input_email_err"><![CDATA[Нужно ввести правильный электронный адрес.]]></string>
+    <string name="_bx_invites_form_request_input_sys_text"><![CDATA[Текст]]></string>
+    <string name="_bx_invites_form_request_input_text"><![CDATA[Почему Вы хотите зарегистрироваться?]]></string>
+    <string name="_bx_invites_form_request_input_text_err"><![CDATA[Нужно вкратце описать, почему Вы хотите зарегистрироваться на нашем сайте.]]></string>
+    <string name="_bx_invites_form_request_input_sys_do_submit"><![CDATA[Послать]]></string>
+    <string name="_bx_invites_form_request_input_do_submit"><![CDATA[Послать]]></string>
+
+
+    <!-- Grids -->
+    <string name="_bx_invites_grid_column_title_name"><![CDATA[Имя]]></string>
+    <string name="_bx_invites_grid_column_title_email"><![CDATA[Эл. адрес]]></string>
+    <string name="_bx_invites_grid_column_title_nip"><![CDATA[IP]]></string>
+    <string name="_bx_invites_grid_column_title_date"><![CDATA[Дата]]></string>
+
+    <string name="_bx_invites_grid_column_title_date_invite"><![CDATA[Дата приглашения]]></string>
+    <string name="_bx_invites_grid_column_title_date_seen"><![CDATA[Дата просмотра]]></string>
+    <string name="_bx_invites_grid_column_title_date_joined"><![CDATA[Дата присоединения]]></string>
+    <string name="_bx_invites_grid_column_title_joined_account"><![CDATA[Присоединился]]></string>
+    <string name="_bx_invites_grid_column_title_status"><![CDATA[Статус]]></string>
+
+    <string name="_bx_invites_grid_action_title_adm_info"><![CDATA[Инфо]]></string>
+    <string name="_bx_invites_grid_action_title_adm_invite_info"><![CDATA[Информация о приглашении]]></string>
+    <string name="_bx_invites_grid_action_title_adm_invite"><![CDATA[Пригласить]]></string>
+    <string name="_bx_invites_grid_action_title_adm_delete"><![CDATA[Удалить]]></string>
+    <string name="_bx_invites_grid_action_title_adm_add"><![CDATA[Отправить приглашения]]></string>
+
+    <string name="_bx_invites_grid_invites_column_title_email"><![CDATA[Эл. адрес]]></string>
+    <string name="_bx_invites_grid_invites_column_title_date"><![CDATA[Дата]]></string>
+    <string name="_bx_invites_grid_invites_column_title_who_sent"><![CDATA[Кто отправил]]></string>
+    <string name="_bx_invites_grid_invites_column_title_multi"><![CDATA[Многоразовый]]></string>
+    <string name="_bx_invites_grid_invites_column_title_aj"><![CDATA[После присоединения]]></string>
+    <string name="_bx_invites_grid_invites_column_title_date_seen"><![CDATA[Дата отправки]]></string>
+    <string name="_bx_invites_grid_invites_column_title_joined_account"><![CDATA[Присоединившийся]]></string>
+    <string name="_bx_invites_grid_invites_column_title_date_joined"><![CDATA[Дата присоединения]]></string>
+    <string name="_bx_invites_grid_invites_column_title_request"><![CDATA[Запрос]]></string>
+    <string name="_bx_invites_grid_txt_account_manager"><![CDATA[К управлению аккаунтом]]></string>
+    <string name="_bx_invites_grid_txt_view_request"><![CDATA[Просмотреть запрос]]></string>
 
 
     <!-- Pages and Blocks -->
@@ -81,34 +85,34 @@
     <string name="_bx_invites_page_title_sys_invites"><![CDATA[Управление приглашениями]]></string>
 
   
-	<!-- Menus -->
-	<string name="_bx_invites_menu_item_title_system_admt_requests"><![CDATA[Запросы на приглашение]]></string>
-	<string name="_bx_invites_menu_item_title_admt_requests"><![CDATA[Приглашения]]></string>
-	<string name="_bx_invites_menu_item_title_requests"><![CDATA[Запросы]]></string>
-  <string name="_bx_invites_menu_dashboard_manage_tools_addon_counter1_caption"><![CDATA[в ожидании]]></string>
-  <string name="_bx_invites_menu_item_title_manage_requests"><![CDATA[Управление приглашениями]]></string>
-  <string name="_bx_invites_menu_item_title_manage_invites"><![CDATA[Управление запросами]]></string>
-
-
-	<!-- Options -->
-  <string name="_bx_invites_option_automatically_befriend"><![CDATA[Автоматическая дружба между приглашающим и приглашенным]]></string>
-	<string name="_bx_invites_option_key_lifetime"><![CDATA[Срок действия ключа приглашения (в днях)]]></string>
-	<string name="_bx_invites_option_enable_request_invite"><![CDATA[Разрешить запросы на приглашение]]></string>
-	<string name="_bx_invites_option_requests_email"><![CDATA[Эл. адреса для посылки запросов на приглашение (разделенение запятой)]]></string>
-	<string name="_bx_invites_option_enable_reg_by_inv"><![CDATA[Регистрация строго по приглашению]]></string>
-
-
-	<!-- ACL -->
-	<string name="_bx_invites_acl_action_invite"><![CDATA[Пригласить]]></string>
-	<string name="_bx_invites_acl_action_request"><![CDATA[Запросить приглашение]]></string>
-	<string name="_bx_invites_acl_action_delete_request"><![CDATA[Удалить запросы на приглашение]]></string>
-  <string name="_bx_invites_acl_action_delete_invite"><![CDATA[Удалить приглашение]]></string>
-
-
-	<!-- Email Templates -->
-	<string name="_bx_invites_et_invite_form_message"><![CDATA[Пригласительная форма - сообщение.]]></string>
-	<string name="_bx_invites_et_invite_form_message_subject"><![CDATA[Приглашение от {site_name}.]]></string>
-	<string name="_bx_invites_et_invite_form_message_body"><![CDATA[{email_header}
+    <!-- Menus -->
+    <string name="_bx_invites_menu_item_title_system_admt_requests"><![CDATA[Запросы на приглашение]]></string>
+    <string name="_bx_invites_menu_item_title_admt_requests"><![CDATA[Приглашения]]></string>
+    <string name="_bx_invites_menu_item_title_requests"><![CDATA[Запросы]]></string>
+    <string name="_bx_invites_menu_dashboard_manage_tools_addon_counter1_caption"><![CDATA[в ожидании]]></string>
+    <string name="_bx_invites_menu_item_title_manage_requests"><![CDATA[Управление приглашениями]]></string>
+    <string name="_bx_invites_menu_item_title_manage_invites"><![CDATA[Управление запросами]]></string>
+
+
+    <!-- Options -->
+    <string name="_bx_invites_option_automatically_befriend"><![CDATA[Автоматическая дружба между приглашающим и приглашенным]]></string>
+    <string name="_bx_invites_option_key_lifetime"><![CDATA[Срок действия ключа приглашения (в днях)]]></string>
+    <string name="_bx_invites_option_enable_request_invite"><![CDATA[Разрешить запросы на приглашение]]></string>
+    <string name="_bx_invites_option_requests_email"><![CDATA[Эл. адреса для посылки запросов на приглашение (разделенение запятой)]]></string>
+    <string name="_bx_invites_option_enable_reg_by_inv"><![CDATA[Регистрация строго по приглашению]]></string>
+
+
+    <!-- ACL -->
+    <string name="_bx_invites_acl_action_invite"><![CDATA[Пригласить]]></string>
+    <string name="_bx_invites_acl_action_request"><![CDATA[Запросить приглашение]]></string>
+    <string name="_bx_invites_acl_action_delete_request"><![CDATA[Удалить запросы на приглашение]]></string>
+    <string name="_bx_invites_acl_action_delete_invite"><![CDATA[Удалить приглашение]]></string>
+
+
+    <!-- Email Templates -->
+    <string name="_bx_invites_et_invite_form_message"><![CDATA[Пригласительная форма - сообщение.]]></string>
+    <string name="_bx_invites_et_invite_form_message_subject"><![CDATA[Приглашение от {site_name}.]]></string>
+    <string name="_bx_invites_et_invite_form_message_body"><![CDATA[{email_header}
 <p><b>Дорогой друг</b>,</p>
 <p>{profile_name} приглашает Вас зарегистрироваться в социальной сети <a href="{site_url}">{site_name}</a>.<br />Сообщение от {profile_name}:</p>
 <hr />
@@ -117,68 +121,73 @@
 <p>Нажмите ссылку ниже, чтобы зарегистрироваться: <a href="{join_url}">{join_url}</a></p>
 {email_footer}]]></string>
 
-	<string name="_bx_invites_et_invite_by_request_message"><![CDATA[Приглашение по запросу - сообщение.]]></string>
-	<string name="_bx_invites_et_invite_by_request_message_subject"><![CDATA[Приглашение от {site_name}.]]></string>
-	<string name="_bx_invites_et_invite_by_request_message_body"><![CDATA[{email_header}
+    <string name="_bx_invites_et_invite_by_request_message"><![CDATA[Приглашение по запросу - сообщение.]]></string>
+    <string name="_bx_invites_et_invite_by_request_message_subject"><![CDATA[Приглашение от {site_name}.]]></string>
+    <string name="_bx_invites_et_invite_by_request_message_body"><![CDATA[{email_header}
 <p><b>Дорогой друг</b>,</p>
 <p>Добро пожаловать на регистрацию в социальной сети <a href="{site_url}">{site_name}</a>.</p>
 <p>Нажмите ссылку ниже, чтобы зарегистрироваться: <a href="{join_url}">{join_url}</a></p>
 {email_footer}]]></string>
 
-	<string name="_bx_invites_et_request_form_message"><![CDATA[Форма запроса приглашения - сообщение.]]></string>
-	<string name="_bx_invites_et_request_form_message_subject"><![CDATA[Запросить приглашение.]]></string>
-	<string name="_bx_invites_et_request_form_message_body"><![CDATA[{email_header}
+    <string name="_bx_invites_et_request_form_message"><![CDATA[Форма запроса приглашения - сообщение.]]></string>
+    <string name="_bx_invites_et_request_form_message_subject"><![CDATA[Запросить приглашение.]]></string>
+    <string name="_bx_invites_et_request_form_message_body"><![CDATA[{email_header}
 <p><b>Дорогой администратор</b>,</p>
 <p>{sender_name} (<a href="mailto:{sender_email}">{sender_email}</a>; IP {sender_ip}) запросил приглашение для регистрации на сайте <b>{site_name}</b>.</p>
 <p><a href="{manage_url}">Нажмите сюда</a> для управление запросами.</p>
 {email_footer}]]></string>
 
 
-	<!-- Common Texts -->
-	<string name="_bx_invites_txt_link_popup_title"><![CDATA[Пригласительная ссылка]]></string>
-	<string name="_bx_invites_txt_invite_block_text"><![CDATA[Вы можете пригласить друзей для регистрации на сайте. У Вас осталось <b>{0}</b> приглашений.]]></string>
-	<string name="_bx_invites_txt_request_block_text"><![CDATA[Регистрация только по приглашению.]]></string>
-	<string name="_bx_invites_txt_unlimited"><![CDATA[неограниченное количество]]></string>
-
-	<string name="_bx_invites_btn_invite_email"><![CDATA[Пригласить по эл. адресу]]></string>
-	<string name="_bx_invites_btn_invite_link"><![CDATA[Пригласительная ссылка]]></string>
-	<string name="_bx_invites_btn_copy"><![CDATA[Скопировать]]></string>
-	<string name="_bx_invites_btn_request"><![CDATA[Запросить приглашение]]></string>
-	<string name="_bx_invites_msg_invitation"><![CDATA[Привет! Этот сайт может оказаться интересным для Вас.]]></string>
-	<string name="_bx_invites_msg_invitation_sent"><![CDATA[Сообщение с приглашением было поставлено в очередь для отправки по {0} эл. адресам из списка.]]></string>
-	<string name="_bx_invites_msg_request_sent"><![CDATA[Запрос на приглашение получен. Мы вышлем приглашение, когда придет ваша очередь.]]></string>
-	<string name="_bx_invites_err_cannot_perform"><![CDATA[Невозможно выполнить действие. Пожалуйста, оповестите нас об этой проблеме.]]></string>
-	<string name="_bx_invites_err_limit_reached"><![CDATA[Число посланных Вами приглашений достигло лимита.]]></string>
-	<string name="_bx_invites_err_not_available"><![CDATA[Эта функция сейчас недоступна. Пожалуйста, попытайтесь ещё раз позднее.]]></string>
-	<string name="_bx_invites_err_invite"><![CDATA[Невозможно послать приглашение по запросу.]]></string>
-  <string name="_bx_invites_err_delete_invite"><![CDATA[Невозможно удалить приглашение.]]></string>
-	<string name="_bx_invites_err_delete_request"><![CDATA[Невозможно удалить запрос.]]></string>
-	<string name="_bx_invites_err_used"><![CDATA[Приглашение не доступно или уже использовано.]]></string>
-	<string name="_bx_invites_err_already_send"><![CDATA[Приглашение уже было отправлено на этот эл. адрес]]></string>
-	<string name="_bx_invites_err_already_registed"><![CDATA[Пользователь с таким  эл. адресом уже зарегистрирован. Пожалуйста, воспользуйтесь <a href="{0}">восстановлением пароля</a> чтобы получить доступ к аккаунту.]]></string>
-	<string name="_bx_invites_request_status_new"><![CDATA[Новый]]></string>
-	<string name="_bx_invites_request_status_invited"><![CDATA[Приглашен]]></string>
-	<string name="_bx_invites_request_status_seen"><![CDATA[Просмотрено]]></string>
-	<string name="_bx_invites_request_status_joined"><![CDATA[Присоединился]]></string>
-	<string name="_bx_invites_request_status_for_filter_all"><![CDATA[Все запросы]]></string>
-	<string name="_bx_invites_request_status_for_filter_new"><![CDATA[Новые запросы]]></string>
-	<string name="_bx_invites_request_status_for_filter_invited"><![CDATA[Запросы с приглашениями]]></string>
-	<string name="_bx_invites_request_status_for_filter_seen"><![CDATA[Приглашение просмотрено]]></string>
-	<string name="_bx_invites_request_status_for_filter_joined"><![CDATA[Присоединился]]></string>
-
-  <string name="_bx_invites_invites_status_for_filter_all"><![CDATA[Все приглашения]]></string>
-  <string name="_bx_invites_invites_status_for_filter_accepted"><![CDATA[Принятые приглашения]]></string>
-  <string name="_bx_invites_invites_status_for_filter_not_accepted"><![CDATA[Не принятые приглашения]]></string>
-
-  <string name="_bx_invites_title_date_invite_sent"><![CDATA[Дата отправки]]></string>
-	<string name="_bx_invites_title_date_invite_seen"><![CDATA[Дата просмотра]]></string>
-
-  <string name="_bx_invites_reports_for_analytics_invited_total"><![CDATA[Приглашенные - Общее количество]]></string>
-  <string name="_bx_invites_reports_for_analytics_invited_speed_grows"><![CDATA[Приглашенные - Динамика роста]]></string>
-  <string name="_bx_invites_reports_for_analytics_invitation_total"><![CDATA[Приглашения - Общее количество]]></string>
-  <string name="_bx_invites_reports_for_analytics_invitation_speed_grows"><![CDATA[Приглашения - Динамика роста]]></string>
-
-
-  <string name="_bx_invites_alert_action_request"><![CDATA[<b class="bx-ntfs-content-profile">{entry_sample}</b> запросил приглашение - <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
-  <string name="_bx_invites_alert_action_request_notify_personal"><![CDATA[Новые запросы]]></string>
+    <!-- Common Texts -->
+    <string name="_bx_invites_txt_code_popup_title"><![CDATA[Пригласительный код]]></string>
+    <string name="_bx_invites_txt_link_popup_title"><![CDATA[Пригласительная ссылка]]></string>
+    <string name="_bx_invites_txt_invite_block_text"><![CDATA[Вы можете пригласить друзей для регистрации на сайте. У Вас осталось <b>{0}</b> приглашений.]]></string>
+    <string name="_bx_invites_txt_request_block_text"><![CDATA[Регистрация только по приглашению.]]></string>
+    <string name="_bx_invites_txt_unlimited"><![CDATA[неограниченное количество]]></string>
+
+    <string name="_bx_invites_btn_invite_code"><![CDATA[Пригласить по коду]]></string>
+    <string name="_bx_invites_btn_invite_email"><![CDATA[Пригласить по эл. адресу]]></string>
+    <string name="_bx_invites_btn_invite_link"><![CDATA[Пригласительная ссылка]]></string>
+    <string name="_bx_invites_btn_copy"><![CDATA[Скопировать]]></string>
+    <string name="_bx_invites_btn_copy_as_link"><![CDATA[Скопировать как ссылку]]></string>
+    <string name="_bx_invites_btn_request"><![CDATA[Запросить приглашение]]></string>
+    <string name="_bx_invites_msg_invitation"><![CDATA[Привет! Этот сайт может оказаться интересным для Вас.]]></string>
+    <string name="_bx_invites_msg_invitation_sent"><![CDATA[Сообщение с приглашением было поставлено в очередь для отправки по {0} эл. адресам из списка.]]></string>
+    <string name="_bx_invites_msg_request_sent"><![CDATA[Запрос на приглашение получен. Мы вышлем приглашение, когда придет ваша очередь.]]></string>
+    <string name="_bx_invites_err_cannot_perform"><![CDATA[Невозможно выполнить действие. Пожалуйста, оповестите нас об этой проблеме.]]></string>
+    <string name="_bx_invites_err_limit_reached"><![CDATA[Число посланных Вами приглашений достигло лимита.]]></string>
+    <string name="_bx_invites_err_not_available"><![CDATA[Эта функция сейчас недоступна. Пожалуйста, попытайтесь ещё раз позднее.]]></string>
+    <string name="_bx_invites_err_invite"><![CDATA[Невозможно послать приглашение по запросу.]]></string>
+    <string name="_bx_invites_err_delete_invite"><![CDATA[Невозможно удалить приглашение.]]></string>
+    <string name="_bx_invites_err_delete_request"><![CDATA[Невозможно удалить запрос.]]></string>
+    <string name="_bx_invites_err_wrong_email"><![CDATA[Можно использовать только эл. адрес, указанный в приглашении.]]></string>
+    <string name="_bx_invites_err_used"><![CDATA[Приглашение не доступно или уже использовано.]]></string>
+    <string name="_bx_invites_err_already_send"><![CDATA[Приглашение уже было отправлено на этот эл. адрес]]></string>
+    <string name="_bx_invites_err_already_registed"><![CDATA[Пользователь с таким  эл. адресом уже зарегистрирован. Пожалуйста, воспользуйтесь <a href="{0}">восстановлением пароля</a> чтобы получить доступ к аккаунту.]]></string>
+    <string name="_bx_invites_request_status_new"><![CDATA[Новый]]></string>
+    <string name="_bx_invites_request_status_invited"><![CDATA[Приглашен]]></string>
+    <string name="_bx_invites_request_status_seen"><![CDATA[Просмотрено]]></string>
+    <string name="_bx_invites_request_status_joined"><![CDATA[Присоединился]]></string>
+    <string name="_bx_invites_request_status_for_filter_all"><![CDATA[Все запросы]]></string>
+    <string name="_bx_invites_request_status_for_filter_new"><![CDATA[Новые запросы]]></string>
+    <string name="_bx_invites_request_status_for_filter_invited"><![CDATA[Запросы с приглашениями]]></string>
+    <string name="_bx_invites_request_status_for_filter_seen"><![CDATA[Приглашение просмотрено]]></string>
+    <string name="_bx_invites_request_status_for_filter_joined"><![CDATA[Присоединился]]></string>
+
+    <string name="_bx_invites_invites_status_for_filter_all"><![CDATA[Все приглашения]]></string>
+    <string name="_bx_invites_invites_status_for_filter_accepted"><![CDATA[Принятые приглашения]]></string>
+    <string name="_bx_invites_invites_status_for_filter_not_accepted"><![CDATA[Не принятые приглашения]]></string>
+
+    <string name="_bx_invites_title_date_invite_sent"><![CDATA[Дата отправки]]></string>
+    <string name="_bx_invites_title_date_invite_seen"><![CDATA[Дата просмотра]]></string>
+    <string name="_bx_invites_txt_email_use"><![CDATA[Обязательное использование во время присоединения.]]></string>
+
+    <string name="_bx_invites_reports_for_analytics_invited_total"><![CDATA[Приглашенные - Общее количество]]></string>
+    <string name="_bx_invites_reports_for_analytics_invited_speed_grows"><![CDATA[Приглашенные - Динамика роста]]></string>
+    <string name="_bx_invites_reports_for_analytics_invitation_total"><![CDATA[Приглашения - Общее количество]]></string>
+    <string name="_bx_invites_reports_for_analytics_invitation_speed_grows"><![CDATA[Приглашения - Динамика роста]]></string>
+
+
+    <string name="_bx_invites_alert_action_request"><![CDATA[<b class="bx-ntfs-content-profile">{entry_sample}</b> запросил приглашение - <b class="bx-ntfs-content-entry">{entry_caption}</b>]]></string>
+    <string name="_bx_invites_alert_action_request_notify_personal"><![CDATA[Новые запросы]]></string>
 </resources>