Просмотр исходного кода

Ticket #4703 - Scores: Add possibility to Undo.

AntonLV 2 лет назад
Родитель
Сommit
e7dbbee8c8

+ 61 - 10
inc/classes/BxDolScore.php

@@ -135,6 +135,7 @@ class BxDolScore extends BxDolObject
                     `table_track` AS `table_track`,
                     `post_timeout` AS `post_timeout`,
                     `pruning` AS `pruning`,
+                    `is_undo` AS `is_undo`,
                     `is_on` AS `is_on`,
                     `trigger_table` AS `trigger_table`,
                     `trigger_field_id` AS `trigger_field_id`,
@@ -175,6 +176,11 @@ class BxDolScore extends BxDolObject
     /**
      * Interface functions for outer usage
      */
+    public function isUndo()
+    {
+        return (int)$this->_aSystem['is_undo'] == 1;
+    }
+
     public function getStatCounterUp()
     {
         $aScore = $this->_getVote();
@@ -243,14 +249,29 @@ class BxDolScore extends BxDolObject
         $iAuthorId = $this->_getAuthorId();
         $iAuthorIp = $this->_getAuthorIp();
 
+        $bUndo = $this->isUndo();
         $bVoted = $this->isPerformed($iObjectId, $iAuthorId, $iAuthorIp);
-        if($bVoted)
+        $bPerformUndo = $bVoted && $bUndo;
+
+        if(!$bPerformUndo && !$this->isAllowedVote())
+            return ['code' => BX_DOL_OBJECT_ERR_ACCESS_DENIED, 'message' => $this->msgErrAllowedVote()];
+
+        if($bVoted && !$bUndo)
             return ['code' => BX_DOL_OBJECT_ERR_DUPLICATE, 'message' => _t('_sys_score_err_duplicate_vote')];
 
-        $iId = $this->_oQuery->putVote($iObjectId, $iAuthorId, $iAuthorIp, $sType);
+        if($bPerformUndo) {
+            $aTrack = $this->_getTrack($iObjectId, $iAuthorId);
+            if(!empty($aTrack) && is_array($aTrack))
+                $aVoteData = array_intersect_key($aTrack, $aVoteData);
+        }
+
+        $iId = $this->_putVoteData($iObjectId, $iAuthorId, $iAuthorIp, $aVoteData, $bPerformUndo);
         if($iId === false)
             return ['code' => BX_DOL_OBJECT_ERR_CANNOT_PERFORM];
 
+        if(!$bPerformUndo)
+            $this->isAllowedVote(true);
+
         $this->_trigger();
 
         $sTypeUc = ucfirst($sType);
@@ -273,7 +294,19 @@ class BxDolScore extends BxDolObject
          * It's equivalent to @ref hook-bx_dol_score-doVoteUp
          * @hook @ref hook-bx_dol_score-doVoteDown
          */
-        bx_alert($this->_sSystem, 'doVote' . $sTypeUc, $iObjectId, $iAuthorId, [
+        /**
+         * @hooks
+         * @hookdef hook-bx_dol_score-undoVoteUp '{object_name}', 'undoVoteUp' - hook after undo score vote 
+         * It's equivalent to @ref hook-bx_dol_score-doVoteUp
+         * @hook @ref hook-bx_dol_score-undoVoteUp
+         */
+        /**
+         * @hooks
+         * @hookdef hook-bx_dol_score-undoVoteDown '{object_name}', 'undoVoteDown' - hook after undo score vote 
+         * It's equivalent to @ref hook-bx_dol_score-doVoteUp
+         * @hook @ref hook-bx_dol_score-undoVoteDown
+         */
+        bx_alert($this->_sSystem, ($bPerformUndo ? 'un' : '') . 'doVote' . $sTypeUc, $iObjectId, $iAuthorId, [
             'score_id' => $iId, 
             'score_author_id' => $iAuthorId, 
             'object_author_id' => $iObjectAuthorId
@@ -281,7 +314,7 @@ class BxDolScore extends BxDolObject
 
         /**
          * @hooks
-         * @hookdef hook-score-doVoteUp 'score', 'doUp' - hook after score vote 
+         * @hookdef hook-score-doUp 'score', 'doUp' - hook after score vote 
          * - $unit_name - equals `score`
          * - $action - equals `doUp`
          * - $object_id - score vote id
@@ -294,11 +327,23 @@ class BxDolScore extends BxDolObject
          */
         /**
          * @hooks
-         * @hookdef hook-score-doVoteDown 'score', 'doVoteDown' - hook after score vote 
+         * @hookdef hook-score-doDown 'score', 'doDown' - hook after score vote 
+         * It's equivalent to @ref hook-score-doUp
+         * @hook @ref hook-score-doDown
+         */
+        /**
+         * @hooks
+         * @hookdef hook-score-undoUp 'score', 'undoUp' - hook after undo score vote 
          * It's equivalent to @ref hook-score-doUp
-         * @hook @ref hook-score-doVoteDown
+         * @hook @ref hook-score-undoUp
          */
-        bx_alert('score', 'do' . $sTypeUc, $iId, $iAuthorId, [
+        /**
+         * @hooks
+         * @hookdef hook-score-undoDown 'score', 'undoDown' - hook after undo score vote 
+         * It's equivalent to @ref hook-score-doUp
+         * @hook @ref hook-score-undoDown
+         */
+        bx_alert('score', ($bPerformUndo ? 'un' : '') . 'do' . $sTypeUc, $iId, $iAuthorId, [
             'object_system' => $this->_sSystem, 
             'object_id' => $iObjectId, 
             'object_author_id' => $iObjectAuthorId
@@ -306,10 +351,11 @@ class BxDolScore extends BxDolObject
 
         $aRequestParamsData['show_script'] = false;
 
+        $bVoted = !$bVoted;
         $aScore = $this->_getVote($iObjectId, true);
         $iCup = (int)$aScore['count_up'];
         $iCdown = (int)$aScore['count_down'];
-        
+
         $aResult = [
             'code' => 0,
             'type' => $sType,
@@ -320,8 +366,8 @@ class BxDolScore extends BxDolObject
             'counter' => $this->getCounter($aRequestParamsData),
             'label_icon' => $this->_getIconDo($sType),
             'label_title' => _t($this->_getTitleDo($sType)),
-            'voted' => !$bVoted,
-            'disabled' => !$bVoted,
+            'voted' => $bVoted,
+            'disabled' => $bVoted && !$bUndo,
         ];
 
         $aResult['api'] = [
@@ -404,6 +450,11 @@ class BxDolScore extends BxDolObject
         return bx_srv($this->_aSystem['module'], 'check_allowed_view_for_profile', [$aObject]) === CHECK_ACTION_RESULT_ALLOWED;
     }
 
+    protected function _putVoteData($iObjectId, $iAuthorId, $iAuthorIp, $aData, $bPerformUndo)
+    {
+        return $this->_oQuery->putVote($iObjectId, $iAuthorId, $iAuthorIp, $aData, $bPerformUndo);
+    }
+
     protected function _returnVoteDataForSocket($aData, $aMask = [])
     {
         if(empty($aMask) || !is_array($aMask))

+ 27 - 7
inc/classes/BxDolScoreQuery.php

@@ -87,26 +87,33 @@ class BxDolScoreQuery extends BxDolObjectQuery
         return $aResult;
     }
 
-    public function putVote($iObjectId, $iAuthorId, $sAuthorIp, $sType)
+    public function putVote($iObjectId, $iAuthorId, $sAuthorIp, $aData, $bUndo = false)
     {
-        $bExists = (int)$this->getOne("SELECT `object_id` FROM `{$this->_sTable}` WHERE `object_id` = :object_id LIMIT 1", array('object_id' => $iObjectId)) != 0;
+        $bExists = (int)$this->getOne("SELECT `object_id` FROM `{$this->_sTable}` WHERE `object_id` = :object_id LIMIT 1", ['object_id' => $iObjectId]) != 0;
+        if(!$bExists && $bUndo)
+            return false;
+
+        $sType = $aData['type'];
 
         if(!$bExists)
             $sQuery = $this->prepare("INSERT INTO {$this->_sTable} SET `object_id` = ?, `count_" . $sType . "` = '1'", $iObjectId);
         else
-            $sQuery = $this->prepare("UPDATE `{$this->_sTable}` SET `count_" . $sType . "` = `count_" . $sType . "` + 1 WHERE `object_id` = ?", $iObjectId);
+            $sQuery = $this->prepare("UPDATE `{$this->_sTable}` SET `count_" . $sType . "` = `count_" . $sType . "` " . ($bUndo ? "-" : "+") . " 1 WHERE `object_id` = ?", $iObjectId);
 
         if((int)$this->query($sQuery) == 0)
             return false;
 
-        if((int)$this->query("INSERT INTO `{$this->_sTableTrack}` SET " . $this->arrayToSQL(array(
+        if($bUndo)
+            return $this->_deleteTrack($iObjectId, $iAuthorId);
+
+        if((int)$this->query("INSERT INTO `{$this->_sTableTrack}` SET " . $this->arrayToSQL([
             'object_id' => $iObjectId, 
             'author_id' => $iAuthorId, 
             'author_nip' => bx_get_ip_hash($sAuthorIp), 
             'type' => $sType, 
             'date' => time()
-        ))) > 0)
-        	return $this->lastId();
+        ])) > 0)
+            return $this->lastId();
 
         return false;
     }
@@ -128,7 +135,20 @@ class BxDolScoreQuery extends BxDolObjectQuery
         return $aResult;
     }
 
-	protected function _updateTriggerTable($iObjectId, $aEntry)
+    protected function _deleteTrack($iObjectId, $iAuthorId)
+    {
+        $iId = (int)$this->getOne("SELECT `id` FROM `{$this->_sTableTrack}` WHERE `object_id`=:object_id AND `author_id`=:author_id LIMIT 1", [
+            'object_id' => $iObjectId, 
+            'author_id' => $iAuthorId
+        ]);
+
+        if((int)$this->query("DELETE FROM `{$this->_sTableTrack}` WHERE `id`=:id LIMIT 1", ['id' => $iId]) > 0)
+            return $iId;
+
+        return false;
+    }
+
+    protected function _updateTriggerTable($iObjectId, $aEntry)
     {
         $aSet = array(
             $this->_sTriggerFieldScore => $aEntry['score'],

+ 1 - 0
install/sql/system.sql

@@ -1568,6 +1568,7 @@ CREATE TABLE `sys_objects_score` (
   `table_track` varchar(50) NOT NULL default '',
   `post_timeout` int(11) NOT NULL default '0',
   `pruning` int(11) NOT NULL default '31536000',
+  `is_undo` tinyint(1) NOT NULL default '0',
   `is_on` tinyint(1) NOT NULL default '1',
   `trigger_table` varchar(32) NOT NULL default '',
   `trigger_field_id` varchar(32) NOT NULL default '',

+ 3 - 1
template/scripts/BxBaseScore.php

@@ -339,10 +339,11 @@ class BxBaseScore extends BxDolScore
 
     protected function _getDoVote($sType, $aParams = [], $isAllowedVote = true)
     {
+        $bUndo = $this->isUndo();
     	$bVoted = isset($aParams['is_voted']) && (bool)$aParams['is_voted'] === true;
         $bShowDoVoteAsButtonSmall = isset($aParams['show_do_vote_as_button_small']) && (bool)$aParams['show_do_vote_as_button_small'] === true;
         $bShowDoVoteAsButton = !$bShowDoVoteAsButtonSmall && isset($aParams['show_do_vote_as_button']) && (bool)$aParams['show_do_vote_as_button'] === true;
-        $bDisabled = !$isAllowedVote || $bVoted;
+        $bDisabled = !$isAllowedVote || ($bVoted && !$bUndo);
 
         $sClass = '';
         if($bShowDoVoteAsButton)
@@ -355,6 +356,7 @@ class BxBaseScore extends BxDolScore
 
         if($this->_bApi)
             return [
+                'is_undo' => $bUndo,
                 'is_voted' => $bVoted,
                 'is_disabled' => $bDisabled,
                 'title' => _t($this->_getTitleDo($sType)),