diff --git a/common/js/plugins/jquery.fileupload/js/main.js b/common/js/plugins/jquery.fileupload/js/main.js index ac3c3b9e2..71d65759f 100644 --- a/common/js/plugins/jquery.fileupload/js/main.js +++ b/common/js/plugins/jquery.fileupload/js/main.js @@ -91,8 +91,8 @@ var chunkStatus = true; var defaultFormData = { "editor_sequence": data.editorSequence, - "upload_target_srl" : data.uploadTargetSrl, - "mid" : window.current_mid, + "upload_target_srl" : data.uploadTargetSrl ? data.uploadTargetSrl : 0, + "mid" : window.editor_mid ? window.editor_mid : window.current_mid, "act": 'procFileUpload' }; diff --git a/modules/communication/communication.view.php b/modules/communication/communication.view.php index 204ebb4f5..c4e324377 100644 --- a/modules/communication/communication.view.php +++ b/modules/communication/communication.view.php @@ -293,6 +293,10 @@ class CommunicationView extends communication { $option->editor_toolbar_hide = 'Y'; } + if ($option->allow_fileupload) + { + $option->module_srl = MemberView::getInstance()->getMemberModuleSrl(); + } $editor = $oEditorModel->getEditor(getNextSequence(), $option); $editor = $editor . "\n" . '' . "\n"; Context::set('editor', $editor); diff --git a/modules/editor/editor.controller.php b/modules/editor/editor.controller.php index 6274cdcd4..55b37ce12 100644 --- a/modules/editor/editor.controller.php +++ b/modules/editor/editor.controller.php @@ -328,11 +328,10 @@ class EditorController extends Editor $editor_sequence = Context::get('editor_sequence'); $primary_key = Context::get('primary_key'); $oEditorModel = getModel('editor'); - $oFileController = getController('file'); $saved_doc = $oEditorModel->getSavedDoc(null); - $oFileController->setUploadInfo($editor_sequence, $saved_doc->document_srl); + FileController::setUploadInfo($editor_sequence, $saved_doc->document_srl, intval($saved_doc->module_srl)); $vars = $this->getVariables(); $this->add("editor_sequence", $editor_sequence); $this->add("key", $primary_key); diff --git a/modules/editor/editor.model.php b/modules/editor/editor.model.php index deee0baa7..ab18dde4d 100644 --- a/modules/editor/editor.model.php +++ b/modules/editor/editor.model.php @@ -251,14 +251,29 @@ class EditorModel extends Editor } Context::set('file_config',$file_config); + // Configure upload status such as file size $upload_status = FileModel::getUploadStatus(); Context::set('upload_status', $upload_status); + // Upload enabled (internally caching) - $oFileController = getController('file'); - $oFileController->setUploadInfo($option->editor_sequence, $upload_target_srl); + FileController::setUploadInfo($option->editor_sequence, $upload_target_srl, $option->module_srl ?? 0); + + // Set editor mid + if (!empty($option->module_srl)) + { + $option->mid = ModuleModel::getModuleInfoByModuleSrl($option->module_srl)->mid ?? null; + } + if (!empty($option->mid)) + { + Context::addHtmlFooter(''); + } + // Check if the file already exists - if($upload_target_srl) $files_count = FileModel::getFilesCount($upload_target_srl); + if ($upload_target_srl) + { + $files_count = FileModel::getFilesCount($upload_target_srl); + } } Context::set('files_count', (int)$files_count); @@ -294,6 +309,7 @@ class EditorModel extends Editor // Initialize options $option = new stdClass(); $option->module_type = $type; + $option->module_srl = (int)$module_srl; // Convert configuration keys according to type (document or comment). if($type == 'document') diff --git a/modules/file/file.controller.php b/modules/file/file.controller.php index 438856085..29492c179 100644 --- a/modules/file/file.controller.php +++ b/modules/file/file.controller.php @@ -31,21 +31,24 @@ class FileController extends File // An error appears if not a normally uploaded file if(!$file_info || !is_uploaded_file($file_info['tmp_name'])) exit(); - // Basic variables setting + // Validate editor_sequence and module_srl. $editor_sequence = Context::get('editor_sequence'); $module_srl = $this->module_srl; - - // Exit a session if there is neither upload permission nor information - if(!$_SESSION['upload_info'][$editor_sequence]->enabled) + if (empty($_SESSION['upload_info'][$editor_sequence]->enabled)) { - throw new Rhymix\Framework\Exceptions\NotPermitted; + throw new Rhymix\Framework\Exceptions\InvalidRequest(sprintf(lang('file.msg_invalid_upload_info'), 'editor_sequence')); + } + if ($_SESSION['upload_info'][$editor_sequence]->module_srl !== $module_srl) + { + throw new Rhymix\Framework\Exceptions\InvalidRequest(sprintf(lang('file.msg_invalid_upload_info'), 'module_srl')); } - // Get upload_target_srl - $upload_target_srl = intval(Context::get('uploadTargetSrl')) ?: intval(Context::get('upload_target_srl')); - if (!$upload_target_srl) + // Validate upload_target_srl. + $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; + $submitted_upload_target_srl = intval(Context::get('uploadTargetSrl')) ?: intval(Context::get('upload_target_srl')); + if ($submitted_upload_target_srl && $submitted_upload_target_srl !== intval($upload_target_srl)) { - $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; + throw new Rhymix\Framework\Exceptions\InvalidRequest(sprintf(lang('file.msg_invalid_upload_info'), 'upload_target_srl')); } if (!$upload_target_srl) { @@ -170,24 +173,39 @@ class FileController extends File function procFileIframeUpload() { // Basic variables setting - $editor_sequence = Context::get('editor_sequence'); $callback = Context::get('callback'); - $module_srl = $this->module_srl; - $upload_target_srl = intval(Context::get('uploadTargetSrl')); - if(!$upload_target_srl) $upload_target_srl = intval(Context::get('upload_target_srl')); - // Exit a session if there is neither upload permission nor information - if(!$_SESSION['upload_info'][$editor_sequence]->enabled) exit(); - // Extract from session information if upload_target_srl is not specified - if(!$upload_target_srl) $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; - // Create if upload_target_srl is not defined in the session information - if(!$upload_target_srl) $_SESSION['upload_info'][$editor_sequence]->upload_target_srl = $upload_target_srl = getNextSequence(); + // Validate editor_sequence and module_srl. + $editor_sequence = Context::get('editor_sequence'); + $module_srl = $this->module_srl; + if (empty($_SESSION['upload_info'][$editor_sequence]->enabled)) + { + throw new Rhymix\Framework\Exceptions\InvalidRequest(sprintf(lang('file.msg_invalid_upload_info'), 'editor_sequence')); + } + if ($_SESSION['upload_info'][$editor_sequence]->module_srl !== $module_srl) + { + throw new Rhymix\Framework\Exceptions\InvalidRequest(sprintf(lang('file.msg_invalid_upload_info'), 'module_srl')); + } + + // Get upload_target_srl + $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; + $submitted_upload_target_srl = intval(Context::get('uploadTargetSrl')) ?: intval(Context::get('upload_target_srl')); + if ($submitted_upload_target_srl && $submitted_upload_target_srl !== intval($upload_target_srl)) + { + throw new Rhymix\Framework\Exceptions\InvalidRequest(sprintf(lang('file.msg_invalid_upload_info'), 'upload_target_srl')); + } + if (!$upload_target_srl) + { + $upload_target_srl = getNextSequence(); + $_SESSION['upload_info'][$editor_sequence]->upload_target_srl = $upload_target_srl; + } + // Delete and then attempt to re-upload if file_srl is requested $file_srl = Context::get('file_srl'); if($file_srl) { $file_info = FileModel::getFile($file_srl); - if($file_info->file_srl == $file_srl && FileModel::isDeletable($file_info)) + if($file_info->file_srl == $file_srl && $file_info->upload_target_srl == $upload_target_srl && FileModel::isDeletable($file_info)) { $this->deleteFile($file_srl); } @@ -582,10 +600,18 @@ class FileController extends File $file_srl = Context::get('file_srl'); $file_srls = Context::get('file_srls'); if($file_srls) $file_srl = $file_srls; - // Exit a session if there is neither upload permission nor information - if(!$_SESSION['upload_info'][$editor_sequence]->enabled) exit(); + // Exit a session if there is neither upload permission nor information + if (!$_SESSION['upload_info'][$editor_sequence]->enabled) + { + throw new Rhymix\Framework\Exceptions\NotPermitted; + } $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; + if (!$upload_target_srl) + { + throw new Rhymix\Framework\Exceptions\TargetNotFound; + } + $module_srl = $_SESSION['upload_info'][$editor_sequence]->module_srl ?? 0; $srls = explode(',',$file_srl); if(!count($srls)) return; @@ -601,9 +627,10 @@ class FileController extends File if(!$output->toBool()) continue; $file_info = $output->data; - if(!$file_info) continue; + if(!$file_info || $file_info->upload_target_srl != $upload_target_srl) continue; + if($module_srl && $file_info->module_srl != $module_srl) continue; if(!FileModel::isDeletable($file_info)) continue; - if($upload_target_srl && $file_srl) $output = $this->deleteFile($file_srl); + $output = $this->deleteFile($file_srl); } } @@ -709,9 +736,10 @@ class FileController extends File * * @param int $editor_sequence * @param int $upload_target_srl + * @param int $module_srl * @return int */ - function setUploadInfo($editor_sequence = 0, $upload_target_srl = 0) + public static function setUploadInfo($editor_sequence = 0, $upload_target_srl = 0, $module_srl = 0) { if(!$editor_sequence) { @@ -721,6 +749,14 @@ class FileController extends File } $editor_sequence = ++$_SESSION['_editor_sequence_']; } + if(!$module_srl) + { + $current_module_info = Context::get('current_module_info'); + if (!empty($current_module_info->module_srl)) + { + $module_srl = $current_module_info->module_srl; + } + } if(!isset($_SESSION['upload_info']) || !is_array($_SESSION['upload_info'])) { $_SESSION['upload_info'] = array(); @@ -730,7 +766,12 @@ class FileController extends File $_SESSION['upload_info'][$editor_sequence] = new stdClass(); } $_SESSION['upload_info'][$editor_sequence]->enabled = true; - $_SESSION['upload_info'][$editor_sequence]->upload_target_srl = $upload_target_srl; + $_SESSION['upload_info'][$editor_sequence]->upload_target_srl = (int)$upload_target_srl; + $_SESSION['upload_info'][$editor_sequence]->module_srl = (int)$module_srl; + if (!$module_srl) + { + trigger_error('No module_srl supplied to setUploadInfo(), and cannot determine automatically', E_USER_WARNING); + } return $editor_sequence; } @@ -1740,17 +1781,32 @@ class FileController extends File public function procFileSetCoverImage() { $vars = Context::getRequestVars(); - $logged_info = Context::get('logged_info'); - if(!$vars->editor_sequence) throw new Rhymix\Framework\Exceptions\InvalidRequest; - - $upload_target_srl = $_SESSION['upload_info'][$vars->editor_sequence]->upload_target_srl; + // Exit a session if there is neither upload permission nor information + $editor_sequence = $vars->editor_sequence ?? 0; + if (!$vars->editor_sequence) + { + throw new Rhymix\Framework\Exceptions\InvalidRequest; + } + if (!$_SESSION['upload_info'][$editor_sequence]->enabled) + { + throw new Rhymix\Framework\Exceptions\NotPermitted; + } + $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; + if (!$upload_target_srl) + { + throw new Rhymix\Framework\Exceptions\TargetNotFound; + } $file_info = FileModel::getFile($vars->file_srl); - - if(!$file_info) throw new Rhymix\Framework\Exceptions\TargetNotFound; - - if(!$this->manager && !$file_info->member_srl === $logged_info->member_srl) throw new Rhymix\Framework\Exceptions\NotPermitted; + if (!$file_info || $file_info->upload_target_srl != $upload_target_srl) + { + throw new Rhymix\Framework\Exceptions\TargetNotFound; + } + if(!$this->grant->manager && $file_info->member_srl != $this->user->member_srl) + { + throw new Rhymix\Framework\Exceptions\NotPermitted; + } $args = new stdClass(); $args->file_srl = $vars->file_srl; @@ -1769,7 +1825,6 @@ class FileController extends File if($file_info->cover_image != 'Y') { - $args->cover_image = 'Y'; $output = executeQuery('file.updateCoverImage', $args); if(!$output->toBool()) @@ -1777,7 +1832,6 @@ class FileController extends File $oDB->rollback(); return $output; } - } $oDB->commit(); diff --git a/modules/file/file.model.php b/modules/file/file.model.php index 7671c3dec..a76cb5245 100644 --- a/modules/file/file.model.php +++ b/modules/file/file.model.php @@ -26,12 +26,8 @@ class FileModel extends File { $file_list = []; $attached_size = 0; - $editor_sequence = Context::get('editor_sequence'); - $upload_target_srl = Context::get('upload_target_srl') ?: 0; - if(!$upload_target_srl && isset($_SESSION['upload_info'][$editor_sequence])) - { - $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl; - } + $editor_sequence = intval(Context::get('editor_sequence')); + $upload_target_srl = $_SESSION['upload_info'][$editor_sequence]->upload_target_srl ?? 0; // Get uploaded files if($upload_target_srl) diff --git a/modules/file/lang/en.php b/modules/file/lang/en.php index 5f7e32902..7fd2b2630 100644 --- a/modules/file/lang/en.php +++ b/modules/file/lang/en.php @@ -49,6 +49,7 @@ $lang->about_save_changelog = 'Keep a log of new and deleted files in the databa $lang->cmd_delete_checked_file = 'Delete Selected Item(s)'; $lang->cmd_move_to_document = 'Move to Document'; $lang->cmd_download = 'Download'; +$lang->msg_invalid_upload_info = 'Invalid upload target information. (%s)'; $lang->msg_not_permitted_download = 'You do not have a permission to download.'; $lang->msg_file_cart_is_null = 'Please select a file(s) to delete.'; $lang->msg_checked_file_is_deleted = '%d attachment(s) was(were) deleted.'; diff --git a/modules/file/lang/ko.php b/modules/file/lang/ko.php index 47691e443..53ee8e429 100644 --- a/modules/file/lang/ko.php +++ b/modules/file/lang/ko.php @@ -49,6 +49,7 @@ $lang->about_save_changelog = '파일 저장 및 삭제 내역을 DB에 기록 $lang->cmd_delete_checked_file = '선택항목 삭제'; $lang->cmd_move_to_document = '문서로 이동'; $lang->cmd_download = '다운로드'; +$lang->msg_invalid_upload_info = '업로드 대상 정보가 일치하지 않습니다. (%s)'; $lang->msg_not_permitted_download = '다운로드할 수 있는 권한이 없습니다.'; $lang->msg_file_cart_is_null = '삭제할 파일을 선택해주세요.'; $lang->msg_checked_file_is_deleted = '%d개의 첨부 파일이 삭제되었습니다.'; diff --git a/modules/member/member.admin.view.php b/modules/member/member.admin.view.php index 8c7d77166..68dcd382a 100644 --- a/modules/member/member.admin.view.php +++ b/modules/member/member.admin.view.php @@ -433,6 +433,14 @@ class MemberAdminView extends Member $option->editor_toolbar_hide = 'Y'; $option->editor_skin = $member_config->signature_editor_skin; $option->sel_editor_colorset = $member_config->sel_editor_colorset; + if (!$option->allow_html) + { + $option->editor_skin = 'textarea'; + } + if ($option->allow_fileupload) + { + $option->module_srl = MemberView::getInstance()->getMemberModuleSrl(); + } Context::set('editor', getModel('editor')->getEditor($member_info->member_srl, $option)); } diff --git a/modules/member/member.view.php b/modules/member/member.view.php index b0a5d1971..54633ff7f 100644 --- a/modules/member/member.view.php +++ b/modules/member/member.view.php @@ -93,6 +93,27 @@ class MemberView extends Member return false; } + /** + * Get the module_srl for the member mid. + * + * @return int + */ + public function getMemberModuleSrl(): int + { + if (!$this->member_config) + { + $this->member_config = MemberModel::getMemberConfig(); + } + if (!empty($this->member_config->mid)) + { + return ModuleModel::getModuleInfoByMid($this->member_config->mid)->module_srl ?? 0; + } + else + { + return 0; + } + } + /** * Module index */ @@ -334,6 +355,10 @@ class MemberView extends Member { $option->editor_skin = 'textarea'; } + if ($option->allow_fileupload) + { + $option->module_srl = $this->getMemberModuleSrl(); + } Context::set('editor', getModel('editor')->getEditor(0, $option)); } @@ -448,6 +473,10 @@ class MemberView extends Member { $option->editor_skin = 'textarea'; } + if ($option->allow_fileupload) + { + $option->module_srl = $this->getMemberModuleSrl(); + } Context::set('editor', getModel('editor')->getEditor($member_info->member_srl, $option)); } diff --git a/tests/unit/framework/TemplateTest.php b/tests/unit/framework/TemplateTest.php index 1814cb6f8..420134e96 100644 --- a/tests/unit/framework/TemplateTest.php +++ b/tests/unit/framework/TemplateTest.php @@ -5,6 +5,7 @@ class TemplateTest extends \Codeception\Test\Unit public function _before() { Context::init(); + $this->baseurl = '/' . basename(dirname(dirname(dirname(__DIR__)))) . '/'; } public function testIsRelativePath() @@ -48,7 +49,7 @@ class TemplateTest extends \Codeception\Test\Unit $this->assertEquals($target, $tmpl->convertPath($source)); $source = '^/foo/bar.gif'; - $target = '/rhymix/foo/bar.gif'; + $target = $this->baseurl . 'foo/bar.gif'; $this->assertEquals($target, $tmpl->convertPath($source)); } diff --git a/tests/unit/framework/parsers/TemplateParserV2Test.php b/tests/unit/framework/parsers/TemplateParserV2Test.php index 9be965cf0..78d2d178d 100644 --- a/tests/unit/framework/parsers/TemplateParserV2Test.php +++ b/tests/unit/framework/parsers/TemplateParserV2Test.php @@ -1145,9 +1145,9 @@ class TemplateParserV2Test extends \Codeception\Test\Unit // Check that resource is loaded $list = \Context::getJsFile('body'); - $this->assertStringContainsString('/rhymix/common/js/plugins/ckeditor/', array_first($list)['file']); + $this->assertStringContainsString('/common/js/plugins/ckeditor/', array_first($list)['file']); $list = \Context::getCssFile(); - $this->assertStringContainsString('/rhymix/tests/_data/template/css/style.scss', array_first($list)['file']); + $this->assertStringContainsString('/tests/_data/template/css/style.scss', array_first($list)['file']); } public function testCompileLang() @@ -1240,7 +1240,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit ); $list = \Context::getJsFile(); - $this->assertStringContainsString('/rhymix/tests/_data/template/js/test.js', array_last($list)['file']); + $this->assertStringContainsString('/tests/_data/template/js/test.js', array_last($list)['file']); } /** @@ -1274,6 +1274,7 @@ class TemplateParserV2Test extends \Codeception\Test\Unit protected function _normalizeWhitespace(string $content): string { $content = preg_replace('/\n/', '', $content); + $content = preg_replace('!(action|src)="' . preg_quote($this->baseurl, '!') . '!', '$1="/rhymix/', $content); $result = []; foreach (explode("\n", $content) as $line)