AntonLV 7 лет назад
Родитель
Сommit
897632b0b8

+ 3 - 0
grid.php

@@ -23,6 +23,9 @@ if (!$oGrid) {
     exit;
 }
 
+if(method_exists($oGrid, 'init'))
+    $oGrid->init();
+
 $sAction = 'performAction' . bx_gen_method_name(bx_process_input(bx_get('a')));
 if (method_exists($oGrid, $sAction)) {
     $oGrid->$sAction();

+ 1 - 1
inc/classes/BxDolAccount.php

@@ -391,7 +391,7 @@ class BxDolAccount extends BxDolFactory implements iBxDolSingleton
     }
 
     /**
-     * Get account email
+     * Get language ID
      */
     public function getLanguageId($iAccountId = false)
     {

+ 12 - 0
inc/classes/BxDolConnectionQuery.php

@@ -253,6 +253,18 @@ class BxDolConnectionQuery extends BxDolDb
         return true;
     }
 
+    public function updateConnection ($iInitiator, $iContent, $aSet)
+    {
+        if(empty($aSet) || !is_array($aSet))
+            return false;
+
+        $sQuery = $this->prepare("UPDATE `" . $this->_sTable . "` SET " . $this->arrayToSQL($aSet) . " WHERE `initiator` = ? AND `content` = ?", $iInitiator, $iContent);
+        if ($bResult = $this->query($sQuery))
+            $this->cleanMemory('BxDolConnectionQuery::getConnection' . $this->_sTable . $iInitiator . $iContent);
+
+        return $bResult;
+    }
+
     public function updateConnectionMutual ($iInitiator, $iContent, $iMutual)
     {
         $sQuery = $this->prepare("UPDATE `" . $this->_sTable . "` SET `mutual` = ? WHERE `initiator` = ? AND `content` = ?", $iMutual, $iInitiator, $iContent);

+ 1 - 0
inc/classes/BxDolForm.php

@@ -14,6 +14,7 @@ define('BX_DOL_FORM_METHOD_SPECIFIC', 'specific');
 define('BX_DATA_LISTS_KEY_PREFIX', '#!');
 define('BX_DATA_VALUES_DEFAULT', 'LKey'); ///< Use default values for data items, @see BxDolForm::getDataItems
 define('BX_DATA_VALUES_ADDITIONAL', 'LKey2'); ///< Use additional values for data items, @see BxDolForm::getDataItems
+define('BX_DATA_VALUES_ALL', 'all'); ///< Return all available info for data items, @see BxDolForm::getDataItems
 
 /**
  * Forms allows to display forms from data stored in DB tables, before it was possible to display forms from PHP arrays only.

+ 7 - 3
inc/classes/BxDolFormQuery.php

@@ -179,11 +179,15 @@ class BxDolFormQuery extends BxDolDb
 
     static public function getDataItems($sKey, $isUseForSet = false, $sUseValues = BX_DATA_VALUES_DEFAULT)
     {
-        if ($sUseValues != BX_DATA_VALUES_DEFAULT && $sUseValues != BX_DATA_VALUES_ADDITIONAL)
+        $oDb = BxDolDb::getInstance();
+
+        if(!in_array($sUseValues, array(BX_DATA_VALUES_DEFAULT, BX_DATA_VALUES_ADDITIONAL, BX_DATA_VALUES_ALL)))
             $sUseValues = BX_DATA_VALUES_DEFAULT;
 
-        $oDb = BxDolDb::getInstance();
-        $sQuery = $oDb->prepare("SELECT `Value`, `LKey`, `LKey2` FROM `sys_form_pre_values` WHERE `Key` = ? ORDER BY `Order` ASC", $sKey);
+        $sQuery = $oDb->prepare("SELECT `Value`, `LKey`, `LKey2`, `Data` FROM `sys_form_pre_values` WHERE `Key` = ? ORDER BY `Order` ASC", $sKey);
+        if($sUseValues == BX_DATA_VALUES_ALL)
+            return $oDb->getAllWithKey($sQuery, 'Value');
+
         $a = $oDb->getAll($sQuery);
 
         $iMaxValue = 0;

+ 141 - 0
inc/classes/BxDolGridConnectionIn.php

@@ -0,0 +1,141 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+/*
+ * Incoming connections. Profile is connected by another profiles.
+ */
+class BxDolGridConnectionIn extends BxTemplGrid
+{
+    protected $_bInit;
+
+    protected $_bOwner;
+    protected $_iViewerId;
+    protected $_iProfileId;
+
+    protected $_oConnection;
+    protected $_sConnectionObject;
+    protected $_sConnectionMethod;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+        $this->_sDefaultSortingOrder = 'DESC';
+        $this->_aQueryAppendExclude[] = 'join_connections'; 
+
+        $this->_bInit = false;
+
+        $this->_bOwner = false;
+        $this->_iViewerId = (int)bx_get_logged_profile_id();
+        $this->_iProfileId = 0;
+
+        $this->_oConnection = null;
+        $this->_sConnectionObject = '';
+        $this->_sConnectionMethod = 'getConnectedInitiatorsAsSQLParts';
+    }
+
+    public function init()
+    {
+        if(!$this->_iProfileId && ($iProfileId = bx_get('profile_id')) !== false)
+            $this->_iProfileId = (int)$iProfileId;
+
+        if(!$this->_iProfileId)
+            return;
+
+        $oProfile = BxDolProfile::getInstance($this->_iProfileId);
+        if(!$oProfile)
+            return;
+
+        if($this->_iProfileId == $this->_iViewerId)
+            $this->_bOwner = true;
+
+        $this->_oConnection = BxDolConnection::getObjectInstance($this->_sConnectionObject);
+        if(!$this->_oConnection)
+            return;
+
+        $aSQLParts = $this->_oConnection->{$this->_sConnectionMethod}('p', 'id', $oProfile->id());
+
+        $this->addMarkers(array(
+            'profile_id' => $oProfile->id(),
+            'join_connections' => $aSQLParts['join']
+        ));
+
+        $this->_bInit = true;
+    }
+
+    public function setProfileId($iProfileId)
+    {
+        $this->_iProfileId = (int)$iProfileId;
+
+        $this->init();
+    }
+
+    public function getCode ($isDisplayHeader = true)
+    {
+        if(!$this->_bInit)
+            return '';
+
+        return parent::getCode($isDisplayHeader);        
+    }
+
+    protected function _getCellName ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $oProfile = BxDolProfile::getInstance($aRow['id']);
+        if (!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        return parent::_getCellDefault ($oProfile->getUnit(), $sKey, $aField, $aRow);
+    }
+
+    public function performActionAdd()
+    {
+        list($iId, $iViewedId) = $this->_prepareIds();
+        if(!$iId)
+            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
+
+        $a = $this->_oConnection->actionAdd($iId, $iViewedId);
+        if(!empty($a['err']))
+            return echoJson(array('msg' => $a['msg']));
+
+        return echoJson(array('grid' => $this->getCode(false), 'blink' => $iId));
+    }
+
+    protected function _getActionAdd ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $iViewerId = bx_get_logged_profile_id();
+        if(!isLogged() || $iViewerId == $aRow['id'] || $this->_oConnection->isConnected($iViewerId, $aRow['id']))
+            return '';
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _prepareIds ()
+    {
+        $iViewedId = (int)bx_get_logged_profile_id();
+
+        $iId = 0;
+        $aIds = bx_get('ids');
+        if($aIds && is_array($aIds))
+            $mixedId = array_pop($aIds);
+
+        if(strpos($mixedId, ':') !== false) {
+            list($iId, $iViewedId) = explode (':', $mixedId);
+
+            $iId = (int)$iId;
+            $iViewedId = (int)$iViewedId;
+        }
+        else 
+            $iId = (int)$mixedId;
+
+        return array($iId, $iViewedId);
+    }
+}
+
+/** @} */

+ 41 - 0
inc/classes/BxDolGridConnectionOut.php

@@ -0,0 +1,41 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+/*
+ * Outcoming connections. A profile connects another profiles.
+ */
+class BxDolGridConnectionOut extends BxDolGridConnectionIn
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sConnectionMethod = 'getConnectedContentAsSQLParts';
+    }
+
+    protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if (!isLogged() || !$this->_bOwner)
+            return '';
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _delete ($mixedId)
+    {
+        list($iId, $iViewedId) = $this->_prepareIds();
+
+        if(!$this->_oConnection->isConnected($iViewedId, $iId))
+            return true;
+
+        return $this->_oConnection->removeConnection($iViewedId, $iId);
+    }
+}
+
+/** @} */

+ 154 - 0
inc/classes/BxDolGridConnectionsin.php

@@ -0,0 +1,154 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+
+class BxDolGridConnectedMe extends BxTemplGrid
+{
+    protected $_bInit = false;
+
+    protected $_bOwner = false;
+    protected $_iProfileId = 0;
+
+    protected $_oConnection = null;
+    protected $_sConnectionObject = '';
+    protected $_sConnectionMethod = 'getConnectedInitiatorsAsSQLParts';
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+        $this->_sDefaultSortingOrder = 'DESC';
+        $this->_aQueryAppendExclude[] = 'join_connections'; 
+        
+        $this->_bInit = false;
+
+        $this->_bOwner = false;
+        $this->_iProfileId = 0;
+
+        $this->_oConnection = null;
+        $this->_sConnectionObject = '';
+        $this->_sConnectionMethod = 'getConnectedInitiatorsAsSQLParts';
+    }
+
+    public function init()
+    {
+        if(!$this->_iProfileId)
+            return false;
+
+        $oProfile = BxDolProfile::getInstance($this->_iProfileId);
+        if(!$oProfile)
+            return false;
+
+        if($oProfile->id() == bx_get_logged_profile_id())
+            $this->_bOwner = true;
+
+        $this->_oConnection = BxDolConnection::getObjectInstance($this->_sConnectionObject);
+        if(!$this->_oConnection)
+            return false;
+
+        $aSQLParts = $this->_oConnection->{$this->_sConnectionMethod}('p', 'id', $oProfile->id());
+
+        $this->addMarkers(array(
+            'profile_id' => $oProfile->id(),
+            'join_connections' => $aSQLParts['join']
+        ));
+
+        return true;
+    }
+
+    public function setProfileId($iProfileId)
+    {
+        $this->_iProfileId = (int)$iProfileId;
+
+        $this->_bInit = $this->init();
+    }
+
+    public function getCode ($isDisplayHeader = true)
+    {
+        if(!$this->_bInit)
+            return '';
+
+        return parent::getCode($isDisplayHeader);        
+    }
+
+    protected function _getCellName ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $oProfile = BxDolProfile::getInstance($aRow['id']);
+        if (!$oProfile)
+            return _t('_sys_txt_error_occured');
+
+        return parent::_getCellDefault ($oProfile->getUnit(), $sKey, $aField, $aRow);
+    }
+
+    /**
+     * 'accept' action handler
+     */
+    public function performActionAdd()
+    {
+        list($iId, $iViewedId) = $this->_prepareIds();
+        if(!$iId)
+            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
+
+        $a = $this->_oConnection->actionAdd($iId, $iViewedId);
+        if(!empty($a['err']))
+            return echoJson(array('msg' => $a['msg']));
+
+        return echoJson(array('grid' => $this->getCode(false), 'blink' => $iId));
+    }
+
+    protected function _getActionSubscribe ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        $iViewerId = bx_get_logged_profile_id();
+        if(!isLogged() || $iViewerId == $aRow['id'] || $this->_oConnection->isConnected($iViewerId, $aRow['id']))
+            return '';
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if (!isLogged() || !$this->_bOwner)
+            return '';
+
+        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _delete ($mixedId)
+    {
+        list($iId, $iViewedId) = $this->_prepareIds();
+
+        if(!$this->_oConnection->isConnected($iViewedId, $iId))
+            return true;
+
+        return $this->_oConnection->removeConnection($iViewedId, $iId);
+    }
+
+    protected function _prepareIds ()
+    {
+        $iViewedId = (int)bx_get_logged_profile_id();
+
+        $iId = 0;
+        $aIds = bx_get('ids');
+        if($aIds && is_array($aIds))
+            $mixedId = array_pop($aIds);
+
+        if(strpos($mixedId, ':') !== false) {
+            list($iId, $iViewedId) = explode (':', $mixedId);
+
+            $iId = (int)$iId;
+            $iViewedId = (int)$iViewedId;
+        }
+        else 
+            $iId = (int)$mixedId;
+
+        return array($iId, $iViewedId);
+    }
+}
+
+/** @} */

+ 91 - 0
inc/classes/BxDolGridRelatedMe.php

@@ -0,0 +1,91 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolGridRelatedMe extends BxDolGridConnectionIn
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sConnectionObject = 'sys_profiles_relations';
+    }
+
+    public function performActionConfirm()
+    {
+        list($iId, $iViewedId) = $this->_prepareIds();
+
+        if(!$iId)
+            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
+
+        $a = $this->_oConnection->actionConfirm($iId, $iViewedId);
+        if (isset($a['err']) && $a['err'])
+            echoJson(array('msg' => $a['msg']));
+        else
+            echoJson(array('grid' => $this->getCode(false), 'blink' => $iId));
+    }
+
+    public function performActionDecline()
+    {
+        list($iId, $iViewedId) = $this->_prepareIds();
+
+        if(!$iId)
+            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
+
+        $a = $this->_oConnection->actionReject($iId, $iViewedId);
+        if (isset($a['err']) && $a['err'])
+            echoJson(array('msg' => $a['msg']));
+        else
+            echoJson(array('grid' => $this->getCode(false), 'blink' => $iId));
+    }
+
+    protected function _getCellMutual($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = _t('_sys_' . ((int)$mixedValue != 1 ? 'un' : '') . 'confirmed');
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellRelation($mixedValue, $sKey, $aField, $aRow)
+    {
+        $aRelations = BxDolFormQuery::getDataItems('sys_relations');
+
+        return parent::_getCellDefault ($aRelations[$mixedValue], $sKey, $aField, $aRow);
+    }
+
+    protected function _getActionConfirm($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bOwner || $aRow['mutual'])
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionDecline($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!$this->_bOwner || $aRow['mutual'])
+            return '';
+
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+
+    protected function _getActionAdd($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    {
+        if(!isLogged() || (int)$aRow['id'] == $this->_iViewerId)
+            return '';
+
+        if($this->_oConnection->isConnected($this->_iViewerId, $aRow['id']))
+            return '';
+
+        unset($a['attr']['bx_grid_action_single']);
+        $a['attr']['onclick'] = "javascript: bx_menu_popup('sys_add_relation', window, {}, {profile_id: " . $aRow['id'] . "});";
+        return parent::_getActionDefault($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+    }
+}
+
+/** @} */

+ 34 - 0
inc/classes/BxDolGridRelations.php

@@ -0,0 +1,34 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolGridRelations extends BxDolGridConnectionOut
+{
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sConnectionObject = 'sys_profiles_relations';
+    }
+
+    protected function _getCellRelation ($mixedValue, $sKey, $aField, $aRow)
+    {
+        $aRelations = BxDolFormQuery::getDataItems('sys_relations');
+
+        return parent::_getCellDefault ($aRelations[$mixedValue], $sKey, $aField, $aRow);
+    }
+
+    protected function _getCellMutual($mixedValue, $sKey, $aField, $aRow)
+    {
+        $mixedValue = _t('_sys_' . ((int)$mixedValue != 1 ? 'un' : '') . 'confirmed');
+
+        return parent::_getCellDefault($mixedValue, $sKey, $aField, $aRow);
+    }
+}
+
+/** @} */

+ 4 - 105
inc/classes/BxDolGridSubscribedMe.php

@@ -7,124 +7,23 @@
  * @{
  */
 
-require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
-
-class BxDolGridSubscribedMe extends BxTemplGrid
+class BxDolGridSubscribedMe extends BxDolGridConnectionIn
 {
-    protected $_bInit = false;
-
-    protected $_bOwner = false;
-    protected $_iProfileId = 0;
-
-    protected $_oConnection;
-    protected $_sConnectionObject = 'sys_profiles_subscriptions';
-    protected $_sConnectionMethod = 'getConnectedInitiatorsAsSQLParts';  
-
     public function __construct ($aOptions, $oTemplate = false)
     {
         parent::__construct ($aOptions, $oTemplate);
-        $this->_sDefaultSortingOrder = 'DESC';
-
-        $this->_aQueryAppendExclude[] = 'join_connections';
-
-        if(($iProfileId = bx_get('profile_id')) !== false)
-            $this->setProfileId($iProfileId);   
-    }
-
-    public function init()
-    {
-        if(!$this->_iProfileId)
-            return false;
-
-        $oProfile = BxDolProfile::getInstance($this->_iProfileId);
-        if(!$oProfile)
-            return false;
-
-        if($oProfile->id() == bx_get_logged_profile_id())
-            $this->_bOwner = true;
-
-        $this->_oConnection = BxDolConnection::getObjectInstance($this->_sConnectionObject);
-        if(!$this->_oConnection)
-            return false;
-
-        $aSQLParts = $this->_oConnection->{$this->_sConnectionMethod}('p', 'id', $oProfile->id());
-
-        $this->addMarkers(array(
-            'profile_id' => $oProfile->id(),
-            'join_connections' => $aSQLParts['join']
-        ));
-
-        return true;
-    }
-
-    public function setProfileId($iProfileId)
-    {
-        $this->_iProfileId = (int)$iProfileId;
 
-        $this->_bInit = $this->init();
+        $this->_sConnectionObject = 'sys_profiles_subscriptions';
     }
 
-    public function getCode ($isDisplayHeader = true)
-    {
-        if(!$this->_bInit)
-            return '';
-
-        return parent::getCode($isDisplayHeader);        
-    }
-
-    /**
-     * 'accept' action handler
-     */
     public function performActionSubscribe()
     {
-        list($iId, $iViewedId) = $this->_prepareIds();
-        if(!$iId)
-            return echoJson(array('msg' => _t('_sys_txt_error_occured')));
-
-        $a = $this->_oConnection->actionAdd($iId, $iViewedId);
-        if(!empty($a['err']))
-            return echoJson(array('msg' => $a['msg']));
-
-        return echoJson(array('grid' => $this->getCode(false), 'blink' => $iId));
-    }
-
-    protected function _getCellName ($mixedValue, $sKey, $aField, $aRow)
-    {
-        $oProfile = BxDolProfile::getInstance($aRow['id']);
-        if (!$oProfile)
-            return _t('_sys_txt_error_occured');
-
-        return parent::_getCellDefault ($oProfile->getUnit(), $sKey, $aField, $aRow);
+        return parent::performActionAdd();
     }
 
     protected function _getActionSubscribe ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
     {
-        $iViewerId = bx_get_logged_profile_id();
-        if(!isLogged() || $iViewerId == $aRow['id'] || $this->_oConnection->isConnected($iViewerId, $aRow['id']))
-            return '';
-
-        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
-    }
-
-    protected function _prepareIds ()
-    {
-        $iViewedId = bx_get_logged_profile_id();
-
-        $iId = 0;
-        $aIds = bx_get('ids');
-        if($aIds && is_array($aIds))
-            $mixedId = array_pop($aIds);
-
-        if(strpos($mixedId, ':') !== false) {
-            list($iId, $iViewedId) = explode (':', $mixedId);
-
-            $iId = (int)$iId;
-            $iViewedId = (int)$iViewedId;
-        }
-        else 
-            $iId = (int)$mixedId;
-
-        return array($iId, $iViewedId);
+        return $this->_getActionAdd ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
     }
 }
 

+ 7 - 17
inc/classes/BxDolGridSubscriptions.php

@@ -7,33 +7,23 @@
  * @{
  */
 
-require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
-
-class BxDolGridSubscriptions extends BxDolGridSubscribedMe
+class BxDolGridSubscriptions extends BxDolGridConnectionOut
 {
-    protected $_sConnectionMethod = 'getConnectedContentAsSQLParts';
-
     public function __construct ($aOptions, $oTemplate = false)
     {
         parent::__construct ($aOptions, $oTemplate);
+
+        $this->_sConnectionObject = 'sys_profiles_subscriptions';
     }
 
-    protected function _delete ($mixedId)
+    public function performActionSubscribe()
     {
-        list($iId, $iViewedId) = $this->_prepareIds();
-
-        if(!$this->_oConnection->isConnected($iViewedId, $iId))
-            return true;
-
-        return $this->_oConnection->removeConnection($iViewedId, $iId);
+        return parent::performActionAdd();
     }
 
-    protected function _getActionDelete ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
+    protected function _getActionSubscribe ($sType, $sKey, $a, $isSmall = false, $isDisabled = false, $aRow = array())
     {
-        if (!isLogged() || !$this->_bOwner)
-            return '';
-
-        return parent::_getActionDefault ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
+        return $this->_getActionAdd ($sType, $sKey, $a, $isSmall, $isDisabled, $aRow);
     }
 }
 

+ 173 - 0
inc/classes/BxDolRelation.php

@@ -0,0 +1,173 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+class BxDolRelation extends BxDolConnection
+{
+    protected function __construct($aObject)
+    {
+        parent::__construct($aObject);
+
+        $this->_oQuery = new BxDolRelationQuery($aObject);
+    }
+
+    /**
+     * Add new relation.
+     * @param $mixedContent content to make relation with or an array with content and relation type
+     * @return array
+     */
+    public function actionAdd($mixedContent = 0, $iInitiator = false)
+    {
+        if(empty($mixedContent))
+            $mixedContent = bx_process_input($_POST['id'], BX_DATA_INT);
+
+        $iContent = 0;
+        $iRelation = 0;
+        if(is_array($mixedContent)) {
+            $iContent = (int)$mixedContent['content'];
+            $iRelation = (int)$mixedContent['relation'];
+        }
+        else
+            $iContent = (int)$mixedContent;
+
+        $iInitiator = $iInitiator ? (int)$iInitiator : (int)bx_get_logged_profile_id();
+
+        $aResult = parent::actionAdd($iContent, $iInitiator);
+        if(empty($iRelation) || (isset($aResult['err']) && $aResult['err'] !== false))
+            return $aResult;
+
+        $this->_oQuery->updateConnection($iInitiator, $iContent, array(
+            'relation' => $iRelation
+        ));
+
+        return $aResult;
+    }
+    
+    /**
+     * Confirm relation request without creation of retroactive relation.
+     * @param $iContent content to make relation with
+     * @return array
+     */
+    public function actionConfirm($iContent = 0, $iInitiator = false)
+    {
+        if(!$iContent)
+            $iContent = bx_process_input($_POST['id'], BX_DATA_INT);
+
+        return $this->_action($iContent, $iInitiator ? $iInitiator : bx_get_logged_profile_id(), 'confirmConnection', '_sys_conn_err_connection_does_not_exists');
+    }
+
+    /**
+     * Remove relation without removing a retroactive relation. This method is wrapper for @see removeConnection to be called from @see conn.php upon AJAX request to this file.
+     * @param $iContent content to make connection to, in most cases some content id, or other profile id in case of friends
+     * @return array
+     */
+    public function actionRemove($iContent = 0, $iInitiator = false)
+    {
+        if(!$iContent)
+            $iContent = bx_process_input($_POST['id'], BX_DATA_INT);
+
+        return $this->_action($iInitiator ? $iInitiator : bx_get_logged_profile_id(), $iContent, 'removeConnection', '_sys_conn_err_connection_does_not_exists');
+    }
+
+    /**
+     * Confirm relation request without creation of retroactive relation.
+     * @param $iInitiator initiator of the connection, in most cases some profile id
+     * @param $iContent content to make connection to, in most cases some content id, or other profile id in case of friends
+     * @return true - if connection was added, false - if connection already exists or error occured
+     */
+    public function confirmConnection($iInitiator, $iContent)
+    {
+        $iMutual = 1;
+        if(!$this->_oQuery->updateConnectionMutual((int)$iInitiator, (int)$iContent, $iMutual))
+            return false;
+
+        bx_alert($this->_sObject, 'connection_confirmed', 0, bx_get_logged_profile_id(), array(
+            'initiator' => (int)$iInitiator,
+            'content' => (int)$iContent,
+            'mutual' => (int)$iMutual,
+            'object' => $this,
+        ));
+
+        return true;
+    }
+
+    /**
+     * Compound function, which calls getCommonContentExt, getConnectedContentExt or getConnectedInitiatorsExt depending on $sContentType
+     * @param $sContentType content type to get BX_CONNECTIONS_CONTENT_TYPE_CONTENT, BX_CONNECTIONS_CONTENT_TYPE_INITIATORS or BX_CONNECTIONS_CONTENT_TYPE_COMMON
+     * @param $iId1 one content or initiator
+     * @param $iId2 second content or initiator only in case of BX_CONNECTIONS_CONTENT_TYPE_COMMON content type
+     * @param $isMutual get mutual connections only
+     * @return array of available connections
+     */
+    public function getConnectionsAsArrayExt($sContentType, $iId1, $iId2, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        if (BX_CONNECTIONS_CONTENT_TYPE_COMMON == $sContentType)
+            return $this->getCommonContentExt($iId1, $iId2, $isMutual, $iStart, $iLimit, $iOrder);
+
+        if (BX_CONNECTIONS_CONTENT_TYPE_INITIATORS == $sContentType)
+            $sMethod = 'getConnectedInitiatorsExt';
+        else
+            $sMethod = 'getConnectedContentExt';
+
+        return $this->$sMethod($iId1, $isMutual, $iStart, $iLimit, $iOrder);
+    }
+
+    /**
+     * Get common content (full info) between two initiators
+     * @param $iInitiator1 one initiator
+     * @param $iInitiator2 second initiator
+     * @param $isMutual get mutual connections only
+     * @return array of available connections
+     */
+    public function getCommonContentExt($iInitiator1, $iInitiator2, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        return $this->_oQuery->getCommonContentExt($iInitiator1, $iInitiator2, $isMutual, $iStart, $iLimit, $iOrder);
+    }
+
+    /**
+     * Get connected initiators (full info)
+     * @param $iContent content of the connection
+     * @param $isMutual get mutual connections only
+     * @return array of available connections
+     */
+    public function getConnectedInitiatorsExt($iContent, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        return $this->_oQuery->getConnectedInitiatorsExt($iContent, $isMutual, $iStart, $iLimit, $iOrder);
+    }
+
+    /**
+     * Get connected content (full info)
+     * @param $iInitiator initiator of the connection
+     * @param $isMutual get mutual connections only
+     * @return array of available connections
+     */
+    public function getConnectedContentExt($iInitiator, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        return $this->_oQuery->getConnectedContentExt($iInitiator, $isMutual, $iStart, $iLimit, $iOrder);
+    }
+
+    /**
+     * Check whether connection between Initiator and Content can be established.
+     */
+    public function checkAllowedConnect($iInitiator, $iContent, $isPerformAction = false, $isMutual = false, $isInvertResult = false, $isSwap = false)
+    {
+        if(!BxDolConnection::getObjectInstance('sys_profiles_friends')->isConnected($iInitiator, $iContent, true))
+            return _t('_sys_txt_access_denied');
+
+        return parent::checkAllowedConnect($iInitiator, $iContent, $isPerformAction, $isMutual, $isInvertResult, $isSwap);
+    }
+
+    public function getRelation($iInitiator, $iContent)
+    {
+        $aConnection = $this->_oQuery->getConnection ($iInitiator, $iContent);
+        if(empty($aConnection) || !is_array($aConnection))
+            return 0;
+
+        return (int)$aConnection['relation'];
+    }
+}

+ 89 - 0
inc/classes/BxDolRelationQuery.php

@@ -0,0 +1,89 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+/**
+ * Database queries for Relation objects.
+ * @see BxDolConnection
+ */
+class BxDolRelationQuery extends BxDolConnectionQuery
+{
+    public function __construct($aObject)
+    {
+        parent::__construct($aObject);
+    }
+
+    public function addConnection ($iInitiator, $iContent, &$iMutualParam = null)
+    {
+        if ($this->getConnection($iInitiator, $iContent)) // connection already exists
+            return false;
+
+        $iMutual = 0;
+        if(!$this->query("INSERT INTO `" . $this->_sTable . "` SET `initiator` = :initiator, `content` = :content, `added` = :added, `mutual` = :mutual", array(
+            'initiator' => $iInitiator, 
+            'content' => $iContent, 
+            'mutual' => $iMutual, 
+            'added' => time()
+        ))) return false;
+
+        if($iMutualParam !== null)
+            $iMutualParam = $iMutual;
+
+        $this->cleanMemory('BxDolConnectionQuery::getConnection' . $this->_sTable . $iInitiator . $iContent);
+        return true;
+    }
+
+    public function removeConnection ($iInitiator, $iContent)
+    {
+        $sQuery = $this->prepare("DELETE FROM `" . $this->_sTable . "` WHERE `initiator` = ? AND `content` = ?", $iInitiator, $iContent);
+        if(!$this->res($sQuery))
+            return false;
+
+        $this->cleanMemory('BxDolConnectionQuery::getConnection' . $this->_sTable . $iInitiator . $iContent);
+        return true;
+    }
+    
+    public function getCommonContentExt($iInitiator1, $iInitiator2, $isMutual, $iStart, $iLimit, $iOrder)
+    {
+        $sFields = "`c`.`content` AS `content`, `c`.`initiator` AS `initiator1`, `c`.`relation` AS `relation1`, `c`.`mutual` AS `mutual1`, `c2`.`initiator` AS `initiator2`, `c2`.`relation` AS `relation2`, `c2`.`mutual` AS `mutual2`";
+
+        $sWhereJoin = (false !== $isMutual) ? " AND `c2`.`mutual` = :mutual" : "";
+        $sJoin = "INNER JOIN `" . $this->_sTable . "` AS `c2` ON (`c2`.`initiator` = :initiator2 AND `c`.`content` = `c2`.`content` $sWhereJoin)";
+
+        $sWhere = " AND `c`.`initiator` = :initiator1";
+        $sQuery = $this->_getConnectionsQuery($sWhere, $sJoin, $sFields, $isMutual, $iStart, $iLimit, $iOrder);
+
+        return $this->getAllWithKey($sQuery, 'content', array(
+            'mutual' => $isMutual,
+            'initiator1' => $iInitiator1,
+            'initiator2' => $iInitiator2
+    	));
+    }
+
+    public function getConnectedContentExt($iInitiator, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        $sWhere = " AND `c`.`initiator` = :initiator";
+        $sQuery = $this->_getConnectionsQuery($sWhere, '', '*', $isMutual, $iStart, $iLimit, $iOrder);
+
+        return $this->getAllWithKey($sQuery, 'content', array(
+            'initiator' => $iInitiator
+        ));
+    }
+
+    public function getConnectedInitiatorsExt($iContent, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        $sWhere = " AND `c`.`content` = :content";
+        $sQuery = $this->_getConnectionsQuery($sWhere, '', '*', $isMutual, $iStart, $iLimit, $iOrder);
+
+        return $this->getAllWithKey($sQuery, 'initiator', array(
+            'content' => $iContent
+        ));
+    }
+}
+
+/** @} */

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
install/sql/system.sql


+ 21 - 0
modules/boonex/decorous/data/template/system/scripts/BxTemplMenuAddRelation.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuAddRelation extends BxBaseMenuAddRelation
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 4
modules/boonex/english/data/langs/system/en.xml

@@ -1635,6 +1635,7 @@
 	<string name="_sys_acl_expire"><![CDATA[Expire: ]]></string>
 	<string name="_sys_acl_expire_never"><![CDATA[never]]></string>
 	<string name="_sys_add_friend"><![CDATA[Add friend]]></string>
+        <string name="_sys_add_relation"><![CDATA[Add relation]]></string>
 	<string name="_sys_adm_installed"><![CDATA[Installed]]></string>
 	<string name="_sys_admin_apply"><![CDATA[Apply]]></string>
 	<string name="_sys_admin_filter"><![CDATA[Filter:]]></string>
@@ -1711,6 +1712,8 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_chart_accounts_growth"><![CDATA[Accounts: Growth]]></string>
 	<string name="_sys_chart_accounts_growth_speed"><![CDATA[Accounts: Growth Speed]]></string>
 	<string name="_sys_close"><![CDATA[Close]]></string>
+        <string name="_sys_confirm"><![CDATA[Confirm]]></string>
+        <string name="_sys_confirmed"><![CDATA[Confirmed]]></string>
 	<string name="_sys_conn_err_connection_already_exists"><![CDATA[Connection already exists]]></string>
 	<string name="_sys_conn_err_connection_does_not_exists"><![CDATA[Connection doesn't exist]]></string>
 	<string name="_sys_conn_err_connection_is_awaiting_confirmation"><![CDATA[Connection request is awaiting confirmation]]></string>
@@ -1729,6 +1732,7 @@ If it is not enabled then please consider implement this optimization, since it
     <string name="_sys_connect_option_privacy"><![CDATA[Default privacy for created profiles]]></string>
 
 	<string name="_sys_currency"><![CDATA[{0}{1}]]></string>
+        <string name="_sys_decline"><![CDATA[Decline]]></string>
 	<string name="_sys_designbox_0"><![CDATA[Content]]></string>
 	<string name="_sys_designbox_1"><![CDATA[Content + Title + Background]]></string>
 	<string name="_sys_designbox_10"><![CDATA[Content + Padding]]></string>
@@ -2370,6 +2374,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_menu_title_set_acl_level"><![CDATA[ACL Levels]]></string>
 	<string name="_sys_menu_title_social_sharing"><![CDATA[Social Sharing]]></string>
         <string name="_sys_menu_title_create_post"><![CDATA[Create Post Menu]]></string>
+        <string name="_sys_menu_title_add_relation"><![CDATA[Add Relation Menu]]></string>
 	<string name="_sys_menu_title_submenu"><![CDATA[Site Submenu]]></string>
 	<string name="_sys_menu_title_toolbar_member"><![CDATA[Member Toolbar]]></string>
 	<string name="_sys_menu_title_toolbar_site"><![CDATA[Site Toolbar]]></string>
@@ -2486,6 +2491,15 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_paginate_info"><![CDATA[{0}-{1}]]></string>
 	<string name="_sys_paginate_view_all"><![CDATA[View All]]></string>
 	<string name="_sys_please_select"><![CDATA[Please select...]]></string>
+        <string name="_sys_pre_lists_relations"><![CDATA[Relations]]></string>
+        <string name="_sys_pre_lists_relations_husband"><![CDATA[husband]]></string>
+        <string name="_sys_pre_lists_relations_wife"><![CDATA[wife]]></string>
+        <string name="_sys_pre_lists_relations_father"><![CDATA[father]]></string>
+        <string name="_sys_pre_lists_relations_mother"><![CDATA[mother]]></string>
+        <string name="_sys_pre_lists_relations_son"><![CDATA[son]]></string>
+        <string name="_sys_pre_lists_relations_daughter"><![CDATA[daughter]]></string>
+        <string name="_sys_pre_lists_relations_brother"><![CDATA[brother]]></string>
+        <string name="_sys_pre_lists_relations_sister"><![CDATA[sister]]></string>
 	<string name="_sys_pre_lists_report_types"><![CDATA[Report Types]]></string>
 	<string name="_sys_pre_lists_report_types_spam"><![CDATA[spam]]></string>
 	<string name="_sys_pre_lists_report_types_scam"><![CDATA[scam]]></string>
@@ -2520,10 +2534,11 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_ps_group_title_secret"><![CDATA[Secret]]></string>
     <string name="_sys_ps_ferr_incorrect_select"><![CDATA[You need to select some value]]></string>
     <string name="_sys_ps_space_title_friend"><![CDATA[friend]]></string>
-	<string name="_sys_push_notification_request"><![CDATA[Would you like to get notifications from {0}?]]></string>  
+    <string name="_sys_push_notification_request"><![CDATA[Would you like to get notifications from {0}?]]></string>  
     <string name="_sys_push_notification_request_yes"><![CDATA[Yes]]></string>  
     <string name="_sys_push_notification_request_no"><![CDATA[No, thanks]]></string>
     <string name="_sys_read_more"><![CDATA[Continue reading "{0}"]]></string>
+    <string name="_sys_relation"><![CDATA[Relation]]></string>
 	<string name="_sys_request_module_not_found_cpt"><![CDATA[Module was not found]]></string>
 	<string name="_sys_request_module_not_found_cnt"><![CDATA[Module({0}) was not found]]></string>
 	<string name="_sys_request_page_not_found_cpt"><![CDATA[Page was not found]]></string>
@@ -2551,6 +2566,7 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_splash_inp_placeholder"><![CDATA[site address]]></string>
 	<string name="_sys_splash_inp_postfix"><![CDATA[.online.me]]></string>
 	<string name="_sys_splash_slogan"><![CDATA[The easiest way to create your own social website.]]></string>
+        <string name="_sys_status"><![CDATA[Status]]></string>
 	<string name="_sys_storage_err_db"><![CDATA[database error]]></string>
 	<string name="_sys_storage_err_engine_add"><![CDATA[error occurred]]></string>
 	<string name="_sys_storage_err_engine_get"><![CDATA[error occurred]]></string>
@@ -2701,9 +2717,10 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_txt_unsubscribe_email_settings_update_success"><![CDATA[Your email preferences has been successfully updated.]]></string>
 	<string name="_sys_txt_unsubscribe_error_occured"><![CDATA[Error occurred, please login to your account and update email references there or contact site administrator to unsubscribe you manually.]]></string>
 	<string name="_sys_txt_unsubscribe_info"><![CDATA[Update email preferences for <b>{0}</b>]]></string>
-    <string name="_sys_txt_unsubscribe_wrong_link"><![CDATA[Unsubscribe link is wrong.]]></string>
-    <string name="_sys_txt_user_n"><![CDATA[User #{0}]]></string>
-  <string name="_sys_txt_reports_title"><![CDATA[Reports]]></string>
+        <string name="_sys_txt_unsubscribe_wrong_link"><![CDATA[Unsubscribe link is wrong.]]></string>
+        <string name="_sys_txt_user_n"><![CDATA[User #{0}]]></string>
+        <string name="_sys_txt_reports_title"><![CDATA[Reports]]></string>
+        <string name="_sys_unconfirmed"><![CDATA[Unconfirmed]]></string>
 	<string name="_sys_upgrade_conclusion"><![CDATA[<h3>Important info:</h3><p>{0}</p>]]></string>
 	<string name="_sys_upgrade_db_and_files_versions_different"><![CDATA[Database and files versions are different, probably previous patch wasn't applied correctly.]]></string>
 	<string name="_sys_upgrade_files_checksum_failed"><![CDATA[Can't apply upgrade because the following files were modified: {0}]]></string>

+ 21 - 0
modules/boonex/lucid/data/template/system/scripts/BxTemplMenuAddRelation.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuAddRelation extends BxBaseMenuAddRelation
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/ocean/data/template/system/scripts/BxTemplMenuAddRelation.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuAddRelation extends BxBaseMenuAddRelation
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 21 - 0
modules/boonex/protean/data/template/system/scripts/BxTemplMenuAddRelation.php

@@ -0,0 +1,21 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaTemplate UNA Template Classes
+ * @{
+ */
+
+/**
+ * @see BxDolMenu
+ */
+class BxTemplMenuAddRelation extends BxBaseMenuAddRelation
+{
+    public function __construct ($aObject, $oTemplate = false)
+    {
+        parent::__construct ($aObject, $oTemplate);
+    }
+}
+
+/** @} */

+ 2 - 0
studio/classes/BxDolStudioFormsQuery.php

@@ -538,6 +538,8 @@ class BxDolStudioFormsQuery extends BxDolDb
                 `tv`.`LKey` AS `LKey`,
                 `tv`.`LKey2` AS `lkey2`,
                 `tv`.`LKey2` AS `LKey2`,
+                `tv`.`Data` AS `data`,
+                `tv`.`Data` AS `Data`,
                 `tv`.`Order` AS `order`,
                 `tv`.`Order` AS `Order`" . $sSelectClause . "
             FROM `sys_form_pre_values` AS `tv` " . $sJoinClause . "

+ 14 - 1
template/css/menu.css

@@ -746,4 +746,17 @@ ul.bx-menu-btns-icon-hor li:last-child .bx-btn {
     height: 1.0rem;
     line-height: 1.0rem;
     font-size: 1.0rem;
-}
+}
+
+/* --------------- add relation menu */
+.bx-popup .bx-menu-ver.bx-menu-object-sys_add_relation li a {
+    line-height: normal;
+}
+.bx-popup .bx-menu-ver.bx-menu-object-sys_add_relation li a span {
+    margin-left: 0;
+    text-transform: capitalize;
+}
+
+.bx-menu-add-relation-hidden {
+    display: none;
+}

+ 97 - 0
template/scripts/BxBaseMenuAddRelation.php

@@ -0,0 +1,97 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaBaseView UNA Base Representation Classes
+ * @{
+ */
+
+/**
+ * Menu to add relation between profiles.
+ */
+class BxBaseMenuAddRelation extends BxTemplMenu
+{
+    protected $_sPreList;
+    protected $_sConnection;
+
+    protected $_iInitiator;
+    protected $_iContent;
+
+    public function __construct ($aObject, $oTemplate)
+    {
+        parent::__construct ($aObject, $oTemplate);
+
+        $this->_sPreList = 'sys_relations';
+        $this->_sConnection = 'sys_profiles_relations';
+
+        $this->_iInitiator = bx_get_logged_profile_id();
+        $this->_iContent = 0;
+    }
+
+    public function getMenuItems ()
+    {
+        $this->loadData();
+
+        return parent::getMenuItems();
+    }
+
+    protected function _getMenuItem ($a)
+    {
+        $aResult = parent::_getMenuItem($a);
+        if(empty($aResult) || !is_array($aResult))
+            return $aResult;
+
+        if(!empty($a['class']))
+            $aResult['class_add'] .= ' ' . $a['class'];
+
+        return $aResult;
+    }
+
+    protected function loadData()
+    {
+        $sClassHidden = 'bx-menu-add-relation-hidden';
+
+        if(bx_get('profile_id') !== false)
+            $this->_iContent = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+        $oRelation = BxDolConnection::getObjectInstance($this->_sConnection);
+        $aRelations = BxDolFormQuery::getDataItems($this->_sPreList, false, BX_DATA_VALUES_ALL);
+
+        $aSuggest = array();
+        $bSuggest = $oRelation->isConnected($this->_iContent, $this->_iInitiator);
+        if($bSuggest) {
+            $iRelation = $oRelation->getRelation($this->_iContent, $this->_iInitiator);
+            if(!empty($iRelation) && !empty($aRelations[$iRelation]['Data']))
+                $aSuggest = unserialize($aRelations[$iRelation]['Data']);
+        }
+
+        $aItems = array();
+        foreach($aRelations as $iId => $aRelation) {
+            $aItems[] = array(
+                'id' => $iId,
+                'name' => $iId,
+                'class' => $bSuggest && !in_array($iId, $aSuggest) ? $sClassHidden : '',
+                'title' => _t($aRelation[BX_DATA_VALUES_DEFAULT]),
+                'icon' => '',
+                'link' => 'javascript:void(0);',
+                'onclick' => "bx_conn_action(this, '" . $this->_sConnection . "', 'add', " . bx_js_string(json_encode(array('content' => $this->_iContent, 'relation' => $iId))) . ")"
+            );
+        }
+
+        if($bSuggest && !empty($aSuggest))
+            $aItems[] = array(
+                'id' => 'see_more',
+                'name' => 'see_more',
+                'class' => '',
+                'title' => _t('_see_more'),
+                'icon' => '',
+                'link' => 'javascript:void(0);',
+                'onclick' => bx_js_string("$(this).parents('li:first').hide().siblings('." . $sClassHidden . "').removeClass('" . $sClassHidden . "');")
+            );
+
+        $this->_aObject['menu_items'] = $aItems;
+    }
+}
+
+/** @} */

+ 56 - 2
template/scripts/BxBaseServiceConnections.php

@@ -141,7 +141,7 @@ class BxBaseServiceConnections extends BxDol
         return $i;
     }
 
-	/**
+    /**
      * get grid with subscriptions connections
      */
     public function serviceSubscriptionsTable ($iProfileId = 0)
@@ -172,7 +172,7 @@ class BxBaseServiceConnections extends BxDol
         ));
     }
 
-	/**
+    /**
      * get grid with subscribed me connections
      */
     public function serviceSubscribedMeTable ($iProfileId = 0)
@@ -203,6 +203,60 @@ class BxBaseServiceConnections extends BxDol
         ));
     }
 
+    /**
+     * get grid with 'relations' connections
+     */
+    public function serviceRelationsTable ($iProfileId = 0)
+    {
+        if(!$iProfileId && bx_get('profile_id') !== false)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+        $aProfile = BxDolProfile::getInstance($iProfileId)->getInfo();
+        if(empty($aProfile) || !is_array($aProfile))
+            return false;
+
+        $oGrid = BxDolGrid::getObjectInstance('sys_grid_relations');
+        if (!$oGrid)
+            return false;
+
+        $oGrid->setProfileId($iProfileId);
+        $sContent = $oGrid->getCode();
+        if(empty($sContent))
+            return false;
+
+        return BxDolTemplate::getInstance()->parseHtmlByName('connections_list.html', array(
+            'name' => 'relations',
+            'content' => $sContent
+        ));
+    }
+
+    /**
+     * get grid with 'related me' connections
+     */
+    public function serviceRelatedMeTable ($iProfileId = 0)
+    {
+        if(!$iProfileId && bx_get('profile_id') !== false)
+            $iProfileId = bx_process_input(bx_get('profile_id'), BX_DATA_INT);
+
+        $aProfile = BxDolProfile::getInstance($iProfileId)->getInfo();
+        if(empty($aProfile) || !is_array($aProfile))
+            return false;
+
+        $oGrid = BxDolGrid::getObjectInstance('sys_grid_related_me');
+        if(!$oGrid)
+            return false;
+
+        $oGrid->setProfileId($iProfileId);
+        $sContent = $oGrid->getCode();
+        if(empty($sContent))
+            return false;
+
+        return BxDolTemplate::getInstance()->parseHtmlByName('connections_list.html', array(
+            'name' => 'related-me',
+            'content' => $sContent
+        ));
+    }
+
     /*
      * Get notification data for Notifications module - action Subscribe. 
      */

Некоторые файлы не были показаны из-за большого количества измененных файлов