diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 6da4321..22b9bf5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -37,7 +37,7 @@ jobs: NC3_BUILD_DIR: "/opt/nc3" NC3_DOCKER_DIR: "/opt/docker" NC3_GIT_URL: "git://github.com/NetCommons3/NetCommons3.git" - NC3_GIT_BRANCH: "master" + NC3_GIT_BRANCH: "availability" PLUGIN_BUILD_DIR: ${{ github.workspace }} PHP_VERSION: ${{ matrix.php }} MYSQL_VERSION: ${{ matrix.mysql }} diff --git a/Controller/LikesController.php b/Controller/LikesController.php index 57bfe2d..97622f9 100644 --- a/Controller/LikesController.php +++ b/Controller/LikesController.php @@ -4,6 +4,7 @@ * * @author Noriko Arai * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project @@ -15,6 +16,7 @@ * Likes Controller * * @author Shohei Nakajima + * @author Kazunori Sakamoto * @package NetCommons\Likes\Controller */ class LikesController extends LikesAppController { @@ -26,6 +28,7 @@ class LikesController extends LikesAppController { */ public $uses = array( 'Likes.Like', + 'Likes.LikesUser', ); /** @@ -35,15 +38,63 @@ class LikesController extends LikesAppController { */ public function beforeFilter() { parent::beforeFilter(); - $this->Auth->allow('like'); + $this->Auth->allow('load'); + $this->Auth->allow('save'); } /** - * like + * load * * @return void */ - public function like() { + public function load() { + $likes = []; + $condsStrs = explode(',', $this->request->query('like_conds_strs')); + + $likesUserConditions = []; + if (Current::read('User.id')) { + $likesUserConditions['user_id'] = Current::read('User.id'); + } else { + $likesUserConditions['session_key'] = $this->Session->id(); + } + + foreach ($condsStrs as $condsStr) { + $conds = explode('-', $condsStr); + $like = $this->Like->find('first', [ + 'fields' => [ + 'id', + 'like_count', + 'unlike_count', + ], + 'conditions' => [ + 'plugin_key' => $conds[0], + 'block_key' => $conds[1], + 'content_key' => $conds[2], + ], + 'recursive' => -1, + ]); + if (! empty($like)) { + $like = $like['Like']; + $likesUserConditions['like_id'] = $like['id']; + $like['disabled'] = $this->LikesUser->find('count', [ + 'conditions' => $likesUserConditions, + 'recursive' => -1, + ]); + unset($like['id']); + $likes[$condsStr] = $like; + } + } + + $this->set('likes', $likes); + $this->set('_serialize', ['likes']); + } + +/** + * save + * + * @return void + */ + public function save() { if (! $this->request->is('post')) { return $this->throwBadRequest(); } diff --git a/Model/LikesAppModel.php b/Model/LikesAppModel.php index 1d3dc29..93ab7c8 100644 --- a/Model/LikesAppModel.php +++ b/Model/LikesAppModel.php @@ -4,6 +4,7 @@ * * @author Noriko Arai * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project @@ -19,4 +20,10 @@ */ class LikesAppModel extends AppModel { +/** + * CDNを無効にする + * + * @var bool + */ + public $invalidateCDN = false; } diff --git a/Test/Case/Controller/LikesControllerTest.php b/Test/Case/Controller/LikesControllerTest.php index f46c1e0..159863c 100644 --- a/Test/Case/Controller/LikesControllerTest.php +++ b/Test/Case/Controller/LikesControllerTest.php @@ -4,6 +4,7 @@ * * @author Noriko Arai * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project @@ -15,6 +16,7 @@ * LikesController Test Case * * @author Shohei Nakajima + * @author Kazunori Sakamoto * @package NetCommons\Likes\Test\Case\Controller * @SuppressWarnings(PHPMD.LongVariable) */ @@ -109,7 +111,7 @@ public function testLikeGet($urlOptions, $assert, $exception = null, $return = ' $url = Hash::merge(array( 'plugin' => $this->plugin, 'controller' => $this->_controller, - 'action' => 'like', + 'action' => 'save', ), $urlOptions); $this->_testGetAction($url, $assert, $exception, $return); @@ -151,7 +153,7 @@ public function dataProviderLikeGet() { * @return void */ public function testLikePost($data, $urlOptions, $exception = null, $return = 'json') { - $this->_testPostAction('post', $data, Hash::merge(array('action' => 'like'), $urlOptions), $exception, $return); + $this->_testPostAction('post', $data, Hash::merge(array('action' => 'save'), $urlOptions), $exception, $return); } /** @@ -193,7 +195,7 @@ public function dataProviderLikePost() { public function testLikeExists() { $data = $this->dataProviderLikePost()[2]['data']; - $this->_testPostAction('post', $data, array('action' => 'like'), null, 'json'); + $this->_testPostAction('post', $data, array('action' => 'save'), null, 'json'); $this->generateNc(Inflector::camelize($this->_controller)); @@ -201,7 +203,7 @@ public function testLikeExists() { TestAuthGeneral::login($this); $this->_mockForReturnTrue('Likes.Like', 'saveLike', 0); - $this->_testPostAction('post', $data, array('action' => 'like'), null, 'json'); + $this->_testPostAction('post', $data, array('action' => 'save'), null, 'json'); } } diff --git a/Test/Case/Model/Like/ExistsLikeTest.php b/Test/Case/Model/Like/ExistsLikeTest.php index eb602d0..4dde930 100644 --- a/Test/Case/Model/Like/ExistsLikeTest.php +++ b/Test/Case/Model/Like/ExistsLikeTest.php @@ -1,11 +1,12 @@ * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project @@ -14,9 +15,10 @@ App::uses('NetCommonsModelTestCase', 'NetCommons.TestSuite'); /** - * Like::ExistLike()のテスト + * Like::existsLike()のテスト * * @author Shohei Nakajima + * @author Kazunori Sakamoto * @package NetCommons\Likes\Test\Case\Model\Like */ class LikeExistsLikeTest extends NetCommonsModelTestCase { @@ -56,7 +58,7 @@ class LikeExistsLikeTest extends NetCommonsModelTestCase { * existsLikeのテスト * * @param array $contentKey キー情報 - * @param string $expected 期待値 + * @param bool $expected 期待値 * @param int $userId ユーザーID * @dataProvider dataProviderExistsLike * @return void @@ -85,9 +87,9 @@ public function testExistsLike($contentKey, $expected, $userId = 0) { */ public function dataProviderExistsLike() { return array( - array('aaa', 0), - array('testcontent', 0), - array('testcontent', 1, 1), + array('aaa', false), + array('testcontent', false), + array('testcontent', true, 1), ); } diff --git a/Test/Case/View/Helper/ButtonsTest.php b/Test/Case/View/Helper/ButtonsTest.php index 837c65b..baf1f6e 100644 --- a/Test/Case/View/Helper/ButtonsTest.php +++ b/Test/Case/View/Helper/ButtonsTest.php @@ -65,11 +65,11 @@ public function tearDown() { public function testButtons($model, $setting, $content) { $result = $this->Like->buttons('Content', $setting, $content); - if ($content['Content']['status'] === WorkflowComponent::STATUS_PUBLISHED && $setting['use_like'] === 1) { - $this->assertContains('assertNotContains('assertContains('assertNotContains('assertContains('glyphicon glyphicon-thumbs-up', $result); } else { diff --git a/Test/Case/View/Helper/DisplayTest.php b/Test/Case/View/Helper/DisplayTest.php index 5b67d22..3970143 100644 --- a/Test/Case/View/Helper/DisplayTest.php +++ b/Test/Case/View/Helper/DisplayTest.php @@ -4,6 +4,7 @@ * * @author Noriko Arai * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project @@ -17,6 +18,7 @@ * Display for LikeHelper Test Case * * @author Shohei Nakajima + * @author Kazunori Sakamoto * @package NetCommons\Likes\Test\Case\View\Helper */ class LikeHelperDisplayTest extends NetCommonsCakeTestCase { @@ -61,7 +63,7 @@ public function tearDown() { * @return void */ public function testDisplay($setting, $content) { - $result = $this->Like->display($setting, $content); + $result = $this->Like->display('Video', $setting, $content); if ($setting['use_like'] === 1) { $this->assertContains('glyphicon glyphicon-thumbs-up', $result); diff --git a/View/Elements/like_button.ctp b/View/Elements/like_button.ctp index 91171fb..ba3b013 100644 --- a/View/Elements/like_button.ctp +++ b/View/Elements/like_button.ctp @@ -3,26 +3,31 @@ * Like button view template * * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project */ ?> - - - {{options.likeCount}} - - {{options.unlikeCount}} - - - - - - {{options.likeCount}} - - {{options.unlikeCount}} - + diff --git a/View/Helper/LikeHelper.php b/View/Helper/LikeHelper.php index 58af0d9..e27f8af 100644 --- a/View/Helper/LikeHelper.php +++ b/View/Helper/LikeHelper.php @@ -4,6 +4,7 @@ * * @author Noriko Arai * @author Shohei Nakajima + * @author Kazunori Sakamoto * @link http://www.netcommons.org NetCommons Project * @license http://www.netcommons.org/license.txt NetCommons License * @copyright Copyright 2014, NetCommons Project @@ -22,6 +23,7 @@ class_exists('Like'); * * イイネ!、ヤダネ!ボタン表示:[buttonsメソッド](#buttons) * * @author Shohei Nakajima + * @author Kazunori Sakamoto * @package NetCommons\Likes\View\Helper */ class LikeHelper extends AppHelper { @@ -31,13 +33,14 @@ class LikeHelper extends AppHelper { * * @var array */ - public $helpers = array( + public $helpers = [ 'Html', 'Form', + 'NetCommons.CDNCache', 'NetCommons.NetCommonsForm', 'NetCommons.NetCommonsHtml', 'NetCommons.Token', - ); + ]; /** * Before render callback. beforeRender is called before the view file is rendered. @@ -138,33 +141,43 @@ public function setting($likeFieldName, $unlikeFieldName, $attributes = array()) * #### Sample code * ##### template file(ctp file) * ``` - * Like->display($bbsSetting, $bbsArticle); ?> + * Like->display('BbsArticle', $bbsSetting, $bbsArticle); ?> * ``` * + * @param array $model String of model name * @param array $setting Array of use like setting data. * @param array $content Array of content data with like count. * @param array $attributes Array of attributes and HTML arguments. * @return string HTML tags */ - public function display($setting, $content, $attributes = array()) { + public function display($model, $setting, $content, $attributes = array()) { $output = ''; + $condsStr = $this->_View->request->params['plugin'] . '-' . + Current::read('Block.key') . '-' . ($content[$model]['key'] ?? ''); + + $like = $this->__getInitialLike($content); + //いいね if (isset($setting['use_like']) && $setting['use_like']) { - $element = ' '; - $element .= (int)Hash::get($content, 'Like.like_count'); + $element = ''; $output .= $this->Html->div( - array('like-icon', 'text-muted'), $element, $attributes - ); + array('like-icon', 'text-muted'), $element, $attributes + ); } //わるいね if (isset($setting['use_unlike']) && $setting['use_unlike']) { - $element = ' '; - $element .= (int)Hash::get($content, 'Like.unlike_count'); + $element = ''; $output .= $this->Html->div( - array('like-icon', 'text-muted'), $element, $attributes - ); + array('like-icon', 'text-muted'), $element, $attributes + ); } return $output; @@ -193,13 +206,12 @@ public function display($setting, $content, $attributes = array()) { public function buttons($model, $setting, $content, $attributes = array()) { $output = ''; - if (! Hash::get($setting, 'use_like') && ! Hash::get($setting, 'use_like')) { + if (! Hash::get($setting, 'use_like') && ! Hash::get($setting, 'use_unlike')) { return $output; } - if (isset($content['LikesUser']['id']) || - $content[$model]['status'] !== WorkflowComponent::STATUS_PUBLISHED) { - return $this->display($setting, $content, $attributes); + if ($content[$model]['status'] !== WorkflowComponent::STATUS_PUBLISHED) { + return $this->display($model, $setting, $content, $attributes); } if (! isset($content['Like']['id'])) { @@ -217,51 +229,53 @@ public function buttons($model, $setting, $content, $attributes = array()) { ); } - $data = array( - 'Frame' => array('id' => Current::read('Frame.id')), - 'Like' => array( + $data = [ + 'Frame' => ['id' => Current::read('Frame.id')], + 'Like' => [ 'plugin_key' => Hash::get($content, 'Like.plugin_key'), 'block_key' => Hash::get($content, 'Like.block_key'), 'content_key' => Hash::get($content, 'Like.content_key'), - ), - 'LikesUser' => array( + ], + 'LikesUser' => [ 'like_id' => Hash::get($content, 'LikesUser.like_id'), 'user_id' => Hash::get($content, 'LikesUser.user_id'), 'is_liked' => Hash::get($content, 'LikesUser.is_liked'), - ), - ); - $options = array( - 'likeCount' => (int)Hash::get($content, 'Like.like_count'), - 'unlikeCount' => (int)Hash::get($content, 'Like.unlike_count'), - 'disabled' => false - ); + ], + ]; $tokenFields = Hash::flatten($data); $hiddenFields = $tokenFields; unset($hiddenFields['LikesUser.is_liked']); $hiddenFields = array_keys($hiddenFields); - $cunnentData = $this->_View->request->data; + $currentData = $this->_View->request->data; $this->_View->request->data = $data; - $tokens = $this->Token->getToken('Like', '/likes/likes/like.json', $tokenFields, $hiddenFields); - $data += $tokens; + $token = $this->Token->getToken( + 'LikeSave', '/likes/likes/save.json', $tokenFields, $hiddenFields + ); + $data += $token; + + $this->_View->request->data = $currentData; + + $like = $content['Like']; + $condsStr = $like['plugin_key'] . '-' . $like['block_key'] . '-' . $like['content_key']; - $this->_View->request->data = $cunnentData; + $like = $this->__getInitialLike($content); $output .= ''; @@ -269,4 +283,25 @@ public function buttons($model, $setting, $content, $attributes = array()) { return $output; } +/** + * Ajaxの実行前に表示すべきいいね情報を返します。 + * + * @param array $content Array of content data with like count. + * @return array + */ + private function __getInitialLike($content) { + if ($this->CDNCache->isCacheable()) { + return [ + 'like_count' => '-', + 'unlike_count' => '-', + 'disabled' => true, + ]; + } + $like = $content['Like']; + return [ + 'like_count' => Hash::get($like, 'like_count', 0), + 'unlike_count' => Hash::get($like, 'unlike_count', 0), + 'disabled' => $content['LikesUser']['is_liked'], + ]; + } } diff --git a/webroot/js/likes.js b/webroot/js/likes.js index bd2708c..f896df6 100644 --- a/webroot/js/likes.js +++ b/webroot/js/likes.js @@ -1,6 +1,7 @@ /** * @fileoverview Likes Javascript * @author nakajimashouhei@gmail.com (Shohei Nakajima) + * @author exkazuu@willbooster.com (Kazunori Sakamoto) */ @@ -11,39 +12,38 @@ * @param {function('$http', '$q')} Controller */ NetCommonsApp.factory('LikesSave', ['$http', '$q', 'NC3_URL', function($http, $q, NC3_URL) { - return function(post) { - + return function(data) { var deferred = $q.defer(); var promise = deferred.promise; $http.get(NC3_URL + '/net_commons/net_commons/csrfToken.json') .then(function(response) { var token = response.data; - post._Token.key = token.data._Token.key; + data._Token.key = token.data._Token.key; - //POSTリクエスト + // POSTリクエスト $http.post( - NC3_URL + '/likes/likes/like.json', - $.param({_method: 'POST', data: post}), - {cache: false, - headers: - {'Content-Type': 'application/x-www-form-urlencoded'} + NC3_URL + '/likes/likes/save.json', + $.param({_method: 'POST', data: data}), + { + cache: false, + headers: {'Content-Type': 'application/x-www-form-urlencoded'} } ).then( - function(response) { - //success condition + function(response) { + // success condition var data = response.data; deferred.resolve(data); }, - function(response) { - //error condition + function(response) { + // error condition var data = response.data; var status = response.status; deferred.reject(data, status); }); }, function(response) { - //Token error condition + // Token error condition var data = response.data; var status = response.status; deferred.reject(data, status); @@ -79,16 +79,6 @@ NetCommonsApp.controller('Likes', ['$scope', 'LikesSave', function($scope, Likes */ $scope.data = null; - /** - * Options parameters - * - disabled - * - likeCounts - * - unlikeCounts - * - * @type {object} - */ - $scope.options = null; - /** * initialize * - disabled @@ -97,10 +87,8 @@ NetCommonsApp.controller('Likes', ['$scope', 'LikesSave', function($scope, Likes * * @return {void} */ - $scope.initialize = function(data, options) { + $scope.initialize = function(data) { $scope.data = data; - $scope.options = options; - $scope.options.disabled = false; }; /** @@ -108,27 +96,28 @@ NetCommonsApp.controller('Likes', ['$scope', 'LikesSave', function($scope, Likes * * @return {void} */ - $scope.save = function(isLiked) { - $scope.data['LikesUser']['is_liked'] = isLiked; - if ($scope.options.disabled) { - return; - } - $scope.options.disabled = true; - $scope.sending = true; + $scope.save = function(isLiked, condsStr) { + var queryPrefix = '.' + condsStr; + var aDisplay = $(queryPrefix + ' > a').css('display'); + var spanDisplay = $(queryPrefix + ' > span').css('display'); + + $(queryPrefix + ' > a').css('display', 'none'); + $(queryPrefix + ' > span').css('display', ''); + $scope.data.LikesUser.is_liked = isLiked; LikesSave($scope.data) - .success(function(data) { - $scope.sending = false; - //success condition + .success(function() { + var $counts; if (isLiked) { - $scope.options['likeCount'] = $scope.options['likeCount'] + 1; + $counts = $(queryPrefix + ' .like-count'); } else { - $scope.options['unlikeCount'] = $scope.options['unlikeCount'] + 1; + $counts = $(queryPrefix + ' .unlike-count'); } + $counts.each(function() { $(this).text(Number($(this).text()) + 1); }); }) - .error(function(data, status) { - //error condition - $scope.sending = false; + .error(function() { + $(queryPrefix + ' > a').css('display', aDisplay); + $(queryPrefix + ' > span').css('display', spanDisplay); }); }; }]);