RomanL 8 سال پیش
والد
کامیت
64215eb32b

+ 3 - 0
modules/boonex/invites/classes/BxInvConfig.php

@@ -31,6 +31,9 @@ class BxInvConfig extends BxBaseModGeneralConfig
         	'URL_INVITE' => 'page.php?i=invites-invite',
         	'URL_REQUEST' => 'page.php?i=invites-request',
         	'URL_REQUESTS' => 'page.php?i=invites-requests',
+            
+            'TABLE_REQUESTS' => $aModule['db_prefix'] . 'requests',
+            'TABLE_INVITES' => $aModule['db_prefix'] . 'invites',
         );
 
 		$this->_aObjects = array(

+ 47 - 6
modules/boonex/invites/classes/BxInvDb.php

@@ -24,9 +24,9 @@ class BxInvDb extends BxDolModuleDb
         parent::__construct($oConfig);
 
         $this->_oConfig = $oConfig;
-
-        $this->_sTableInvites = $this->_sPrefix . 'invites';
-        $this->_sTableRequests = $this->_sPrefix . 'requests';
+        $CNF = $oConfig->CNF;
+        $this->_sTableInvites = $CNF['TABLE_INVITES'];
+        $this->_sTableRequests = $CNF['TABLE_REQUESTS'];
     }
 
 	public function getInvites($aParams, $bReturnCount = false)
@@ -68,13 +68,54 @@ class BxInvDb extends BxDolModuleDb
         $sSql = "DELETE FROM `{$this->_sTableInvites}` WHERE " . $this->arrayToSQL($aParams, " AND ");
         return $this->query($sSql);
     }
+    
+    public function attachInviteToRequest($iReqestId, $iInviteId)
+    {
+        $aBindings = array(
+            'id' => $iReqestId,
+            'invite_id' => $iInviteId
+        );
+        $this->query("UPDATE `{$this->_sTableRequests}` SET invite_id=:invite_id WHERE id=:id", $aBindings);
+    }
+    
+    public function attachAccountIdToInvite($iAccountId, $sKey)
+    {
+        $aBindings = array(
+            '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);
+    }
+    
+    public function updateDateSeenForInvite($sKey)
+    {
+        $aBindings = array(
+            'date_seen' => time(),
+            'keyvalue' => $sKey
+        );
+        $this->query("UPDATE `{$this->_sTableInvites}` SET `date_seen`=:date_seen WHERE `key`=:keyvalue", $aBindings);
+    }
+    
+    public function insertInvite($iAccountId, $iProfileId, $sKey, $sEmail, $iDate) 
+    {
+        $aBindings = array(
+			'account_id' => $iAccountId,
+			'profile_id' => $iProfileId,
+			'keyvalue' => $sKey,
+			'email' => $sEmail,
+			'date' => $iDate
+		);
+        $this->query("INSERT `{$this->_sTableInvites}` (account_id, profile_id, `key`, email, date) VALUES (:account_id, :profile_id, :keyvalue, :email, :date)", $aBindings);  
+        return (int)$this->lastId();
+    }
 
 	public function getRequests($aParams, $bReturnCount = false)
     {
     	$aMethod = array('name' => 'getAll', 'params' => array(0 => 'query'));
-        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
-
-        $sSelectClause = "`{$this->_sTableRequests}`.*";
+        $sSelectClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+        $sJoinClause = " LEFT JOIN `{$this->_sTableInvites}` ON `bx_inv_invites`.`id` = `bx_inv_requests`.`invite_id` ";
+        $sSelectClause = "`{$this->_sTableRequests}`.*, `{$this->_sTableInvites}`.`date_seen`, `{$this->_sTableInvites}`.`date_joined`, `{$this->_sTableInvites}`.`joined_account_id` AS joined_account, `{$this->_sTableInvites}`.`date` AS `date_invite` ";
 
         switch($aParams['type']) {
         	case 'by_id':

+ 200 - 7
modules/boonex/invites/classes/BxInvGridRequests.php

@@ -9,18 +9,102 @@
  * @{
  */
 
+define('BX_INV_FILTER_STATUS_NEW', 'new');
+define('BX_INV_FILTER_STATUS_INVITED', 'invited');
+define('BX_INV_FILTER_STATUS_SEEN', 'seen');
+define('BX_INV_FILTER_STATUS_JOINED', 'joined');
+
 class BxInvGridRequests extends BxTemplGrid
 {
 	protected $_sModule;
 	protected $_oModule;
 
+    protected $_sFilter1Name;
+	protected $_sFilter1Value;
+	protected $_aFilter1Values;
+    protected $_sParamsDivider;
+    
     public function __construct ($aOptions, $oTemplate = false)
     {
         parent::__construct ($aOptions, $oTemplate);
 
 		$this->_sModule = 'bx_invites';
 		$this->_oModule = BxDolModule::getInstance($this->_sModule);
+        
+        $this->_sFilter1Name = 'filter1';
+        $this->_aFilter1Values = array(
+            '' => _t('_bx_invites_request_status_for_filter_all'),
+        	BX_INV_FILTER_STATUS_NEW => _t('_bx_invites_request_status_for_filter_new'),
+            BX_INV_FILTER_STATUS_INVITED => _t('_bx_invites_request_status_for_filter_invited'),
+            BX_INV_FILTER_STATUS_SEEN => _t('_bx_invites_request_status_for_filter_seen'),
+            BX_INV_FILTER_STATUS_JOINED => _t('_bx_invites_request_status_for_filter_joined')
+		);
+        
+        $sFilter1 = bx_get($this->_sFilter1Name);
+        if(!empty($sFilter1)) {
+            $this->_sFilter1Value = bx_process_input($sFilter1);
+            $this->_aQueryAppend['filter1'] = $this->_sFilter1Value;
+        }
+        $this->_sParamsDivider = '#-#';
+    }
+    
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        $CNF = $this->_oModule->_oConfig->CNF;
+        $sTableRequests = $CNF['TABLE_REQUESTS'];
+        $sTableInvites = $CNF['TABLE_INVITES'];
+        
+		if(strpos($sFilter, $this->_sParamsDivider) !== false)
+            list($this->_sFilter1Value, $sFilter) = explode($this->_sParamsDivider, $sFilter);
+       
+        $sFilterSql = "";
+    	if(!empty($this->_sFilter1Value)){
+            switch ($this->_sFilter1Value) {
+                case BX_INV_FILTER_STATUS_NEW:
+                    $sFilterSql = " AND " . $sTableRequests . ".invite_id IS NULL ";
+                    break;
+                case BX_INV_FILTER_STATUS_INVITED:
+                    $sFilterSql = " AND " . $sTableRequests . ".invite_id IS NOT NULL AND " . $sTableInvites . ".date_seen IS  NULL AND " . $sTableInvites . ".joined_account_id IS NULL ";
+                    break;
+                case BX_INV_FILTER_STATUS_SEEN:
+                    $sFilterSql = " AND " . $sTableInvites . ".date_seen IS NOT NULL AND " . $sTableInvites . ".joined_account_id IS NULL";
+                    break;
+                case BX_INV_FILTER_STATUS_JOINED:
+                    $sFilterSql = " AND " . $sTableInvites . ".joined_account_id IS NOT NULL ";
+                    break;
+            }
+        }
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString($sFilterSql);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
     }
+    
+    public function performActionAdd()
+    {
+        $sAction = 'add';
+        $oForm = $this->_oModule->getFormObjectInvite();
+        if (!$oForm)
+            return '';
+        $oForm->aInputs['text']['value'] = _t('_bx_invites_msg_invitation');
+        $oForm->aFormAttrs['action'] = BX_DOL_URL_ROOT . 'grid.php?' . bx_encode_url_params($_GET, array('ids', '_r'));
+        $oForm->initChecker();
+        
+        if($oForm->isSubmittedAndValid()) {
+            $sResult = $this->_oModule->processFormObjectInvite($oForm);
+            $aRes = array('msg' => $sResult);
+            echoJson($aRes);
+        }
+        else {
+            $sContent = BxTemplStudioFunctions::getInstance()->popupBox('_bx_invites_form_invite', _t('_bx_invites_form_invite'), $this->_oModule->_oTemplate->parseHtmlByName('popup_invite.html', array(
+                'form_id' => $oForm->id,
+                'form' => $oForm->getCode(true),
+                'object' => $this->_sObject,
+                'action' => $sAction
+            )));
+            echoJson(array('popup' => array('html' => $sContent, 'options' => array('closeOnOuterClick' => true))));
+        }
+    }
+    
     public function performActionInfo()
     {
     	$aIds = bx_get('ids');
@@ -39,6 +123,7 @@ class BxInvGridRequests extends BxTemplGrid
 
 		echoJson(array('popup' => array('html' => $sContent)));
     }
+    
 	public function performActionInvite($aParams = array())
     {
     	$iProfileId = $this->_oModule->getProfileId();
@@ -58,28 +143,27 @@ class BxInvGridRequests extends BxTemplGrid
 
         $sText = _t('_bx_invites_msg_invitation');
 
-        $oForm = BxDolForm::getObjectInstance($this->_oModule->_oConfig->getObject('form_request'), $this->_oModule->_oConfig->getObject('form_display_request_send'));
-
         $aIdsAffected = array ();
         foreach($aIds as $iId) {
 			$aRequest = $this->_oModule->_oDb->getRequests(array('type' => 'by_id', 'value' => $iId));
 			if(empty($aRequest) || !is_array($aRequest))
 				continue;
-
+            
+            $iInviteId = -1;
         	$mixedResult = $this->_oModule->invite(BX_INV_TYPE_FROM_SYSTEM, $aRequest['email'], $sText);
         	if($mixedResult === false)
         		continue;
-
+            else
+                $iInviteId = (int)$mixedResult[0];
 			$this->_oModule->isAllowedInvite($iProfileId, true);
-
-			$oForm->delete($iId);
-
+			$this->_oModule->_oDb->attachInviteToRequest($iId, $iInviteId);
             $aIdsAffected[] = $iId;
             $iAffected++;
         }
 
         echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected, 'msg' => _t('_bx_invites_msg_invitation_sent', $iAffected)) : array('msg' => _t('_bx_invites_err_invite')));
     }
+    
 	public function performActionDelete($aParams = array())
     {
     	$iProfileId = $this->_oModule->getProfileId();
@@ -112,6 +196,56 @@ class BxInvGridRequests extends BxTemplGrid
 
         echoJson($iAffected ? array('grid' => $this->getCode(false), 'blink' => $aIdsAffected) : array('msg' => _t('_bx_invites_err_delete_request')));
     }
+    
+    protected function _getFilterControls ()
+    {
+        parent::_getFilterControls();
+        return  $this->_getFilterSelectOne($this->_sFilter1Name, $this->_sFilter1Value, $this->_aFilter1Values) . $this->_getSearchInput();
+    }
+    
+    protected function _getSearchInput()
+    {
+        $sJsObject = $this->_oModule->_oConfig->getJsObject('main');
+        $aInputSearch = array(
+            'type' => 'text',
+            'name' => 'search',
+            'attrs' => array(
+                'id' => 'bx-grid-search-' . $this->_sObject,
+                'onKeyup' => 'javascript:$(this).off(\'keyup focusout\'); ' . $sJsObject . '.onChangeFilter(this)',
+                'onBlur' => 'javascript:' . $sJsObject . '.onChangeFilter(this)',
+            )
+        );
+
+        $oForm = new BxTemplFormView(array());
+        return $oForm->genRow($aInputSearch);
+    }
+
+    
+    protected function _getFilterSelectOne($sFilterName, $sFilterValue, $aFilterValues)
+    {
+        if(empty($sFilterName) || empty($aFilterValues))
+            return '';
+
+		$CNF = &$this->_oModule->_oConfig->CNF;
+		$sJsObject = $this->_oModule->_oConfig->getJsObject('main');
+
+		foreach($aFilterValues as $sKey => $sValue)
+			$aFilterValues[$sKey] = _t($sValue);
+
+        $aInputModules = array(
+            'type' => 'select',
+            'name' => $sFilterName,
+            'attrs' => array(
+                'id' => 'bx-grid-' . $sFilterName . '-' . $this->_sObject,
+                'onChange' => 'javascript:' . $sJsObject . '.onChangeFilter(this)'
+            ),
+            'value' => $sFilterValue,
+            'values' => $aFilterValues
+        );
+
+        $oForm = new BxTemplFormView(array());
+        return $oForm->genRow($aInputModules);
+    }
 
 	protected function _getCellNip($mixedValue, $sKey, $aField, $aRow)
     {
@@ -122,6 +256,65 @@ class BxInvGridRequests extends BxTemplGrid
     {
         return parent::_getCellDefault(bx_time_js($mixedValue), $sKey, $aField, $aRow);
     }
+    
+    protected function _getCellStatus($mixedValue, $sKey, $aField, $aRow)
+    {
+        $sStatus = _t('_bx_invites_request_status_new');
+        if($aRow["invite_id"] != "")
+            $sStatus = _t('_bx_invites_request_status_invited');
+        if($aRow["date_seen"] != "")
+            $sStatus = _t('_bx_invites_request_status_seen');
+        if($aRow["joined_account"] != "")
+            $sStatus = _t('_bx_invites_request_status_joined');
+        return parent::_getCellDefault($sStatus, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellDateSeen($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->getDateValueOrEmpty($mixedValue), $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellDateJoined($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->getDateValueOrEmpty($mixedValue), $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellJoinedAccount($mixedValue, $sKey, $aField, $aRow)
+    {
+        $sAccountInfo = "";
+        if ($mixedValue != 'undefined') {
+            $iAccountId = (int)$mixedValue;
+            $oJoinedProfile = BxDolProfile::getInstanceByAccount($iAccountId);
+            if ($oJoinedProfile->getModule() != 'system') {
+                $sAccountInfo = $this->_oModule->_oTemplate->parseHtmlByName('member_link.html', array(
+                    'href' => $oJoinedProfile->getUrl(),
+                    'content' => $oJoinedProfile->getDisplayName()
+        	        )
+                );
+            }
+            else {
+                $sAccountInfo = BxDolAccount::getInstance($iAccountId)->getDisplayName();
+            }
+        }
+        return parent::_getCellDefault($sAccountInfo, $sKey, $aField, $aRow);
+    }
+    
+    protected function _getCellDateInvite($mixedValue, $sKey, $aField, $aRow)
+    {
+        return parent::_getCellDefault($this->getDateValueOrEmpty($mixedValue), $sKey, $aField, $aRow);
+    }
+    
+    protected function _getActionInvite($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(isset($aRow["invite_id"]) && $aRow["invite_id"] != "")
+            return '';
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+    
+    private function getDateValueOrEmpty($sValue)
+    {
+        return $sValue != 'undefined' ? bx_time_js($sValue) : '';
+    }
 }
 
 /** @} */

+ 67 - 47
modules/boonex/invites/classes/BxInvModule.php

@@ -63,6 +63,13 @@ class BxInvModule extends BxDolModule
         	$this->getJoinLink($sKey)
         )));
     }
+    
+    public function actionSetSeenMark($Code)
+    {
+        header('Content-Type: image/png');
+        if (isset($Code) && trim($Code) != "")
+            $this->_oDb->updateDateSeenForInvite($Code);
+    }
 
     /**
      * SERVICE METHODS
@@ -144,40 +151,14 @@ class BxInvModule extends BxDolModule
      */
     public function serviceGetBlockFormInvite()
     {
-    	$iProfileId = $this->getProfileId();
-		$iAccountId = $this->getAccountId($iProfileId);
-
-        $mixedAllowed = $this->isAllowedInvite($iProfileId);
-        if($mixedAllowed !== true)
-            return array(
-                'content' => MsgBox($mixedAllowed)
-            );
-
-		$mixedInvites = false;
-		if(!isAdmin($iAccountId)) {
-			$iInvited = (int)$this->_oDb->getInvites(array('type' => 'count_by_account', 'value' => $iAccountId));
-			$mixedInvites = $this->_oConfig->getCountPerUser() - $iInvited;
-			if($mixedInvites <= 0)
-				return array(
-					'content' => MsgBox(_t('_bx_invites_err_limit_reached'))
-				);
-		}
-
         $oForm = $this->getFormObjectInvite();
         $oForm->aInputs['text']['value'] = _t('_bx_invites_msg_invitation');
 
         $sResult = '';
         $oForm->initChecker();
         if($oForm->isSubmittedAndValid()) {
-        	$sEmails = bx_process_input($oForm->getCleanValue('emails'));
-        	$sText = bx_process_pass($oForm->getCleanValue('text'));
-
-        	$mixedResult = $this->invite(BX_INV_TYPE_FROM_MEMBER, $sEmails, $sText, $mixedInvites, $oForm);
-        	if($mixedResult !== false)
-        		$sResult = _t('_bx_invites_msg_invitation_sent', (int)$mixedResult);
-        	else
-				$sResult = _t('_bx_invites_err_not_available');
-
+        	
+            $sResult = $this->processFormObjectInvite($oForm);
         	$sResult = MsgBox($sResult);
         }
 
@@ -235,12 +216,15 @@ class BxInvModule extends BxDolModule
      */
     public function serviceGetBlockManageRequests()
     {
+        $this->_oTemplate->addJs('jquery.form.min.js');
+        $this->_oTemplate->addJs('main.js');
         $oGrid = BxDolGrid::getObjectInstance($this->_oConfig->getObject('grid_requests'));
         if(!$oGrid)
             return '';
 
 		$this->_oTemplate->addCss(array('main.css'));
-		return $oGrid->getCode();
+        $this->_oTemplate->addJsTranslation(array('_sys_grid_search'));
+		return  $this->_oTemplate->getJsCode('main') . $oGrid->getCode();
     }
 
     /**
@@ -340,10 +324,10 @@ class BxInvModule extends BxDolModule
 			'text' => $sText
 		), $iAccountId, $iProfileId);
 
-		$iSent = 0;
+		$aAccountIds = array();
 		$iDate = time();
 		$aEmails = preg_split("/[\s\n,;]+/", $sEmails);
-		if(is_array($aEmails) && !empty($aEmails))
+		if(is_array($aEmails) && !empty($aEmails)){
 			foreach($aEmails as $sEmail) {
 				if($mixedLimit !== false && (int)$mixedLimit <= 0)
 					break;
@@ -353,25 +337,51 @@ class BxInvModule extends BxDolModule
 					continue;
 
 				$sKey = $oKeys->getNewKey(false, $iKeyLifetime);
-				if(sendMail($sEmail, $aMessage['Subject'], $aMessage['Body'], 0, array('join_url' => $this->getJoinLink($sKey)), BX_EMAIL_SYSTEM)) {
-					$oForm->insert(array(
-						'account_id' => $iAccountId,
-						'profile_id' => $iProfileId,
-						'key' => $sKey,
-						'email' => $sEmail,
-						'date' => $iDate
-					));
-
-					$this->onInvite($iAccountId, $iProfileId);
-
-					$iSent += 1;
-					if($mixedLimit !== false) 
+				if(sendMail($sEmail, $aMessage['Subject'], $aMessage['Body'], 0, array('join_url' => $this->getJoinLink($sKey), 'seen_image_url' => $this->getSeenImageUrl($sKey)), BX_EMAIL_SYSTEM)) {
+					$iInviteId = (int)$this->_oDb->insertInvite($iAccountId, $iProfileId, $sKey, $sEmail, $iDate);
+                    array_push($aAccountIds, $iInviteId);
+					
+                    $this->onInvite($iAccountId, $iProfileId);
+					
+                    if($mixedLimit !== false) 
 						$mixedLimit -= 1;					
 				}
 			}
-
-		return $iSent;
+        }
+		return $aAccountIds;
 	}
+    
+    public function processFormObjectInvite($oForm)
+    {
+        $iProfileId = $this->getProfileId();
+		$iAccountId = $this->getAccountId($iProfileId);
+
+        $mixedAllowed = $this->isAllowedInvite($iProfileId);
+        if($mixedAllowed !== true)
+            return array(
+                'content' => MsgBox($mixedAllowed)
+            );
+
+		$mixedInvites = false;
+		if(!isAdmin($iAccountId)) {
+			$iInvited = (int)$this->_oDb->getInvites(array('type' => 'count_by_account', 'value' => $iAccountId));
+			$mixedInvites = $this->_oConfig->getCountPerUser() - $iInvited;
+			if($mixedInvites <= 0)
+				return array(
+					'content' => MsgBox(_t('_bx_invites_err_limit_reached'))
+				);
+		}
+        
+        $sEmails = bx_process_input($oForm->getCleanValue('emails'));
+        $sText = bx_process_pass($oForm->getCleanValue('text'));
+        $mixedResult = $this->invite(BX_INV_TYPE_FROM_MEMBER, $sEmails, $sText, $mixedInvites, $oForm);
+        if($mixedResult !== false)
+            $sResult = _t('_bx_invites_msg_invitation_sent', count($mixedResult));
+        else
+            $sResult = _t('_bx_invites_err_not_available');
+        
+        return  $sResult;
+    }
 
 	public function isAllowedInvite($iProfileId, $bPerform = false)
     {
@@ -432,7 +442,7 @@ class BxInvModule extends BxDolModule
         //--- Event -> Request for Alerts Engine ---//
     }
 
-    protected function getFormObjectInvite($sDisplay = '')
+    public function getFormObjectInvite($sDisplay = '')
     {
     	if(empty($sDisplay))
     		$sDisplay = $this->_oConfig->getObject('form_display_invite_send');
@@ -448,6 +458,16 @@ class BxInvModule extends BxDolModule
 		$sJoinUrl = BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=create-account');
 		return bx_append_url_params($sJoinUrl, array($sKeyCode => $sKey));
 	}
+    
+    protected function getSeenImageUrl($sKey)
+	{
+        return  BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'SetSeenMark/' . $sKey . "/";
+	}
+    
+    public function attachAccountIdToInvite($iAccountId, $sKey)
+    {
+        $this->_oDb->attachAccountIdToInvite($iAccountId, $sKey);
+    }
 }
 
 /** @} */

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

@@ -49,10 +49,10 @@ class BxInvResponse extends BxDolAlertsResponse
     		return;
 
     	$sKeyCode = $this->_oModule->_oConfig->getKeyCode();
-
     	$sKey = BxDolSession::getInstance()->getUnsetValue($sKeyCode);
     	if($sKey === false)
     		return;
+        $this->_oModule->attachAccountIdToInvite($oAlert->iObject, $sKey);
 
 		$oKeys = BxDolKey::getInstance();
     	if($oKeys && $oKeys->isKeyExists($sKey))

+ 23 - 1
modules/boonex/invites/classes/BxInvTemplate.php

@@ -41,6 +41,27 @@ class BxInvTemplate extends BxBaseModGeneralTemplate
     	return $this->parseHtmlByName('request_text.html', array(
 			'style_prefix' => $this->_oConfig->getPrefix('style'),
 			'text' => bx_process_output(nl2br($aRequest['text']), BX_DATA_TEXT_MULTILINE),
+            'bx_if:show_date_invite' => array(
+    			'condition' => $aRequest['date_invite'] != '',
+    			'content' => array(
+    				'title' => _t('_bx_invites_grid_column_title_date_invite'),
+                    'value' => bx_time_js($aRequest['date_invite'], BX_FORMAT_DATE_TIME, true)
+    			)
+    		),
+            'bx_if:show_date_seen' => array(
+    			'condition' => $aRequest['date_seen'] != '',
+    			'content' => array(
+    				'title' => _t('_bx_invites_grid_column_title_date_seen'),
+                    'value' => bx_time_js($aRequest['date_seen'], BX_FORMAT_DATE_TIME, true)
+    			)
+    		),
+            'bx_if:show_date_joined' => array(
+    			'condition' => $aRequest['date_joined'] != '',
+    			'content' => array(
+    				'title' => _t('_bx_invites_grid_column_title_date_joined'),
+                    'value' => bx_time_js($aRequest['date_joined'], BX_FORMAT_DATE_TIME, true)
+    			)
+    		)
 		));
     }
 
@@ -161,7 +182,8 @@ class BxInvTemplate extends BxBaseModGeneralTemplate
 	public function getJsCode($sType, $aParams = array(), $bWrap = true)
     {
         $aParams = array_merge(array(
-            'aHtmlIds' => $this->_oConfig->getHtmlIds()
+            'aHtmlIds' => $this->_oConfig->getHtmlIds(),
+            'sObjNameGrid' => $this->_oConfig->getObject('grid_requests'),
         ), $aParams);
 
         return parent::getJsCode($sType, $aParams, $bWrap);

+ 20 - 2
modules/boonex/invites/install/langs/en.xml

@@ -37,12 +37,19 @@
 	<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"><![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>
 
 
-	<!-- Pages and Blocks -->
+  <!-- Pages and Blocks -->
 	<string name="_bx_invites_page_title_sys_invite"><![CDATA[Invite]]></string>
 	<string name="_bx_invites_page_title_invite"><![CDATA[Invite]]></string>
 	<string name="_bx_invites_page_block_title_invite_form"><![CDATA[Invite]]></string>
@@ -92,10 +99,12 @@
 
 	<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}
+	<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>
 <p>Click the following link to join: <a href="{join_url}">{join_url}</a></p>
+<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>
@@ -126,4 +135,13 @@
 	<string name="_bx_invites_err_invite"><![CDATA[Cannot send an invitation on request.]]></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_request_status_new"><![CDATA[New]]></string>
+  <string name="_bx_invites_request_status_invited"><![CDATA[Invited]]></string>
+  <string name="_bx_invites_request_status_seen"><![CDATA[Joined]]></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>
 </resources>

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

@@ -9,7 +9,11 @@ CREATE TABLE IF NOT EXISTS `bx_inv_invites` (
   `key` varchar(128) NOT NULL,
   `email` varchar(128) NOT NULL,
   `date` int(11) NOT NULL default '0',
+   `date_seen` int(11) DEFAULT NULL,
+   `date_joined` int(11) DEFAULT NULL,
+   `joined_account_id` int(11) DEFAULT NULL,
   PRIMARY KEY  (`id`)
+
 );
 
 CREATE TABLE IF NOT EXISTS `bx_inv_requests` (
@@ -19,7 +23,9 @@ CREATE TABLE IF NOT EXISTS `bx_inv_requests` (
   `text` text NOT NULL,
   `nip` int(11) unsigned NOT NULL default '0',
   `date` int(11) NOT NULL default '0',
-  PRIMARY KEY  (`id`)
+  `invite_id` int(11) DEFAULT NULL,
+  PRIMARY KEY  (`id`),
+  INDEX `bx_inv_requests_invite_id` (`invite_id`)
 );
 
 
@@ -62,22 +68,28 @@ INSERT INTO `sys_form_display_inputs` (`display_name`, `input_name`, `visible_fo
 
 -- 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 * FROM `bx_inv_requests` WHERE 1 ', 'bx_inv_requests', 'id', '', '', '', 20, NULL, 'start', '', 'name,email', '', 'like', '', '', 192, 'BxInvGridRequests', 'modules/boonex/invites/classes/BxInvGridRequests.php');
+('bx_invites_requests', 'Sql', 'SELECT `bx_inv_requests`.*, `bx_inv_invites`.`date_seen`, `bx_inv_invites`.`date_joined`, `bx_inv_invites`.`joined_account_id` AS joined_account, `bx_inv_invites`.`date` AS `date_invite` FROM `bx_inv_requests` LEFT JOIN `bx_inv_invites` ON `bx_inv_invites`.`id` = `bx_inv_requests`.`invite_id` WHERE 1', 'bx_inv_requests', 'id', 'invite_id', '', '', 20, NULL, 'start', '', 'bx_inv_requests`.`name, bx_inv_requests`.`email', '', 'like', '', '', 192, 'BxInvGridRequests', 'modules/boonex/invites/classes/BxInvGridRequests.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),
-('bx_invites_requests', 'name', '_bx_invites_grid_column_title_name', '20%', 0, '', '', 2),
-('bx_invites_requests', 'email', '_bx_invites_grid_column_title_email', '20%', 1, '25', '', 3),
-('bx_invites_requests', 'nip', '_bx_invites_grid_column_title_nip', '15%', 0, '15', '', 4),
-('bx_invites_requests', 'date', '_bx_invites_grid_column_title_date', '20%', 0, '20', '', 5),
-('bx_invites_requests', 'actions', '', '23%', 0, '', '', 6);
+('bx_invites_requests', 'name', '_bx_invites_grid_column_title_name', '14%', 0, '', '', 2),
+('bx_invites_requests', 'email', '_bx_invites_grid_column_title_email', '14%', 1, '25', '', 3),
+('bx_invites_requests', 'nip', '_bx_invites_grid_column_title_nip', '10%', 0, '15', '', 4),
+('bx_invites_requests', 'date', '_bx_invites_grid_column_title_date', '10%', 0, '20', '', 5),
+/*('bx_invites_requests', 'date_invite', '_bx_invites_grid_column_title_date_invite', '8%', 0, '20', '', 6),
+('bx_invites_requests', 'date_seen', '_bx_invites_grid_column_title_date_seen', '8%', 0, '20', '', 7),
+('bx_invites_requests', 'date_joined', '_bx_invites_grid_column_title_date_joined', '8%', 0, '20', '', 8),*/
+('bx_invites_requests', 'joined_account', '_bx_invites_grid_column_title_joined_account', '20%', 0, '20', '', 6),
+('bx_invites_requests', 'status', '_bx_invites_grid_column_title_status', '10%', 0, '15', '', 7),
+('bx_invites_requests', 'actions', '', '20%', 0, '', '', 8);
 
 INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
 ('bx_invites_requests', 'bulk', 'invite', '_bx_invites_grid_action_title_adm_invite', '', 0, 0, 1),
 ('bx_invites_requests', 'bulk', 'delete', '_bx_invites_grid_action_title_adm_delete', '', 0, 1, 2),
 ('bx_invites_requests', 'single', 'info', '_bx_invites_grid_action_title_adm_info', 'exclamation-circle', 1, 0, 1),
 ('bx_invites_requests', 'single', 'invite', '_bx_invites_grid_action_title_adm_invite', 'envelope', 1, 0, 2),
-('bx_invites_requests', 'single', 'delete', '_bx_invites_grid_action_title_adm_delete', 'remove', 1, 1, 3);
+('bx_invites_requests', 'single', 'delete', '_bx_invites_grid_action_title_adm_delete', 'remove', 1, 1, 3),
+('bx_invites_requests', 'independent', 'add', '_bx_invites_grid_action_title_adm_add', '', 0, 0, 4);
 
 
 -- STUDIO PAGE & WIDGET

+ 32 - 0
modules/boonex/invites/js/main.js

@@ -6,6 +6,8 @@ function BxInvMain(oOptions) {
     this._oRequestParams = oOptions.oRequestParams == undefined ? {} : oOptions.oRequestParams;
     this._sAnimationEffect = oOptions.sAnimationEffect == undefined ? 'fade' : oOptions.sAnimationEffect;
     this._iAnimationSpeed = oOptions.iAnimationSpeed == undefined ? 'slow' : oOptions.iAnimationSpeed;
+    this._sObjNameGrid = oOptions.sObjNameGrid;
+    this._sParamsDivider = oOptions.sParamsDivider == undefined ? '#-#' : oOptions.sParamsDivider;
 }
 
 BxInvMain.prototype.initRequestForm = function(sFormId) {
@@ -103,3 +105,33 @@ BxInvMain.prototype._getDefaultData = function () {
 	var oDate = new Date();
     return jQuery.extend({}, this._oRequestParams, {_t:oDate.getTime()});
 };
+
+BxInvMain.prototype.onChangeFilter = function (oFilter) {
+    var $this = this;
+	var oFilter1 = $('#bx-grid-filter1-' + this._sObjNameGrid);
+	var sValueFilter1 = oFilter1.length > 0 ? oFilter1.val() : '';
+	var oSearch = $('#bx-grid-search-' + this._sObjNameGrid);
+	var sValueSearch = oSearch.length > 0 ? oSearch.val() : '';
+	if(sValueSearch == _t('_sys_grid_search'))
+		sValueSearch = '';
+
+	clearTimeout($this._iSearchTimeoutId);
+	$this._iSearchTimeoutId = setTimeout(function () {
+        glGrids[$this._sObjNameGrid].setFilter(sValueFilter1 + $this._sParamsDivider + sValueSearch, true);
+    }, 500);
+};
+
+BxInvMain.prototype.setFilter = function (sFilter, isReload) {
+
+    if (this._sFilter == sFilter)
+        return;
+
+    this._sFilter = sFilter;
+
+    if (isReload) {
+        if (sFilter.length > 0)
+            this.reload(0);
+        else
+            this.reload();
+    }
+};

+ 16 - 0
modules/boonex/invites/template/css/main.css

@@ -29,4 +29,20 @@ div.bx-inv-request-btn  .bx-btn {
 div.bx-inv-request-text {
 	max-width: 400px;
 	max-width: 25rem;
+}
+
+/*--- General ---*/
+div.bx-grid-header div.bx-form-element-wrapper {
+    position: relative;
+    float: left;
+    width: 165px;
+}
+
+/*--- Administration tools ---*/
+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;
 }

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

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

+ 19 - 0
modules/boonex/invites/template/popup_invite.html

@@ -0,0 +1,19 @@
+<div class="bx-pgt-new-key bx-def-color-bg-block">
+    <div class="bx-pgt-new-key-cnt">
+        __form__
+        <script type="text/javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 15 - 1
modules/boonex/invites/template/request_text.html

@@ -1 +1,15 @@
-<div class="__style_prefix__-request-text bx-def-padding">__text__</div>
+<div class="__style_prefix__-request-text bx-def-padding">
+    __text__
+    <bx_if:show_date_invite>
+        <br>
+        __title__: __value__
+    </bx_if:show_date_invite>
+    <bx_if:show_date_seen>
+        <br>
+        __title__: __value__
+    </bx_if:show_date_seen>
+    <bx_if:show_date_joined>
+        <br>
+        __title__: __value__
+    </bx_if:show_date_joined>  
+</div>