diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..592d72f --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,59 @@ +on: + push: + # Sequence of patterns matched against refs/tags + tags: + - '3*' + +name: create_release + +jobs: + build: + name: create_release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Slack Notification on Start + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_RELEASE }} + SLACK_CHANNEL: notify-nc3-release + SLACK_TITLE: "${{ github.repository }}" + SLACK_COLOR: "#f0ad4e" + SLACK_MESSAGE: "Start Job" + + - name: Create Release + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token + with: + tag_name: ${{ github.ref }} + release_name: ${{ github.ref }} + body: | + NetCommons ${{ github.ref }} released. + draft: false + prerelease: false + + # テスト成功時はこちらのステップが実行される + - name: Slack Notification on Finish + uses: rtCamp/action-slack-notify@v2.2.0 + if: success() + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_RELEASE }} + SLACK_CHANNEL: notify-nc3-release + SLACK_TITLE: "${{ github.repository }}" + SLACK_COLOR: good + SLACK_MESSAGE: "Job Success" + + # テスト失敗時はこちらのステップが実行される + - name: Slack Notification on Failure + uses: rtCamp/action-slack-notify@v2.2.0 + if: failure() + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_RELEASE }} + SLACK_CHANNEL: notify-nc3-tests + SLACK_TITLE: "${{ github.repository }}" + SLACK_COLOR: danger + SLACK_MESSAGE: "Job Failure" diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000..eb2068b --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,170 @@ +on: + push: + branches: + - main + - master + - availability + pull_request: + branches: + - main + - master + - availability + +name: tests + +jobs: + setup: + name: setup + runs-on: ubuntu-latest + steps: + - name: Slack Notification on Start + uses: rtCamp/action-slack-notify@v2.2.0 + if: env.SLACK_WEBHOOK != '' + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_TESTS }} + SLACK_CHANNEL: notify-nc3-tests + SLACK_TITLE: "${{ github.repository }}" + SLACK_COLOR: "#f0ad4e" + + tests: + name: tests + needs: setup + runs-on: ubuntu-latest + strategy: + matrix: + php: [ '7.1', '7.2', '7.3', '7.4' ] + mysql: [ '5.7', '8.0' ] + + env: + NC3_BUILD_DIR: "/opt/nc3" + NC3_DOCKER_DIR: "/opt/docker" + NC3_GIT_URL: "git://github.com/NetCommons3/NetCommons3.git" + NC3_GIT_BRANCH: "master" + PLUGIN_BUILD_DIR: ${{ github.workspace }} + PHP_VERSION: ${{ matrix.php }} + MYSQL_VERSION: ${{ matrix.mysql }} + MYSQL_ROOT_PASSWORD: root + MYSQL_DATABASE: cakephp_test + COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + steps: + - uses: actions/checkout@v2 + + - name: Fix up git URLs + run: echo -e '[url "https://github.com/"]\n insteadOf = "git://github.com/"' >> ~/.gitconfig + + - name: environment + run: | + echo "GITHUB_WORKSPACE=${GITHUB_WORKSPACE}" + echo "PLUGIN_BUILD_DIR=${PLUGIN_BUILD_DIR}" + echo "PHP_VERSION=${PHP_VERSION}" + echo "MYSQL_VERSION=${MYSQL_VERSION}" + ls -al ${PLUGIN_BUILD_DIR} + + - name: docker-compose install + run: | + curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > ~/docker-compose + chmod +x ~/docker-compose + sudo mv ~/docker-compose /usr/local/bin/docker-compose + docker-compose --version + + - name: git clone nc3 + run: git clone -b ${NC3_GIT_BRANCH} ${NC3_GIT_URL} ${NC3_BUILD_DIR} + + - name: git clone nc3_docker + run: git clone https://github.com/NetCommons3/nc3app-docker.git ${NC3_DOCKER_DIR} + + - name: docker-compose start + run: | + cd ${NC3_DOCKER_DIR} + docker-compose up -d + docker-compose start + + - run: docker ps + + - name: check libraries + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/start-on-docker.sh + + - name: nc3 build + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/app-build.sh + + - name: phpcs (PHP CodeSniffer) + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/phpcs.sh + + - name: phpmd (PHP Mess Detector) + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/phpmd.sh + + - name: phpcpd (PHP Copy/Paste Detector) + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/phpcpd.sh + + - name: gjslint (JavaScript Style Check) + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/gjslint.sh + + - name: phpdoc (PHP Documentor) + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/phpdoc.sh + + - name: phpunit (PHP UnitTest) + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose exec -T nc3app bash /opt/scripts/phpunit.sh + sudo -s chmod a+w -R ${NC3_BUILD_DIR}/build + +# - name: push coveralls +# env: +# COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} +# COVERALLS_FLAG_NAME: ${{ matrix.php }} +# run: | +# cd ${NC3_BUILD_DIR} +# ls -la ${NC3_BUILD_DIR} +# vendors/bin/php-coveralls --coverage_clover=build/logs/clover.xml -v + + - name: docker-compose remove + if: always() + run: | + cd ${NC3_DOCKER_DIR} + docker-compose rm -f + + # テスト失敗時はこちらのステップが実行される + - name: Slack Notification on Failure + uses: rtCamp/action-slack-notify@v2.2.0 + if: env.SLACK_WEBHOOK != '' && failure() + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_TESTS }} + SLACK_CHANNEL: notify-nc3-tests + SLACK_TITLE: "${{ github.repository }}(php${{ matrix.php }}, mysql${{ matrix.mysql }})" + SLACK_COLOR: danger + + teardown: + name: teardown + runs-on: ubuntu-latest + needs: tests + steps: + # テスト成功時はこちらのステップが実行される + - name: Slack Notification on Success + uses: rtCamp/action-slack-notify@v2.2.0 + if: env.SLACK_WEBHOOK != '' && success() + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK_TESTS }} + SLACK_CHANNEL: notify-nc3-tests + SLACK_TITLE: "${{ github.repository }}" + SLACK_COLOR: good diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index af3b7b8..0000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: php - -php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 - - 7.1 - -sudo: false - -env: - matrix: - - NETCOMMONS_VERSION=master DB=mysql - global: - - secure: "mF+LYvAgZauto0g3knD6wqd3wz3TEiIFEc1IhJDHWsqSjTr371xxk8n1RmrbqoRYpcRutxBtdItvp531SbLjyuo7WJ/yW4VG9k0vh8p1Vxa6x9OreqFmwibDCtO0qwewrqNJzsH4ktPlWracMv6tLNdIJyEhmp8zLQ7etzmoAJ+YGwI7Jtib7r2Mrrplfyf/AK7Vn59QNIKV33vZ7FhCPON6+N2gsuvDG2qS0ulrc/SKujXHyVfaVB7j3ZEQNpuaZC5ZANl5y3FbsgpjUWJPjAt+O9o4Xq+rFGzaoVGsB5IwRLIDiNQye4tgvFDKWzEruslGtfXxOFbOAeD9og+jSoACQ62/vzNwzp8J68+ppDtY0KPp9iOMjAivErv/niF0Ed7059tjR3Z5fyZBr1mxPXY6v3ZKlJ+1IKy+sJcSho/rGhBrfQW8UOMzi08O/ZrXyMMeCZuqByR8BGQtLmEmNZGt0fIGBV4L3NlGG6KaBHUJVpfru2rHkSjM6u1/+v5YUt5f79eyt+BnVNaaTx0Tn8HbE9tcouk2h4VeocGHpskO0oHx5kcxNRJ0Tj9oiJZ0zcRrU0K1ulpLaUAVvszqPTbV88U5UoaggJ987SAeM3xrhG0yBHvrG0gRQfJ5BUouVehadEVEWBgD37UIhKnd8rC2uISwXfxYxaoi2UiqJvM=" - - GIT_COMMITTER_NAME=RyujiAMANO - - GIT_COMMITTER_EMAIL=ryuji@ryus.co.jp - - GIT_AUTHOR_NAME=RyujiAMANO - - GIT_AUTHOR_EMAIL=ryuji@ryus.co.jp - -before_script: - - export NETCOMMONS_BUILD_DIR=`dirname $TRAVIS_BUILD_DIR`/NetCommons3 - - git clone git://github.com/NetCommons3/NetCommons3 $NETCOMMONS_BUILD_DIR - - cd $NETCOMMONS_BUILD_DIR - - git checkout $NETCOMMONS_VERSION - - travis_wait . tools/build/plugins/cakephp/travis/pre.sh - - . tools/build/plugins/cakephp/travis/environment.sh - -script: - - . tools/build/plugins/cakephp/travis/main.sh - -after_script: - - . tools/build/plugins/cakephp/travis/post.sh - -notifications: - email: - recipients: - - netcommons3@googlegroups.com - on_success: never # default: change - on_failure: always # default: always diff --git a/Controller/CabinetFilesController.php b/Controller/CabinetFilesController.php index ae9d80e..352d9e5 100644 --- a/Controller/CabinetFilesController.php +++ b/Controller/CabinetFilesController.php @@ -100,7 +100,8 @@ public function beforeFilter() { 'view', 'folder_detail', 'download', - 'download_folder' + 'download_folder', + 'check_download_folder' ); parent::beforeFilter(); $this->_cabinet = $this->Cabinet->find('first', array( @@ -271,8 +272,6 @@ public function download() { //$this->set('cabinetFile', $cabinetFile); // ここまで元コンテンツを取得する処理 - //$this->AuthorizationKey->guard('popup', 'BlogEntry', $blogEntry); - $this->AuthorizationKey->guard('popup', 'CabinetFile', $cabinetFile); // ダウンロード実行 @@ -297,8 +296,11 @@ public function download() { * @return CakeResponse|string|void */ public function download_folder() { + if (! $this->request->is('post')) { + return $this->throwBadRequest(); + } // フォルダを取得 - $folderKey = Hash::get($this->request->params, 'key', null); + $folderKey = Hash::get($this->request->data, 'CabinetFile.key', null); $conditions = [ 'CabinetFile.key' => $folderKey, 'CabinetFile.cabinet_key' => $this->_cabinet['Cabinet']['key'] @@ -309,10 +311,12 @@ public function download_folder() { $tmpFolder = new TemporaryFolder(); try { $this->_prepareDownload($tmpFolder->path, $cabinetFolder); - } catch (Exception $e) { - $this->set('error', $e->getMessage()); - - return; + } catch (BadRequestException $e) { + //先にcheck_download_folderでチェックしているため、この処理は基本通らない + //もしタイムラグでダウンロードパスワードが設定されたら、フラッシュメッセージを表示して、 + //ブラウザをリフレッシュする + $this->NetCommons->setFlashNotification($e->getMessage(), [], $e->getCode()); + return $this->redirect($this->referer()); } $zipDownloader = $this->_getZipDownloader(); @@ -323,23 +327,37 @@ public function download_folder() { foreach ($files as $file) { $zipDownloader->addFile($file); } + return $zipDownloader->download($cabinetFolder['CabinetFile']['filename'] . '.zip'); + } - //$zipDownloader->addFolder($tmpFolder->path); +/** + * フォルダのZIPダウンロードができるか否かチェック + * + * @return void + */ + public function check_download_folder() { + if (! $this->request->is('post') || ! $this->request->is('ajax')) { + return $this->throwBadRequest(); + } + // フォルダを取得 + $folderKey = Hash::get($this->request->data, 'CabinetFile.key', null); + $conditions = [ + 'CabinetFile.key' => $folderKey, + 'CabinetFile.cabinet_key' => $this->_cabinet['Cabinet']['key'] + ]; + $conditions = $this->CabinetFile->getWorkflowConditions($conditions); + $cabinetFolder = $this->CabinetFile->find('first', ['conditions' => $conditions]); - //$this->response = $zipDownloader->download($cabinetFolder['CabinetFile']['filename'] . '.zip'); - //return $this->response; - return $zipDownloader->download($cabinetFolder['CabinetFile']['filename'] . '.zip'); + $this->_checkDownloadFolder($cabinetFolder); } /** - * フォルダのZIPダウンロード前処理 + * 圧縮ダウンロード用のCabinetFileデータを取得 * - * @param string $path ダウンロード処理用テンポラリフォルダのカレントパス * @param array $cabinetFolder CabinetFileデータ 処理するフォルダ - * @throws Exception - * @return void + * @return array */ - protected function _prepareDownload($path, $cabinetFolder) { + protected function _findCabinetFilesByFolderDownload($cabinetFolder) { // フォルダのファイル取得 $files = $this->CabinetFile->find( 'all', @@ -352,13 +370,27 @@ protected function _prepareDownload($path, $cabinetFolder) { ) ] ); + return $files; + } + +/** + * フォルダのZIPダウンロード前処理 + * + * @param string $path ダウンロード処理用テンポラリフォルダのカレントパス + * @param array $cabinetFolder CabinetFileデータ 処理するフォルダ + * @throws BadRequestException + * @return void + */ + protected function _prepareDownload($path, $cabinetFolder) { + // フォルダのファイル取得 + $files = $this->_findCabinetFilesByFolderDownload($cabinetFolder); foreach ($files as $file) { if ($file['CabinetFile']['is_folder']) { mkdir($path . DS . $file['CabinetFile']['filename']); $this->_prepareDownload($path . DS . $file['CabinetFile']['filename'], $file); } else { if (isset($file['AuthorizationKey'])) { - throw new Exception( + throw new BadRequestException( __d( 'cabinets', 'Folder that contains the files that are password is set can not be downloaded ZIP.' @@ -375,7 +407,32 @@ protected function _prepareDownload($path, $cabinetFolder) { // $file['UploadFile']['file']['id'] . // DS . $file['UploadFile']['file']['real_file_name']; copy($filePath, $path . DS . $file['CabinetFile']['filename']); + } + } + } +/** + * フォルダのZIPダウンロードができるか否かチェックする + * + * @param array $cabinetFolder CabinetFileデータ 処理するフォルダ + * @throws BadRequestException + * @return void + */ + protected function _checkDownloadFolder($cabinetFolder) { + // フォルダのファイル取得 + $files = $this->_findCabinetFilesByFolderDownload($cabinetFolder); + foreach ($files as $file) { + if ($file['CabinetFile']['is_folder']) { + $this->_checkDownloadFolder($file); + } else { + if (isset($file['AuthorizationKey'])) { + throw new BadRequestException( + __d( + 'cabinets', + 'Folder that contains the files that are password is set can not be downloaded ZIP.' + ) + ); + } } } } @@ -392,6 +449,10 @@ protected function _getCurrentFolder($folderKey) { $currentFolder = $this->CabinetFile->getRootFolder($this->_cabinet); return $currentFolder; } else { + // Hack: findFolderとかメソッドはやしたほうがいいかな。CabinetFolderってモデルつくるのがいいか? + $this->CabinetFile->Behaviors->disable('AuthorizationKey'); + $this->CabinetFile->Behaviors->disable('Attachment'); + $currentFolder = $this->CabinetFile->find( 'first', [ @@ -402,6 +463,8 @@ protected function _getCurrentFolder($folderKey) { ] ] ); + $this->CabinetFile->Behaviors->enable('AuthorizationKey'); + $this->CabinetFile->Behaviors->enable('Attachment'); return $currentFolder; } } diff --git a/Controller/CabinetFilesEditController.php b/Controller/CabinetFilesEditController.php index 1aa50d2..39758fb 100644 --- a/Controller/CabinetFilesEditController.php +++ b/Controller/CabinetFilesEditController.php @@ -39,7 +39,7 @@ class CabinetFilesEditController extends CabinetsAppController { 'NetCommons.Permission' => array( //アクセスの権限 'allow' => array( - 'add,edit,delete,move' => 'content_creatable', + 'add,edit,delete,move,get_folder_path,select_folder' => 'content_creatable', // フォルダの作成・編集は公開権限以上 'add_folder,edit_folder' => 'content_publishable', 'unzip' => 'content_publishable' @@ -63,6 +63,11 @@ class CabinetFilesEditController extends CabinetsAppController { //'Likes.Like', ); +/** + * @var array Cabinet + */ + protected $_cabinet; + /** * beforeFilter * @@ -108,9 +113,9 @@ private function __getParentFolderUrl($parentId) { * @return void */ public function add() { - //レイアウトの設定 - $this->viewClass = 'View'; - $this->layout = 'NetCommons.modal'; + if (!$this->__isExistsParentFolder()) { + return $this->throwBadRequest(); + } $this->set('isEdit', false); @@ -152,6 +157,7 @@ public function add() { $this->NetCommons->handleValidationError($this->CabinetFile->validationErrors); } else { + $this->layout = 'NetCommons.modal'; $this->request->data = $cabinetFile; $this->request->data['CabinetFileTree']['parent_id'] = Hash::get( $this->request->named, @@ -269,7 +275,8 @@ public function edit() { $this->set('cabinetFile', $cabinetFile); $this->set('isDeletable', $this->CabinetFile->canDeleteWorkflowContent($cabinetFile)); - $this->render('form'); + $this->view = 'form'; + //$this->render('form'); } /** @@ -278,6 +285,10 @@ public function edit() { * @return void */ public function add_folder() { + if (!$this->__isExistsParentFolder()) { + return $this->throwBadRequest(); + } + $this->set('isEdit', false); $cabinetFile = $this->CabinetFile->getNew(); @@ -337,7 +348,8 @@ public function add_folder() { ]; $this->set('folderPath', $folderPath); - $this->render('folder_form'); + $this->view = 'folder_form'; + //$this->render('folder_form'); } /** @@ -367,7 +379,7 @@ public function edit_folder() { throw new InternalErrorException(); } if ($this->CabinetFile->canEditWorkflowContent($cabinetFile) === false) { - throw new ForbiddenException(__d('net_commons', 'Permission denied')); + throw new ForbiddenException(); } $treeId = $cabinetFile['CabinetFileTree']['id']; @@ -417,7 +429,8 @@ public function edit_folder() { $this->set('cabinetFile', $cabinetFile); $this->set('isDeletable', $this->CabinetFile->canDeleteWorkflowContent($cabinetFile)); - $this->render('folder_form'); + $this->view = 'folder_form'; + //$this->render('folder_form'); } /** @@ -516,7 +529,7 @@ public function move() { // フォルダの移動は公開権限が必要 if ($cabinetFile['CabinetFile']['is_folder']) { if (!Current::permission('content_publishable')) { - throw new ForbiddenException(__d('net_commons', 'Permission denied')); + throw new ForbiddenException(); } } @@ -691,4 +704,17 @@ protected function _isAllowUnzip($cabinetFile) { return true; } + +/** + * __isExistsParentFolder + * + * @return bool + */ + private function __isExistsParentFolder() { + $parentId = $this->request->data['CabinetFileTree']['parent_id'] ?? Hash::get( + $this->request->named, + 'parent_id' + ); + return $this->CabinetFile->isExistsByTreeId($this->_cabinet['Cabinet']['key'], $parentId); + } } diff --git a/Model/Behavior/CabinetFolderBehavior.php b/Model/Behavior/CabinetFolderBehavior.php index 46d6f89..1d9af31 100644 --- a/Model/Behavior/CabinetFolderBehavior.php +++ b/Model/Behavior/CabinetFolderBehavior.php @@ -41,7 +41,14 @@ public function hasChildren(Model $model, $cabinetFile) { 'CabinetFileTree.parent_id' => $cabinetFile['CabinetFileTree']['id'], ]; $conditions = $model->getWorkflowConditions($conditions); + + $model->Behaviors->disable('AuthorizationKey'); + $model->Behaviors->disable('Attachment'); + $count = $model->find('count', ['conditions' => $conditions]); + + $model->Behaviors->enable('AuthorizationKey'); + $model->Behaviors->enable('Attachment'); return ($count > 0); } @@ -53,7 +60,10 @@ public function hasChildren(Model $model, $cabinetFile) { * @return array|null */ public function getRootFolder(Model $model, $cabinet) { - return $model->find('first', [ + $model->Behaviors->disable('AuthorizationKey'); + $model->Behaviors->disable('Attachment'); + + $rootFolder = $model->find('first', [ 'conditions' => $this->_getRootFolderConditions( $cabinet, array( @@ -64,6 +74,11 @@ public function getRootFolder(Model $model, $cabinet) { ) ) ]); + + $model->Behaviors->enable('AuthorizationKey'); + $model->Behaviors->enable('Attachment'); + + return $rootFolder; } /** @@ -173,9 +188,7 @@ public function rootFolderExist(Model $model, $cabinet) { * @return int 合計サイズ */ public function getTotalSizeByFolder(Model $model, $folder) { - // ベタパターン - // 配下全てのファイルを取得する - //$this->CabinetFileTree->setup(]); + // 配下全てのファイル key を取得する $cabinetKey = $folder['Cabinet']['key']; $conditions = [ 'CabinetFileTree.cabinet_key' => $cabinetKey, @@ -183,13 +196,52 @@ public function getTotalSizeByFolder(Model $model, $folder) { 'CabinetFileTree.rght <' => $folder['CabinetFileTree']['rght'], 'CabinetFile.is_folder' => false, ]; - $files = $model->find('all', ['conditions' => $conditions]); - $total = 0; - foreach ($files as $file) { - $total += Hash::get($file, 'UploadFile.file.size', 0); + $model->Behaviors->disable('AuthorizationKey'); + + // HACK: ファイルサイズをCabinetsに持つようにすればFilesプラグインのテーブルを参照する必要はなくなるが、 + // テーブル変更すると移行ツールも改修する必要があるので、 + // ひとまずトータル取得ロジックのカイゼンだけにとどめた。 + $files = $model->find('all', [ + 'conditions' => $conditions, + //'fields' => ['CabinetFile.key'] + 'fields' => ['CabinetFile.id'] + ]); + $contentIds = array_column(array_column($files, 'CabinetFile'), 'id'); + if (empty($contentIds)) { + return 0; + } + + /** @var UploadFilesContent $uploadFilesContent */ + $uploadFilesContent = ClassRegistry::init('Files.UploadFilesContent'); + $conditions = [ + 'UploadFilesContent.plugin_key' => 'cabinets', + 'UploadFilesContent.content_id' => $contentIds, + ]; + $links = $uploadFilesContent->find('all', [ + 'conditions' => $conditions, + 'recursive' => -1, + 'fields' => ['UploadFilesContent.upload_file_id'] + ]); + $uploadFileIds = array_column(array_column($links, 'UploadFilesContent'), 'upload_file_id'); + if (empty($uploadFileIds)) { + return 0; } + + /** @var UploadFile $uploadFile */ + $uploadFile = ClassRegistry::init('Files.UploadFile'); + $conditions = [ + 'UploadFile.id' => $uploadFileIds + ]; + $uploadFile->virtualFields['cabinet_folder_size'] = 'sum(size)'; + $result = $uploadFile->find('first', [ + 'conditions' => $conditions, + 'fields' => ['cabinet_folder_size' ], + //'recursive' => 0 + ]); + unset($uploadFile->virtualFields['cabinet_folder_size']); + + $total = (int)$result['UploadFile']['cabinet_folder_size']; return $total; - // sumパターンはUploadFileの構造をしらないと厳しい… がんばってsumするより合計サイズをキャッシュした方がいいかも } /** @@ -224,12 +276,8 @@ public function updateCabinetTotalSize(Model $model, $cabinetKey) { 'recursive' => -1, 'conditions' => array('key' => $cabinetKey), )); + $totalSize = $this->calcCabinetTotalSize($model, $cabinet); - // トータルサイズ取得 - $rootFolder = $model->getRootFolder($cabinet); - $totalSize = $model->getTotalSizeByFolder( - $rootFolder - ); // キャビネット更新 $update = array( 'Cabinet.total_size' => $totalSize @@ -245,4 +293,20 @@ public function updateCabinetTotalSize(Model $model, $cabinetKey) { //$model->Cabinet->id = $cabinetId; //$model->Cabinet->saveField('total_size', $totalSize, ['callbacks' => false]); } + +/** + * calcCabinetTotalSize + * + * @param Model $model モデル + * @param array $cabinet Cabinetデータ + * @return mixed + */ + public function calcCabinetTotalSize(Model $model, $cabinet) { + // トータルサイズ取得 + $rootFolder = $model->getRootFolder($cabinet); + $totalSize = $model->getTotalSizeByFolder( + $rootFolder + ); + return $totalSize; + } } \ No newline at end of file diff --git a/Model/Behavior/CabinetUnzipBehavior.php b/Model/Behavior/CabinetUnzipBehavior.php index f20a367..e0234a3 100644 --- a/Model/Behavior/CabinetUnzipBehavior.php +++ b/Model/Behavior/CabinetUnzipBehavior.php @@ -25,7 +25,7 @@ public function unzip(Model $model, $cabinetFile) { try { // テンポラリフォルダにunzip - $zipPath = WWW_ROOT . $cabinetFile['UploadFile']['file']['path'] . + $zipPath = UPLOADS_ROOT . $cabinetFile['UploadFile']['file']['path'] . $cabinetFile['UploadFile']['file']['id'] . DS . $cabinetFile['UploadFile']['file']['real_file_name']; //debug($zipPath); diff --git a/Model/Cabinet.php b/Model/Cabinet.php index e2f819c..bde41d5 100644 --- a/Model/Cabinet.php +++ b/Model/Cabinet.php @@ -91,7 +91,7 @@ class Cabinet extends CabinetsAppModel { * @see Model::save() */ public function beforeValidate($options = array()) { - $this->validate = Hash::merge( + $this->validate = ValidateMerge::merge( $this->validate, array( //'block_id' => array( diff --git a/Model/CabinetFile.php b/Model/CabinetFile.php index e85ac8a..d0ebb0e 100644 --- a/Model/CabinetFile.php +++ b/Model/CabinetFile.php @@ -13,6 +13,8 @@ /** * Summary for CabinetFile Model + * + * @SuppressWarnings(PHPMD.TooManyPublicMethods) */ class CabinetFile extends CabinetsAppModel { @@ -59,6 +61,9 @@ class CabinetFile extends CabinetsAppModel { 'embedTags' => array( 'X-SUBJECT' => 'CabinetFile.filename', 'X-BODY' => 'CabinetFile.description', + 'X-URL' => array( + 'controller' => 'cabinet_files' + ) ), ), //多言語 @@ -159,7 +164,7 @@ public function beforeValidate($options = array()) { ]; } - $this->validate = Hash::merge($this->validate, $validate); + $this->validate = ValidateMerge::merge($this->validate, $validate); return parent::beforeValidate($options); } @@ -271,7 +276,8 @@ public function afterSave($created, $options = array()) { public function save($data = null, $validate = true, $fieldList = array()) { // 保存前に modified フィールドをクリアする $this->set($data); - if (isset($this->data[$this->alias]['modified'])) { + $isNoUnsetModified = Hash::get($this->data, $this->alias . '._is_no_unset_modified'); + if (isset($this->data[$this->alias]['modified']) && !$isNoUnsetModified) { unset($this->data[$this->alias]['modified']); } return parent::save($this->data, $validate, $fieldList); @@ -563,4 +569,21 @@ public function isAllowUnzip($cabinetFile) { return true; } + +/** + * isExists + * + * @param string $cabinetKey Caibnet.key + * @param string|int $cabinetFileTreeId CabinetFile.id + * @return bool + */ + public function isExistsByTreeId($cabinetKey, $cabinetFileTreeId) { + $conditions = [ + 'CabinetFile.cabinet_key' => $cabinetKey, + 'CabinetFile.cabinet_file_tree_id' => $cabinetFileTreeId, + ]; + $conditions = $this->getWorkflowConditions($conditions); + $count = $this->find('count', ['conditions' => $conditions]); + return ($count > 0); + } } diff --git a/README.md b/README.md index 9e09278..5c49a76 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,6 @@ -# Cabinets +Cabinets ======= -Cabinets for NetComomns3 - -[![Build Status](https://travis-ci.org/NetCommons3/Cabinets.svg?branch=master)](https://travis-ci.org/NetCommons3/Cabinets) -[![Coverage Status](https://img.shields.io/coveralls/NetCommons3/Cabinets.svg)](https://coveralls.io/r/NetCommons3/Cabinets?branch=master) - -| dependencies | status | -| ------------ | ------ | -| composer.json | [![Dependency Status](https://www.versioneye.com/user/projects/57060976fcd19a004543fc60/badge.svg?style=flat)](https://www.versioneye.com/user/projects/57060976fcd19a004543fc60) | - - +[![Tests Status](https://github.com/NetCommons3/Cabinets/actions/workflows/tests.yml/badge.svg?branch=master)](https://github.com/NetCommons3/Cabinets/actions/workflows/tests.yml) +[![Coverage Status](https://coveralls.io/repos/NetCommons3/Cabinets/badge.svg?branch=master)](https://coveralls.io/r/NetCommons3/Cabinets?branch=master) +[![Stable Version](https://img.shields.io/packagist/v/netcommons/cabinets.svg?label=stable)](https://packagist.org/packages/netcommons/cabinets) diff --git a/Test/Case/Config/RoutesTest.php b/Test/Case/Config/RoutesTest.php deleted file mode 100644 index 8a1a621..0000000 --- a/Test/Case/Config/RoutesTest.php +++ /dev/null @@ -1,99 +0,0 @@ - - * @author Shohei Nakajima - * @link http://www.netcommons.org NetCommons Project - * @license http://www.netcommons.org/license.txt NetCommons License - * @copyright Copyright 2014, NetCommons Project - */ - -App::uses('NetCommonsRoutesTestCase', 'NetCommons.TestSuite'); - -/** - * Config/routes.phpのテスト - * - * @author Shohei Nakajima - * @package NetCommons\Pages\Test\Case\Routing\Route\SlugRoute - */ -class RoutesTest extends NetCommonsRoutesTestCase { - -/** - * Fixtures - * - * @var array - */ - public $fixtures = array(); - -/** - * Plugin name - * - * @var string - */ - public $plugin = 'cabinets'; - -/** - * DataProvider - * - * ### 戻り値 - * - url URL - * - expected 期待値 - * - * @return array テストデータ - */ - public function dataProvider() { - return array( - array( - 'url' => '/cabinets/cabinet_files/index/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files', 'action' => 'index', - 'block_id' => '1', 'key' => 'content_key', - ) - ), - array( - 'url' => '/cabinets/cabinet_files/folder_detail/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files', 'action' => 'folder_detail', - 'block_id' => '1', 'key' => 'content_key', - ) - ), - array( - 'url' => '/cabinets/cabinet_files/view/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files', 'action' => 'view', - 'block_id' => '1', 'key' => 'content_key', - ) - ), - array( - 'url' => '/cabinets/cabinet_files/download/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files', 'action' => 'download', - 'block_id' => '1', 'key' => 'content_key', - ) - ), - array( - 'url' => '/cabinets/cabinet_files/download_folder/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files', 'action' => 'download_folder', - 'block_id' => '1', 'key' => 'content_key', - ) - ), - array( - 'url' => '/cabinets/cabinet_files_edit/edit/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files_edit', 'action' => 'edit', - 'block_id' => '1', 'key' => 'content_key' - ) - ), - array( - 'url' => '/cabinets/cabinet_files_edit/edit_folder/1/content_key', - 'expected' => array( - 'plugin' => 'cabinets', 'controller' => 'cabinet_files_edit', 'action' => 'edit_folder', - 'block_id' => '1', 'key' => 'content_key' - ) - ), - ); - } - -} diff --git a/Test/Case/Controller/CabinetBlockRolePermissionsController/EditTest.php b/Test/Case/Controller/CabinetBlockRolePermissionsController/EditTest.php index be8e932..7081417 100644 --- a/Test/Case/Controller/CabinetBlockRolePermissionsController/EditTest.php +++ b/Test/Case/Controller/CabinetBlockRolePermissionsController/EditTest.php @@ -72,7 +72,7 @@ private function __data() { 'CabinetSetting' => array( 'id' => 2, 'cabinet_key' => 'cabinet_key_2', - 'use_workflow' => true, + 'use_workflow' => '1', //'use_comment_approval' => true, //'approval_type' => true, ) diff --git a/Test/Case/Controller/CabinetBlocksController/EditTest.php b/Test/Case/Controller/CabinetBlocksController/EditTest.php index 8e183eb..48005a4 100644 --- a/Test/Case/Controller/CabinetBlocksController/EditTest.php +++ b/Test/Case/Controller/CabinetBlocksController/EditTest.php @@ -65,8 +65,8 @@ private function __data($isEdit) { $frameId = '6'; //$frameKey = 'frame_3'; if ($isEdit) { - $blockId = '4'; - $blockKey = 'block_2'; + $blockId = '2'; + $blockKey = 'block_1'; $cabinetId = '3'; $cabinetKey = 'cabinet_key_2'; } else { diff --git a/Test/Case/Controller/CabinetFilesController/DownloadFolderTest.php b/Test/Case/Controller/CabinetFilesController/DownloadFolderTest.php index ee2837d..fff8a3d 100644 --- a/Test/Case/Controller/CabinetFilesController/DownloadFolderTest.php +++ b/Test/Case/Controller/CabinetFilesController/DownloadFolderTest.php @@ -84,9 +84,9 @@ public function testDownloadFolder() { 'methods' => [ '_getZipDownloader' ], - //'components' => [ - // 'Download' - //] + 'components' => [ + 'Security', + ] ] ); $zipDownloaderMock = $this->getMock('ZipDownloader', ['download']); @@ -109,6 +109,8 @@ public function testDownloadFolder() { $urlOptions = $this->__data(); //テスト実施 - $this->_testGetAction($urlOptions, array('method' => 'assertEmpty'), null, 'result'); + $this->_testPostAction('post', ['CabinetFile' => ['key' => $urlOptions['key']]], + $urlOptions, null, 'result' + ); } } \ No newline at end of file diff --git a/Test/Case/Controller/CabinetFilesEditController/AddFolderTest.php b/Test/Case/Controller/CabinetFilesEditController/AddFolderTest.php index accb7b7..5b7407c 100644 --- a/Test/Case/Controller/CabinetFilesEditController/AddFolderTest.php +++ b/Test/Case/Controller/CabinetFilesEditController/AddFolderTest.php @@ -297,6 +297,7 @@ public function testViewFileByPublishable() { 'action' => 'add_folder', 'frame_id' => $data['Frame']['id'], 'block_id' => $data['Block']['id'], + 'parent_id' => $data['CabinetFileTree']['parent_id'], ), array('method' => 'assertNotEmpty') ); diff --git a/Test/Case/Controller/CabinetFilesEditController/AddTest.php b/Test/Case/Controller/CabinetFilesEditController/AddTest.php index bd7e106..aa2b059 100644 --- a/Test/Case/Controller/CabinetFilesEditController/AddTest.php +++ b/Test/Case/Controller/CabinetFilesEditController/AddTest.php @@ -157,7 +157,7 @@ public function dataProviderAddGet() { $results[0] = array( 'urlOptions' => array( 'frame_id' => $data['Frame']['id'], - 'block_id' => $data['Block']['id'] + 'block_id' => $data['Block']['id'], ), 'assert' => null, 'exception' => 'ForbiddenException', ); @@ -185,6 +185,7 @@ public function dataProviderAddGetByCreatable() { 'urlOptions' => array( 'frame_id' => $data['Frame']['id'], 'block_id' => $data['Block']['id'], + 'parent_id' => $data['CabinetFileTree']['parent_id'], ), 'assert' => array('method' => 'assertNotEmpty'), ); @@ -313,6 +314,7 @@ public function testViewFileByCreatable() { 'action' => 'add', 'frame_id' => $data['Frame']['id'], 'block_id' => $data['Block']['id'], + 'parent_id' => $data['CabinetFileTree']['parent_id'], ), array('method' => 'assertNotEmpty') ); @@ -344,6 +346,7 @@ public function testViewFileByPublishable() { 'action' => 'add', 'frame_id' => $data['Frame']['id'], 'block_id' => $data['Block']['id'], + 'parent_id' => $data['CabinetFileTree']['parent_id'], ), array('method' => 'assertNotEmpty') ); diff --git a/Test/Case/Controller/CabinetFilesEditController/BeforeFilterTest.php b/Test/Case/Controller/CabinetFilesEditController/BeforeFilterTest.php index 8f60d39..fe8dfa5 100644 --- a/Test/Case/Controller/CabinetFilesEditController/BeforeFilterTest.php +++ b/Test/Case/Controller/CabinetFilesEditController/BeforeFilterTest.php @@ -78,7 +78,7 @@ public function testBeforeFilterGet() { //テスト実行 $blockId = '2'; - $this->_testGetAction(array('action' => 'add', 'block_id' => $blockId), array('method' => + $this->_testGetAction(array('action' => 'add', 'block_id' => $blockId, 'parent_id' => 11), array('method' => 'assertNotEmpty'), null, 'view'); diff --git a/Test/Case/Model/Behavior/CabinetFolderBehavior/UpdateCabinetTotalSizeTest.php b/Test/Case/Model/Behavior/CabinetFolderBehavior/UpdateCabinetTotalSizeTest.php new file mode 100644 index 0000000..7650543 --- /dev/null +++ b/Test/Case/Model/Behavior/CabinetFolderBehavior/UpdateCabinetTotalSizeTest.php @@ -0,0 +1,92 @@ + + * @author Ryuji AMANO + * @link http://www.netcommons.org NetCommons Project + * @license http://www.netcommons.org/license.txt NetCommons License + * @copyright Copyright 2014, NetCommons Project + */ + + +\App::uses('NetCommonsModelTestCase', 'NetCommons.TestSuite'); + +/** + * Class UpdateCabinetTotalSizeTest + */ +final class UpdateCabinetTotalSizeTest extends \NetCommonsModelTestCase { + +/** + * Fixture + * + * @var string[] + */ + public $fixtures = [ + 'plugin.cabinets.cabinet', + 'plugin.cabinets.cabinet_file', + 'plugin.cabinets.cabinet_file_tree', + 'plugin.cabinets.upload_file_for_cabinets', + 'plugin.cabinets.upload_files_content_for_cabinets', + 'plugin.workflow.workflow_comment', + ]; + +/** + * testCalcCabinetTotalSize + * + * @return void + */ + public function testCalcCabinetTotalSize() { + $cabinetFile = \ClassRegistry::init('Cabinets.CabinetFile'); + $cabinet = [ + 'Cabinet' => [ + 'id' => 2, + 'block_id' => '2', + 'name' => 'Cabinet1', + 'key' => 'content_block_1', + 'total_size' => '1' + ] + ]; + /** @see \CabinetFolderBehavior::calcCabinetTotalSize */ + $totalSize = $cabinetFile->calcCabinetTotalSize($cabinet); + + $expectedTotal = 13638761; + self::assertSame($expectedTotal, $totalSize); + } + +/** + * testUpdateCabinetTotalSize + * + * @return void + */ + public function testUpdateCabinetTotalSize() { + $cabinetFile = \ClassRegistry::init('Cabinets.CabinetFile'); + /** @see \CabinetFolderBehavior::updateCabinetTotalSize() */ + $cabinetFile->updateCabinetTotalSize('content_block_1'); + + $cabinetModel = ClassRegistry::init('Cabinets.Cabinet'); + $cabinet = $cabinetModel->find('first', [ + 'Cabinet.id' => '2' + ]); + $totalSize = $cabinet['Cabinet']['total_size']; + + // total_sizeはmysqlのfloatで保存されてるので、頭5桁だけで比較する + $expectedTotal = '13638761'; + $expectedFloatLeft5 = $this->__truncate5($expectedTotal); + + $floatLeft5TotalSize = $this->__truncate5($totalSize); + self::assertSame($expectedFloatLeft5, $floatLeft5TotalSize); + } + +/** + * 上位5桁だけでのこし、端数を切り捨てる + * + * @param float $floatSize + * @return float + */ + private function __truncate5(float $floatSize) { + $roundNumber = 5 - strlen($floatSize); + return round($floatSize, $roundNumber, PHP_ROUND_HALF_DOWN); + } + +} \ No newline at end of file diff --git a/Test/Case/Model/Cabinet/SaveCabinetTest.php b/Test/Case/Model/Cabinet/SaveCabinetTest.php index 3db129a..1b77b35 100644 --- a/Test/Case/Model/Cabinet/SaveCabinetTest.php +++ b/Test/Case/Model/Cabinet/SaveCabinetTest.php @@ -62,8 +62,8 @@ public function setUp() { Current::$current['Block']['id'] = '2'; Current::$current['Room']['id'] = '1'; - Current::$current['Permission']['content_editable']['value'] = true; - Current::$current['Permission']['content_publishable']['value'] = true; + Current::writePermission('1', 'content_editable', true); + Current::writePermission('1', 'content_publishable', true); } /** diff --git a/Test/Case/Model/CabinetFileTree/SaveTest.php b/Test/Case/Model/CabinetFileTree/SaveTest.php index 048dda5..799dde4 100644 --- a/Test/Case/Model/CabinetFileTree/SaveTest.php +++ b/Test/Case/Model/CabinetFileTree/SaveTest.php @@ -63,7 +63,10 @@ public function testSave() { $data = (new CabinetFileTreeFixture())->records[0]; $data['modified'] = '2000-01-01 00:00:00'; - $result = $this->CabinetFileTree->save($data); - $this->assertNotEquals($result['CabinetFileTree']['modified'], $data['modified']); + $this->CabinetFileTree->save($data); + $this->assertNotEquals( + $this->CabinetFileTree->data['CabinetFileTree']['modified'], + $data['modified'] + ); } } diff --git a/VERSION.txt b/VERSION.txt new file mode 100644 index 0000000..86fb650 --- /dev/null +++ b/VERSION.txt @@ -0,0 +1 @@ +3.3.7 diff --git a/View/CabinetFiles/folder_detail.ctp b/View/CabinetFiles/folder_detail.ctp index 2801f01..9e6348c 100644 --- a/View/CabinetFiles/folder_detail.ctp +++ b/View/CabinetFiles/folder_detail.ctp @@ -68,7 +68,7 @@ echo $this->Html->script(
-
element('file_path'); ?>
+
element('Cabinets.file_path'); ?>
Number->toReadableSize( @@ -115,13 +115,13 @@ echo $this->Html->script( ) ?> - NetCommonsHtml->link( - __d('cabinets', 'Download'), - ['action' => 'download_folder', 'key' => $cabinetFile['CabinetFile']['key']], - ['class' => 'btn btn-primary'] - ) - ?> + CabinetFile->zipDownload( + $cabinetFile, + __d('cabinets', 'Download'), + ['class' => 'btn btn-primary'] + ); + ?> diff --git a/View/CabinetFiles/index.ctp b/View/CabinetFiles/index.ctp index 1b30f05..130ecf1 100644 --- a/View/CabinetFiles/index.ctp +++ b/View/CabinetFiles/index.ctp @@ -26,7 +26,7 @@
- element('file_path', ['currentFile' => $currentFolder]); ?> + element('Cabinets.file_path', ['currentFile' => $currentFolder]); ?>
@@ -92,7 +92,7 @@ @@ -152,17 +152,14 @@ 0) { - echo $this->NetCommonsHtml->link( + echo $this->CabinetFile->zipDownload( + $currentFolder, __d('cabinets', 'Zip download'), [ - 'action' => 'download_folder', - 'key' => $currentFolder['CabinetFile']['key'] - ], - ['class' => 'btn btn-xs btn-default', + 'class' => 'btn btn-xs btn-default', 'style' => 'margin-left:0px;' ] ); - } ?> @@ -181,10 +178,10 @@ - element('CabinetFiles/folder_row', + element('Cabinets.CabinetFiles/folder_row', ['cabinetFile' => $cabinetFile]); ?> - element('CabinetFiles/file_row', + element('Cabinets.CabinetFiles/file_row', ['cabinetFile' => $cabinetFile]); ?> diff --git a/View/CabinetFiles/tree.ctp b/View/CabinetFiles/tree.ctp index 7da26f7..c44881a 100644 --- a/View/CabinetFiles/tree.ctp +++ b/View/CabinetFiles/tree.ctp @@ -1 +1 @@ -element('CabinetFiles/folder_tree'); \ No newline at end of file +element('Cabinets.CabinetFiles/folder_tree'); \ No newline at end of file diff --git a/View/CabinetFiles/view.ctp b/View/CabinetFiles/view.ctp index 8269e2d..8c1e382 100644 --- a/View/CabinetFiles/view.ctp +++ b/View/CabinetFiles/view.ctp @@ -70,7 +70,7 @@ echo $this->Html->script(
-
element('file_path'); ?>
+
element('Cabinets.file_path'); ?>
Number->toReadableSize( diff --git a/View/CabinetFilesEdit/add.ctp b/View/CabinetFilesEdit/add.ctp index 075e6a3..347ce66 100644 --- a/View/CabinetFilesEdit/add.ctp +++ b/View/CabinetFilesEdit/add.ctp @@ -19,7 +19,7 @@ echo $this->NetCommonsHtml->script( >
- element('file_path'); ?> + element('Cabinets.file_path'); ?>
diff --git a/View/CabinetFilesEdit/folder_form.ctp b/View/CabinetFilesEdit/folder_form.ctp index 88b97f5..3efe7b2 100644 --- a/View/CabinetFilesEdit/folder_form.ctp +++ b/View/CabinetFilesEdit/folder_form.ctp @@ -61,7 +61,7 @@ echo $this->NetCommonsHtml->script( __d('cabinets', 'Path') ); ?> diff --git a/View/CabinetFilesEdit/form.ctp b/View/CabinetFilesEdit/form.ctp index 0f0562f..889d150 100644 --- a/View/CabinetFilesEdit/form.ctp +++ b/View/CabinetFilesEdit/form.ctp @@ -114,7 +114,7 @@ echo $this->NetCommonsHtml->script( __d('cabinets', 'Path') ); ?> diff --git a/View/Elements/CabinetFiles/file_dropdown.ctp b/View/Elements/CabinetFiles/file_dropdown.ctp new file mode 100644 index 0000000..0feffe8 --- /dev/null +++ b/View/Elements/CabinetFiles/file_dropdown.ctp @@ -0,0 +1,138 @@ + \ No newline at end of file diff --git a/View/Elements/CabinetFiles/file_row.ctp b/View/Elements/CabinetFiles/file_row.ctp index 8ad05b7..2e60f12 100644 --- a/View/Elements/CabinetFiles/file_row.ctp +++ b/View/Elements/CabinetFiles/file_row.ctp @@ -70,143 +70,5 @@ ) ?> - - + element('Cabinets.CabinetFiles/file_dropdown', ['cabinetFile' => $cabinetFile]); ?> diff --git a/View/Elements/CabinetFiles/folder_row.ctp b/View/Elements/CabinetFiles/folder_row.ctp index 1b1e447..604694b 100644 --- a/View/Elements/CabinetFiles/folder_row.ctp +++ b/View/Elements/CabinetFiles/folder_row.ctp @@ -5,7 +5,10 @@ echo $icon; echo $this->NetCommonsHtml->link( h($cabinetFile['CabinetFile']['filename']), - ['key' => $cabinetFile['CabinetFile']['key']], + [ + 'action' => 'index', + 'key' => $cabinetFile['CabinetFile']['key'] + ], ['escape' => false] ); ?> @@ -61,7 +64,7 @@ ); ?> - +
  • NetCommonsHtml->link( - __d('cabinets', 'Zip download'), - [ - 'action' => 'download_folder', - 'key' => $cabinetFile['CabinetFile']['key'] - ] - ); + echo $this->CabinetFile->zipDownload( + $cabinetFile, + __d('cabinets', 'Zip download'), + [] + ); ?>
  • diff --git a/View/Helper/CabinetFileHelper.php b/View/Helper/CabinetFileHelper.php index b9d2a3a..eaf8d42 100644 --- a/View/Helper/CabinetFileHelper.php +++ b/View/Helper/CabinetFileHelper.php @@ -9,9 +9,33 @@ /** * Class CabinetsFormatHelper + * + * @property NetCommonsHtmlHelper $NetCommonsHtml + * @property TokenHelper $Token */ class CabinetFileHelper extends AppHelper { +/** + * @var array helpers + */ + public $helpers = [ + 'NetCommons.NetCommonsHtml', + 'NetCommons.Token', + ]; + +/** + * Before render callback. beforeRender is called before the view file is rendered. + * + * Overridden in subclasses. + * + * @param string $viewFile The view file that is going to be rendered + * @return void + */ + public function beforeRender($viewFile) { + $this->NetCommonsHtml->script('/cabinets/js/cabinets_zip_download.js'); + parent::beforeRender($viewFile); + } + /** * 解凍してよいか * @@ -22,4 +46,75 @@ public function isAllowUnzip($cabinetFile) { $CabinetFile = ClassRegistry::init('Cabinets.CabinetFile'); return $CabinetFile->isAllowUnzip($cabinetFile); } + +/** + * 圧縮ダウンロードリンク + * + * @param array $cabinetFile CabinetFile data + * @param string $label ボタン(リンク)のラベル + * @param string $options ボタン(リンク)のオプション + * @return string + */ + public function zipDownload($cabinetFile, $label, $options) { + $html = ''; + + $rootUrl = substr(Router::url('/'), 0, -1); + + //アクションURL生成 + $action = [ + 'action' => 'download_folder', + 'key' => $cabinetFile['CabinetFile']['key'] + ]; + $downloadUrl = substr($this->NetCommonsHtml->url($action), strlen($rootUrl)); + + $action = [ + 'action' => 'check_download_folder', + 'key' => $cabinetFile['CabinetFile']['key'] + ]; + $checkUrl = substr($this->NetCommonsHtml->url($action), strlen($rootUrl)); + + //POSTデータ生成 + $requestData = [ + 'CabinetFile' => [ + 'key' => $cabinetFile['CabinetFile']['key'] + ], + ]; + $currentData = $this->_View->request->data; + $tokenFields = Hash::flatten($requestData); + $hiddenFields = array_keys($tokenFields); + // * チェック用のToken作成 + $this->_View->request->data = $requestData; + $checkToken = $this->Token->getToken( + 'CabinetFile', $checkUrl, $tokenFields, $hiddenFields + ); + $checkToken['_Token']['key'] = ''; + // * ダウンロード用のToken作成 + $this->_View->request->data = $requestData; + $downloadToken = $this->Token->getToken( + 'CabinetFile', $downloadUrl, $tokenFields, $hiddenFields + ); + $downloadToken['_Token']['key'] = ''; + // * $thisi->request->dataを元に戻す + $this->_View->request->data = $currentData; + + $requestData['Check'] = [ + 'action' => $checkUrl, + 'token' => $checkToken['_Token'], + ]; + + $requestData['Download'] = [ + 'action' => $downloadUrl, + 'token' => $downloadToken['_Token'], + ]; + //アンカータグ生成 + $options['ng-controller'] = 'CabinetFiles.zipDownload'; + $options['ng-init'] = "initialize(" . json_encode($requestData) . ")"; + $options['ng-click'] = 'download($event)'; + $options['href'] = ''; + $attributes = $this->_parseAttributes($options); + + $html .= "" . h($label) . ""; + return $html; + } + } diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 4ef9896..c5d658f 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,5 +1,8 @@ + + + app/Plugin/Cabinets @@ -14,6 +17,6 @@ - + diff --git a/webroot/js/cabinets.js b/webroot/js/cabinets.js index 275fb0e..79cbea4 100644 --- a/webroot/js/cabinets.js +++ b/webroot/js/cabinets.js @@ -81,7 +81,7 @@ NetCommonsApp.controller('CabinetFile.index', // フォルダを動かしたらリロード location.reload(); } else { - $scope.flashMessage(data.name, data.class, data.interval); + $scope.flashMessage(data.message, data.class, data.interval); // 違うフォルダへ移動なので、今のフォルダ内ファイル一覧から非表示にする $scope.moved[cabinetFileKey] = true; } @@ -89,14 +89,14 @@ NetCommonsApp.controller('CabinetFile.index', function(response) { var data = response.data; // エラー処理 - $scope.flashMessage(data.name, 'danger', 0); + $scope.flashMessage(data.message, 'danger', 0); }); }, function(response) { //Token error condition // エラー処理 var data = response.data; - $scope.flashMessage(data.name, 'danger', 0); + $scope.flashMessage(data.message, 'danger', 0); }); } }); @@ -128,20 +128,20 @@ NetCommonsApp.controller('CabinetFile.index', // エラーがなかったらリロードする location.reload(); } else { - $scope.flashMessage(data.name, data.class, 0); + $scope.flashMessage(data.message, data.class, 0); } }, function(response) { // エラー処理 var data = response.data; - $scope.flashMessage(data.name, data.class, 0); + $scope.flashMessage(data.message, data.class, 0); }); }, function(response) { //Token error condition // エラー処理 var data = response.data; - $scope.flashMessage(data.name, 'danger', 3); + $scope.flashMessage(data.message, 'danger', 3); }); }; }] @@ -163,6 +163,8 @@ NetCommonsApp.controller('CabinetFile.addFile', url = url + '/parent_id:' + $scope.parent_id; } url = url + '?frame_id=' + frameId; + + $http.defaults.headers.common['Accept'] = 'text/html'; var modal = NetCommonsModal.show($scope, 'CabinetFile.addFileModal', url); }; } @@ -290,7 +292,7 @@ NetCommonsApp.controller('CabinetFile.edit', $scope.folderPath = result; }) .error(function(data, status, headers, config) { - $scope.flashMessage(data.name, 'danger', 0); + $scope.flashMessage(data.message, 'danger', 0); }); }); }; diff --git a/webroot/js/cabinets_zip_download.js b/webroot/js/cabinets_zip_download.js new file mode 100644 index 0000000..a7f2885 --- /dev/null +++ b/webroot/js/cabinets_zip_download.js @@ -0,0 +1,112 @@ +/** + * Cabinets Javascript + */ + + +/** + * 圧縮ダウンロード + */ +NetCommonsApp.controller('CabinetFiles.zipDownload', + ['$scope', '$http', 'NC3_URL', 'ajaxSendPost', + function($scope, $http, NC3_URL, ajaxSendPost) { + + /** + * ファイル(フォルダ)キー + * + * @type {object} + */ + $scope.postData = {}; + + /** + * イニシャライズ処理 + * + * @return {void} + */ + $scope.initialize = function(postData) { + $scope.postData = postData; + }; + + /** + * ダウンロード処理 + * + * @return {void} + */ + $scope.download = function($event) { + if ($scope.$parent.sending) { + event.preventDefault(); + return; + } + $scope.$parent.sending = true; + $event.preventDefault(); + + var postData = { + CabinetFile: $scope.postData['CabinetFile'], + _Token: $scope.postData['Check']['token'] + }; + ajaxSendPost('POST', $scope.postData['Check']['action'], postData) + .success(function(response) { + $scope.__submitDownload(); + }) + .error(function(response) { + //エラー処理 + var data = response.data; + $scope.flashMessage(data.message, 'danger', data.interval); + $scope.$parent.sending = false; + }); + }; + + /** + * ダウンロードするためのformエレメントを作成する + * + * @return {void} + */ + $scope.__submitDownload = function() { + $http.get(NC3_URL + '/net_commons/net_commons/csrfToken.json') + .then(function(response) { + var token = response.data; + $scope.postData['Download']['token']['key'] = token.data._Token.key; + var formId = 'CabinetFileZipDownload' + Math.random().toString(36).slice(2); + var formElement = $scope.__createFormElement(formId); + formElement.appendTo(document.body).submit(); + $('#' + formId).remove(); + $scope.$parent.sending = false; + }, + function(response) { + $scope.$parent.sending = false; + }); + }; + + /** + * ダウンロードするためのformエレメントを作成する + * + * @return {void} + */ + $scope.__createFormElement = function(formId) { + var formElement = $('
    ', { + id: formId, + target: '_blank', + action: NC3_URL + $scope.postData['Download']['action'], + method: 'post' + }); + + angular.forEach($scope.postData['Download']['token'], function(value, key) { + var inputElement = $('', { + type: 'hidden', + name: 'data[_Token][' + key + ']', + value: value + }); + formElement.append(inputElement); + }); + angular.forEach($scope.postData['CabinetFile'], function(value, key) { + var inputElement = $('', { + type: 'hidden', + name: 'data[CabinetFile][' + key + ']', + value: value + }); + formElement.append(inputElement); + }); + + return formElement; + }; + + }]);