diff --git a/classes/xml/xmlquery/queryargument/DefaultValue.class.php b/classes/xml/xmlquery/queryargument/DefaultValue.class.php index 455d06537..0e0d53471 100644 --- a/classes/xml/xmlquery/queryargument/DefaultValue.class.php +++ b/classes/xml/xmlquery/queryargument/DefaultValue.class.php @@ -126,14 +126,15 @@ class DefaultValue switch($func_name) { case 'ipaddress' : - $val = '$_SERVER[\'REMOTE_ADDR\']'; + $val = '\\RX_CLIENT_IP'; $this->_is_string_from_function = TRUE; break; case 'unixtime' : - $val = '$_SERVER[\'REQUEST_TIME\']'; + $val = '\\RX_TIME'; + $this->_is_string_from_function = TRUE; break; case 'curdate' : - $val = 'date("YmdHis")'; + $val = 'getInternalDateTime()'; $this->_is_string_from_function = TRUE; break; case 'sequence' : diff --git a/common/framework/datetime.php b/common/framework/datetime.php index ac7001c64..6c19c0b29 100644 --- a/common/framework/datetime.php +++ b/common/framework/datetime.php @@ -12,6 +12,19 @@ class DateTime */ protected static $_timezones = array(); + /** + * Format a Unix timestamp using the internal timezone. + * + * @param string $format Format used in PHP date() function + * @param int $timestamp Unix timestamp (optional, default is now) + * @return string + */ + public static function formatTimestamp($format, $timestamp = null) + { + $offset = Config::get('locale.internal_timezone') ?: date('Z', $timestamp); + return gmdate($format, $timestamp + $offset); + } + /** * Format a Unix timestamp for the current user's timezone. * @@ -125,6 +138,12 @@ class DateTime /** * Get a PHP time zone by UTC offset. * + * Time zones with both (a) fractional offsets and (b) daylight saving time + * (such as Iran's +03:30/+04:30) cannot be converted in this way. + * However, if Rhymix is installed for the first time in such a time zone, + * the internal time zone will be automatically set to UTC, + * so this should never be a problem in practice. + * * @param int $offset * @return bool */ @@ -133,6 +152,15 @@ class DateTime switch ($offset) { case 0: return 'Etc/UTC'; + case -34200: return 'Pacific/Marquesas'; // -09:30 + case -16200: return 'America/Caracas'; // -04:30 + case 16200: return 'Asia/Kabul'; // +04:30 + case 19800: return 'Asia/Kolkata'; // +05:30 + case 20700: return 'Asia/Kathmandu'; // +05:45 + case 23400: return 'Asia/Rangoon'; // +06:30 + case 30600: return 'Asia/Pyongyang'; // +08:30 + case 31500: return 'Australia/Eucla'; // +08:45 + case 34200: return 'Australia/Darwin'; // +09:30 default: return 'Etc/GMT' . ($offset > 0 ? '-' : '+') . intval(abs($offset / 3600)); } } diff --git a/common/lang/ko.php b/common/lang/ko.php index 3a369e771..56f13c647 100644 --- a/common/lang/ko.php +++ b/common/lang/ko.php @@ -195,10 +195,10 @@ $lang->unit_meridiem['am'] = '오전'; $lang->unit_meridiem['pm'] = '오후'; $lang->unit_meridiem['AM'] = '오전'; $lang->unit_meridiem['PM'] = '오후'; -$lang->time_gap['min'] = '%d 분 전'; -$lang->time_gap['mins'] = '%d 분 전'; -$lang->time_gap['hour'] = '%d 시간 전'; -$lang->time_gap['hours'] = '%d 시간 전'; +$lang->time_gap['min'] = '%d분 전'; +$lang->time_gap['mins'] = '%d분 전'; +$lang->time_gap['hour'] = '%d시간 전'; +$lang->time_gap['hours'] = '%d시간 전'; $lang->about_tag = '쉼표(,)를 이용하여 복수 등록'; $lang->about_layout = '레이아웃은 콘텐츠의 겉모습을 꾸며줍니다. 상단 레이아웃 메뉴에서 관리할 수 있습니다.'; $lang->about_ipaddress_input = 'IP주소 입력형식
1. 와일드카드(*) 사용가능(예: 192.168.0.*)
2. 하이픈(-)을 사용하여 대역으로 입력가능
(단, 대역폭으로 입력할 경우 와일드카드 사용불가. 예: 192.168.0.1-192.168.0.254)
3.여러개의 항목은 줄을 바꾸어 입력하세요'; diff --git a/common/legacy.php b/common/legacy.php index c948a158c..f43b17e0d 100644 --- a/common/legacy.php +++ b/common/legacy.php @@ -530,8 +530,9 @@ function ztime($str) { $hour = $min = $sec = 0; } - $offset = Rhymix\Framework\Config::get('locale.internal_timezone') ?: date('Z'); - return gmmktime($hour, $min, $sec, $month, $day, $year) - $offset; + $timestamp = gmmktime($hour, $min, $sec, $month, $day, $year); + $offset = Rhymix\Framework\Config::get('locale.internal_timezone') ?: date('Z', $timestamp); + return $timestamp - $offset; } /** @@ -601,6 +602,32 @@ function zdate($str, $format = 'Y-m-d H:i:s', $conversion = false) return $result; } +/** + * Convert a Unix timestamp to YYYYMMDDHHIISS format, using the internal time zone. + * If the timestamp is not given, the current time is used. + * + * @param int $timestamp Unix timestamp + * @return string + */ +function getInternalDateTime($timestamp = null, $format = 'YmdHis') +{ + $timestamp = ($timestamp !== null) ? $timestamp : time(); + return Rhymix\Framework\DateTime::formatTimestamp($format, $timestamp); +} + +/** + * Convert a Unix timestamp to YYYYMMDDHHIISS format, using the internal time zone. + * If the timestamp is not given, the current time is used. + * + * @param int $timestamp Unix timestamp + * @return string + */ +function getDisplayDateTime($timestamp = null, $format = 'YmdHis') +{ + $timestamp = ($timestamp !== null) ? $timestamp : time(); + return Rhymix\Framework\DateTime::formatTimestampForCurrentUser($format, $timestamp); +} + /** * If the recent post within a day, output format of YmdHis is "min/hours ago from now". If not within a day, it return format string. * @@ -610,24 +637,24 @@ function zdate($str, $format = 'Y-m-d H:i:s', $conversion = false) */ function getTimeGap($date, $format = 'Y.m.d') { - $gap = $_SERVER['REQUEST_TIME'] + zgap() - ztime($date); + $gap = RX_TIME - ztime($date); $lang_time_gap = Context::getLang('time_gap'); - if($gap < 60) + if($gap < 60 * 1.5) { - $buff = sprintf($lang_time_gap['min'], (int)($gap / 60) + 1); + $buff = sprintf($lang_time_gap['min'], round($gap / 60)); } elseif($gap < 60 * 60) { - $buff = sprintf($lang_time_gap['mins'], (int)($gap / 60) + 1); + $buff = sprintf($lang_time_gap['mins'], round($gap / 60)); } - elseif($gap < 60 * 60 * 2) + elseif($gap < 60 * 60 * 1.5) { - $buff = sprintf($lang_time_gap['hour'], (int)($gap / 60 / 60) + 1); + $buff = sprintf($lang_time_gap['hour'], round($gap / 60 / 60)); } elseif($gap < 60 * 60 * 24) { - $buff = sprintf($lang_time_gap['hours'], (int)($gap / 60 / 60) + 1); + $buff = sprintf($lang_time_gap['hours'], round($gap / 60 / 60)); } else { diff --git a/modules/board/board.controller.php b/modules/board/board.controller.php index 77f9b5e71..e1646246c 100644 --- a/modules/board/board.controller.php +++ b/modules/board/board.controller.php @@ -114,9 +114,22 @@ class boardController extends board return new Object(-1,'msg_not_permitted'); } - if($this->module_info->protect_content=="Y" && $oDocument->get('comment_count')>0 && $this->grant->manager==false) + if($this->module_info->protect_content == 'Y' || $this->module_info->protect_update_content == 'Y') { - return new Object(-1,'msg_protect_content'); + if($oDocument->get('comment_count') > 0 && $this->grant->manager == false) + { + return new Object(-1, 'msg_protect_update_content'); + } + } + + if($this->module_info->protect_document_regdate > 0 && $this->grant->manager == false) + { + if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_document'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } } if(!$this->grant->manager) @@ -202,11 +215,23 @@ class boardController extends board $oDocumentModel = &getModel('document'); $oDocument = $oDocumentModel->getDocument($document_srl); // check protect content - if($this->module_info->protect_content=="Y" && $oDocument->get('comment_count')>0 && $this->grant->manager==false) + if($this->module_info->protect_content == 'Y' || $this->module_info->protect_delete_content == 'Y') { - return new Object(-1, 'msg_protect_content'); + if($oDocument->get('comment_count') > 0 && $this->grant->manager == false) + { + return new Object(-1, 'msg_protect_delete_content'); + } } + if($this->module_info->protect_document_regdate > 0 && $this->grant->manager == false) + { + if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_document'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } + } // generate document module controller object $oDocumentController = getController('document'); @@ -306,12 +331,12 @@ class boardController extends board else { $comment = $oCommentModel->getComment($obj->comment_srl, $this->grant->manager); - if($this->module_info->protect_comment === 'Y' && $this->grant->manager == false) + if($this->module_info->protect_update_comment === 'Y' && $this->grant->manager == false) { $childs = $oCommentModel->getChildComments($obj->comment_srl); - if (count($childs) > 0) + if(count($childs) > 0) { - return new Object(-1, 'msg_board_protect_comment'); + return new Object(-1, 'msg_board_update_protect_comment'); } } } @@ -349,6 +374,15 @@ class boardController extends board } else { + if($this->module_info->protect_comment_regdate > 0 && $this->grant->manager == false) + { + if($comment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_comment'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } + } // check the grant if(!$comment->isGranted()) { @@ -384,15 +418,24 @@ class boardController extends board $oCommentModel = getModel('comment'); - if($this->module_info->protect_comment === 'Y' && $this->grant->manager==false) + if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false) { $childs = $oCommentModel->getChildComments($comment_srl); if(count($childs) > 0) { - return new Object(-1, 'msg_board_protect_comment'); + return new Object(-1, 'msg_board_delete_protect_comment'); + } + } + $comment = $oCommentModel->getComment($comment_srl, $this->grant->manager); + if($this->module_info->protect_comment_regdate > 0 && $this->grant->manager == false) + { + if($comment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_comment'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); } } - // generate comment controller object $oCommentController = getController('comment'); diff --git a/modules/board/board.view.php b/modules/board/board.view.php index 631f96c76..015241e69 100644 --- a/modules/board/board.view.php +++ b/modules/board/board.view.php @@ -692,9 +692,24 @@ class boardView extends board if($oDocument->get('module_srl') == $oDocument->get('member_srl')) $savedDoc = TRUE; $oDocument->add('module_srl', $this->module_srl); - if($oDocument->isExists() && $this->module_info->protect_content=="Y" && $oDocument->get('comment_count')>0 && $this->grant->manager==false) + if($oDocument->isExists()) { - return new Object(-1, 'msg_protect_content'); + if($this->module_info->protect_document_regdate > 0 && $this->grant->manager == false) + { + if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_document'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } + } + if($this->module_info->protect_content == "Y" || $this->module_info->protect_update_content == 'Y') + { + if($oDocument->get('comment_count') > 0 && $this->grant->manager == false) + { + return new Object(-1, 'msg_protect_update_content'); + } + } } if($member_info->is_admin == 'Y' && $logged_info->is_admin != 'Y') { @@ -806,9 +821,22 @@ class boardView extends board return $this->setTemplateFile('input_password_form'); } - if($this->module_info->protect_content=="Y" && $oDocument->get('comment_count')>0 && $this->grant->manager==false) + if($this->module_info->protect_document_regdate > 0 && $this->grant->manager == false) { - return $this->dispBoardMessage('msg_protect_content'); + if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_document'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } + } + + if($this->module_info->protect_content == "Y" || $this->module_info->protect_delete_content == 'Y') + { + if($oDocument->get('comment_count')>0 && $this->grant->manager == false) + { + return new Object(-1,'msg_protect_delete_content'); + } } Context::set('oDocument',$oDocument); @@ -955,6 +983,23 @@ class boardView extends board $oMemberModel = getModel('member'); $member_info = $oMemberModel->getMemberInfoByMemberSrl($oComment->member_srl); + if($this->module_info->protect_comment_regdate > 0 && $this->grant->manager == false) + { + if($oComment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_comment'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } + } + if($this->module_info->protect_update_comment === 'Y' && $this->grant->manager == false) + { + $childs = $oCommentModel->getChildComments($comment_srl); + if(count($childs) > 0) + { + return new Object(-1, 'msg_board_update_protect_comment'); + } + } if($member_info->is_admin == 'Y' && $logged_info->is_admin != 'Y') { @@ -1006,6 +1051,26 @@ class boardView extends board $oComment = $oCommentModel->getComment($comment_srl, $this->grant->manager); } + if($this->module_info->protect_comment_regdate > 0 && $this->grant->manager == false) + { + if($oComment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) + { + $format = Context::getLang('msg_protect_regdate_comment'); + $massage = sprintf($format, $this->module_info->protect_document_regdate); + return new Object(-1, $massage); + } + } + + if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false) + { + $oCommentModel = getModel('comment'); + $childs = $oCommentModel->getChildComments($comment_srl); + if(count($childs) > 0) + { + return new Object(-1, 'msg_board_delete_protect_comment'); + } + } + // if the comment is not existed, then back to the board content page if(!$oComment->isExists() ) { diff --git a/modules/board/lang/ko.php b/modules/board/lang/ko.php index e6fc59258..ce76b6e86 100644 --- a/modules/board/lang/ko.php +++ b/modules/board/lang/ko.php @@ -42,8 +42,14 @@ $lang->hide_category = '분류 숨기기'; $lang->about_hide_category = '임시로 분류를 사용하지 않으려면 체크하세요.'; $lang->protect_content = '글 보호 기능'; $lang->protect_comment = '댓글 보호 기능'; -$lang->about_protect_content = '작성된 글에 댓글이 작성된 경우 글 작성자는 해당 글을 수정하거나 삭제 할 수 없습니다. '; -$lang->msg_protect_content = '댓글이 작성된 게시물의 글을 수정 또는 삭제 할 수 없습니다.'; +$lang->protect_regdate = '기간 제한 기능'; +$lang->about_protect_regdate = '작성된 글이나 댓글의 작성기간이 설정한 기간보다 이전일일 경우 글을 수정 또는 삭제할 수 없도록 합니다. (단위 : day)'; +$lang->about_protect_content = '작성된 글에 댓글이 작성된 경우 글 작성자는 해당 글을 수정 또는 삭제를 할 수 없습니다.'; +$lang->msg_protect_delete_content = '작성된 글에 댓글이 작성된 경우 글 작성자는 해당 글을 삭제할 수 없습니다. '; +$lang->msg_protect_update_content = '작성된 글에 댓글이 작성된 경우 글 작성자는 해당 글을 수정할 수 없습니다. '; $lang->msg_admin_document_no_modify = '최고관리자의 게시물을 수정할 권한이 없습니다.'; $lang->msg_admin_comment_no_modify = '최고관리자의 댓글을 수정할 권한이 없습니다.'; -$lang->msg_board_protect_comment = '댓글이 작성된 댓글의 글을 수정 또는 삭제할 수 없습니다.'; +$lang->msg_board_delete_protect_comment = '댓글이 작성된 댓글의 글을 삭제할 수 없습니다.'; +$lang->msg_board_update_protect_comment = '댓글이 작성된 댓글의 글을 수정할 수 없습니다.'; +$lang->msg_protect_regdate_document = '%s일 이전의 게시글은 수정 또는 삭제 할 수 없습니다.'; +$lang->msg_protect_regdate_comment = '%s일 이전의 댓글은 수정 또는 삭제 할 수 없습니다.'; \ No newline at end of file diff --git a/modules/board/tpl/board_insert.html b/modules/board/tpl/board_insert.html index c941f9974..ad2e7c176 100644 --- a/modules/board/tpl/board_insert.html +++ b/modules/board/tpl/board_insert.html @@ -202,13 +202,25 @@
- + + +

{$lang->about_protect_content}

- + + +

{$lang->about_protect_comment}

+
+
+
+ +
+ {$lang->document} : + {$lang->comment} : +

{$lang->about_protect_regdate}

diff --git a/tests/Unit/framework/DateTimeTest.php b/tests/Unit/framework/DateTimeTest.php index e25f0e424..0c0708b12 100644 --- a/tests/Unit/framework/DateTimeTest.php +++ b/tests/Unit/framework/DateTimeTest.php @@ -62,6 +62,35 @@ class DateTimeTest extends \Codeception\TestCase\Test Rhymix\Framework\Config::set('locale.internal_timezone', 10800); } + public function testGetInternalDateTime() + { + $timestamp = 1454000000; + + // Test zdate() when the internal time zone is different from the default time zone. + Rhymix\Framework\Config::set('locale.internal_timezone', 10800); + $this->assertEquals('20160128195320', getInternalDateTime($timestamp)); + + // Test zdate() when the internal time zone is the same as the default time zone. + Rhymix\Framework\Config::set('locale.internal_timezone', 32400); + $this->assertEquals('20160129015320', getInternalDateTime($timestamp)); + } + + public function testGetTimeGap() + { + Context::getInstance()->lang = Rhymix\Framework\Lang::getInstance('en'); + Context::getInstance()->lang->loadPlugin('common'); + + // Test getTimeGap() when the internal time zone is different from the default time zone. + Rhymix\Framework\Config::set('locale.internal_timezone', 10800); + $this->assertEquals('30 minutes ago', getTimeGap(getInternalDateTime(RX_TIME - 1800))); + $this->assertEquals('2 hours ago', getTimeGap(getInternalDateTime(RX_TIME - 6000))); + + // Test getTimeGap() when the internal time zone is the same as the default time zone. + Rhymix\Framework\Config::set('locale.internal_timezone', 32400); + $this->assertEquals('30 minutes ago', getTimeGap(getInternalDateTime(RX_TIME - 1800))); + $this->assertEquals('2 hours ago', getTimeGap(getInternalDateTime(RX_TIME - 6000))); + } + public function testGetTimezoneForCurrentUser() { // Test when the current user's time zone is different from the system default. @@ -82,16 +111,19 @@ class DateTimeTest extends \Codeception\TestCase\Test $_SESSION['timezone'] = 'America/Chicago'; $this->assertEquals('20160128 105320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_winter)); $this->assertEquals('20150728 115320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_summer)); + $this->assertEquals('20150728 115320', getDisplayDateTime($timestamp_summer, 'Ymd His')); // Test when the current user's time zone is in the Southern hemisphere with DST. $_SESSION['timezone'] = 'Pacific/Auckland'; $this->assertEquals('20160129 055320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_winter)); $this->assertEquals('20150729 045320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_summer)); + $this->assertEquals('20150729 045320', getDisplayDateTime($timestamp_summer, 'Ymd His')); // Test when the current user's time zone is the same as the system default without DST. unset($_SESSION['timezone']); $this->assertEquals('20160129 015320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_winter)); $this->assertEquals('20150729 015320', Rhymix\Framework\DateTime::formatTimestampForCurrentUser('Ymd His', $timestamp_summer)); + $this->assertEquals('20150729 015320', getDisplayDateTime($timestamp_summer, 'Ymd His')); } public function testGetTimezoneList() @@ -131,5 +163,8 @@ class DateTimeTest extends \Codeception\TestCase\Test { $this->assertEquals('Etc/GMT-9', Rhymix\Framework\DateTime::getTimezoneNameByOffset(32400)); $this->assertEquals('Etc/GMT+5', Rhymix\Framework\DateTime::getTimezoneNameByOffset(-18000)); + $this->assertEquals('Etc/UTC', Rhymix\Framework\DateTime::getTimezoneNameByOffset(0)); + $this->assertEquals('Asia/Kolkata', Rhymix\Framework\DateTime::getTimezoneNameByOffset(19800)); + $this->assertEquals('Australia/Eucla', Rhymix\Framework\DateTime::getTimezoneNameByOffset(31500)); } }