Compare commits

...

55 commits

Author SHA1 Message Date
Lastorder-DC
48a5278a8e Fanbinit 0302 2026-03-02 13:23:56 +09:00
Copilot
fc0e8a9843
Add admin login-as (impersonate) feature to member admin list (#4)
Co-authored-by: Lastorder-DC <18280396+Lastorder-DC@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
2026-03-02 13:17:40 +09:00
Lastorder
fdb1f8269b
Merge branch 'rhymix:master' into master 2026-03-02 13:04:15 +09:00
Kijin Sung
cdb520d2b1 Preserve module_srl after managing document #2683 2026-03-01 23:32:39 +09:00
Kijin Sung
2392b923b0 Fix reference to potentially undefined config variable 2026-02-27 20:51:30 +09:00
Kijin Sung
6386ddfe27 Fix warnings when user is logged out #2680 2026-02-27 20:51:07 +09:00
Kijin Sung
798b0cd1d6 Fix warnings when user is logged out #2680 2026-02-27 20:46:49 +09:00
Kijin Sung
73e153be60 Fix warnings when logged_info is false #2680 2026-02-27 20:46:32 +09:00
Lastorder-DC
89bab34d8b Merge branch 'master' of github.com:Lastorder-DC/rhymix 2026-02-27 18:04:51 +09:00
Lastorder
25f6d02677
Merge branch 'rhymix:master' into master 2026-02-27 18:04:35 +09:00
Kijin Sung
840a9adac8 Version 2.1.31 2026-02-26 13:18:24 +09:00
Kijin Sung
2ede904d56 Ensure that the default version of jQuery and jQuery Migrate are always loaded during install 2026-02-26 13:15:12 +09:00
Kijin Sung
465248a7a4 Update jQuery Migrate to 3.6.0 2026-02-26 13:10:47 +09:00
Kijin Sung
d0d1505367 Enable secure session and cookies by default if installed or upgraded in an HTTPS site 2026-02-26 01:25:36 +09:00
Kijin Sung
7ce40653d7 Use jQuery 3.x by default 2026-02-26 01:23:10 +09:00
Kijin Sung
f0f73c6ac8 Update jQuery to 3.7.1 and recommend updating 2026-02-26 01:21:19 +09:00
Kijin Sung
74b9533281 Merge branch 'security/rve-2026-2' 2026-02-25 20:39:06 +09:00
Kijin Sung
bcda659add Merge branch 'security/rve-2026-1' 2026-02-25 20:39:04 +09:00
Kijin Sung
ed68509c98 Add comment to DocumentItem::getBrowserTitle() 2026-02-24 17:08:28 +09:00
Kijin Sung
4c91040c35 Rename misleading label for list_order sort 2026-02-24 17:05:59 +09:00
Kijin Sung
cb947abb76 Remove unreasonable list_count default 2026-02-23 13:55:37 +09:00
Kijin Sung
47e54bc564 Fix typo in XML filter file #2679 2026-02-23 13:55:17 +09:00
Lastorder
fffa08d61f
Merge branch 'rhymix:master' into master 2026-02-22 22:45:33 +09:00
Kijin Sung
37b23341be Fix template path error in mobile document page #2679 2026-02-22 20:18:05 +09:00
Kijin Sung
a53e293a5a Support searching admin memo in member list #2676 2026-02-21 21:51:41 +09:00
Kijin Sung
d47dd2d824 Remove reference to old themes in layout module 2026-02-21 21:45:48 +09:00
Kijin Sung
18401d2688 Remove reference to old theme file #2677 2026-02-21 21:41:35 +09:00
Kijin Sung
e4c60b56d4 Add unit tests for Security::sanitize() supporting SVG 2026-02-20 21:57:35 +09:00
Kijin Sung
91744ec87c Always download SVG as attachment 2026-02-20 21:57:07 +09:00
Kijin Sung
bf2df84d0f Use enshrined\svgSanitize to clean SVG file content 2026-02-20 21:55:29 +09:00
Kijin Sung
a18b45f0f8 Strip namespace prefixes before checking dangerous tags in SVG 2026-02-20 21:40:37 +09:00
Kijin Sung
187bffe9d2 Fix unit test for Validator 2026-02-16 21:59:14 +09:00
Kijin Sung
f131a616eb Fix RVE-2026-1 arbitrary file association by extra var 2026-02-16 21:56:44 +09:00
Lastorder-DC
752b51c78f spammer update 2026-02-15 22:28:44 +09:00
Lastorder
aba6016986
Merge branch 'rhymix:master' into master 2026-02-12 14:03:54 +09:00
Kijin Sung
c5d453a2df #2675 보완 및 최적화 2026-02-11 21:02:50 +09:00
Kijin Sung
5834a3c18a Fix fatal error in some environments when relative URL is passed to encodeIdna() or decodeIdna() #2675 2026-02-11 20:54:00 +09:00
Kijin Sung
1199095e7f Version 2.1.30 2026-02-10 12:23:00 +09:00
Kijin Sung
ad1617b17c Show clickable list of layout instances in "installed layout" page 2026-02-09 21:40:56 +09:00
Kijin Sung
59f95fe099 Remove outdated filter files in admin module 2026-02-08 11:08:37 +09:00
Kijin Sung
ee5418d9d5 Clean up message module config JS 2026-02-08 11:02:50 +09:00
Kijin Sung
b9a512c007 Fix add IP to spamfilter menu not working 2026-02-08 10:56:28 +09:00
Kijin Sung
4339d01a75 Update Daum/Kakao postcode API URL #2672 2026-02-07 21:10:34 +09:00
Kijin Sung
0e013367a0 Fix misspelled variables and incorrect config references 2026-02-06 21:48:23 +09:00
Kijin Sung
867014d0f4 Don't filter by extra var lang when sorting by numeric value 2026-02-06 18:13:40 +09:00
Kijin Sung
2f8c4ca77d Enable customizing the number of comments/replies required to prevent editing or deleting a post 2026-02-06 18:06:16 +09:00
Lastorder
bbd62dbea3
Merge branch 'rhymix:master' into master 2026-02-06 09:51:56 +09:00
Kijin Sung
5a8c669c42 Fix duplicated layout info when layout.html (or layout.blade.php) does not exist #2132 #2670 2026-02-05 23:16:38 +09:00
Kijin Sung
26c59c251c Fix incorrect conversion of JS template variable containing path #2657 2026-02-05 23:05:19 +09:00
Kijin Sung
8920cb7491 Fix incorrect path conversion on Windows #2667 2026-02-05 22:39:33 +09:00
Kijin Sung
d824bc9da3 Clean up method of loading default sender info #2661 2026-02-05 22:36:31 +09:00
Kijin Sung
d9a6c577fd Restore available fields in password reset email #2663 2026-02-05 22:26:24 +09:00
Kijin Sung
9d1738e21d Add trigger before auto-login #2665 #2666 2026-02-05 22:14:06 +09:00
Lastorder-DC
0518b04fff remove debug 2026-02-05 18:26:12 +09:00
Lastorder-DC
f343dff713 fanbinit 0205 2026-02-05 18:24:58 +09:00
97 changed files with 1463 additions and 1505 deletions

View file

@ -7,8 +7,8 @@ class HTMLDisplayHandler
*/
public const JQUERY_V2 = '2.2.4';
public const JQUERY_V2_MIGRATE = '1.4.1';
public const JQUERY_V3 = '3.6.3';
public const JQUERY_V3_MIGRATE = '3.4.0';
public const JQUERY_V3 = '3.7.1';
public const JQUERY_V3_MIGRATE = '3.6.0';
/**
* Default viewport setting
@ -746,7 +746,8 @@ class HTMLDisplayHandler
*/
private function _loadCommonJSCSS()
{
if (config('view.jquery_version') === 3)
$jquery_version = config('view.jquery_version') ?: 2;
if ($jquery_version == 3)
{
$jquery_version = self::JQUERY_V3;
$jquery_migrate_version = self::JQUERY_V3_MIGRATE;

View file

@ -3,7 +3,7 @@
/**
* RX_VERSION is the version number of the Rhymix CMS.
*/
define('RX_VERSION', '2.1.29');
define('RX_VERSION', '2.1.31');
/**
* RX_MICROTIME is the startup time of the current script, in microseconds since the Unix epoch.

View file

@ -90,7 +90,7 @@ return array(
'minify_scripts' => 'common',
'concat_scripts' => 'none',
'delay_compile' => 0,
'jquery_version' => 2,
'jquery_version' => 3,
),
'admin' => array(
'allow' => array(),

View file

@ -38,6 +38,12 @@ class Security
if (!utf8_check($input)) return false;
return Filters\FilenameFilter::clean($input);
// Clean up SVG content to prevent various attacks.
case 'svg':
if (!utf8_check($input)) return false;
$sanitizer = new \enshrined\svgSanitize\Sanitizer();
return strval($sanitizer->sanitize($input));
// Unknown filters.
default:
throw new Exception('Unknown filter type for sanitize: ' . $type);

View file

@ -380,7 +380,7 @@ class Session
self::$_autologin_key = self::_getAutologinKey();
if (!$member_srl && self::$_autologin_key)
{
$member_srl = \MemberController::getInstance()->doAutologin(self::$_autologin_key);
$member_srl = \MemberController::doAutoLogin(self::$_autologin_key);
if ($member_srl && self::isValid($member_srl))
{
self::login($member_srl, false);

View file

@ -528,7 +528,7 @@ class Template
*/
public function isRelativePath(string $path): bool
{
return !preg_match('#^((?:https?|file|data):|[\/\{<])#i', $path);
return !preg_match('#^((?:https?|file|data):|[\/\{\\\\<$\#@]|&\#x1B;)#i', $path);
}
/**

View file

@ -207,9 +207,13 @@ class URL
*/
public static function encodeIdna(string $url): string
{
if (preg_match('@[:/#]@', $url))
if (!preg_match('@^/(?!/)@', $url) && preg_match('@[:/#]@', $url))
{
$domain = parse_url($url, \PHP_URL_HOST);
if (!$domain)
{
return $url;
}
$position = strpos($url, $domain);
if ($position === false)
{
@ -243,9 +247,13 @@ class URL
*/
public static function decodeIdna(string $url): string
{
if (preg_match('@[:/#]@', $url))
if (!preg_match('@^/(?!/)@', $url) && preg_match('@[:/#]@', $url))
{
$domain = parse_url($url, \PHP_URL_HOST);
if (!$domain)
{
return $url;
}
$position = strpos($url, $domain);
if ($position === false)
{

View file

@ -44,7 +44,7 @@ class FileContentFilter
$skip_xml = preg_match('/^(hwpx)$/', $ext);
// Check SVG files.
if (($ext === 'svg' || $is_xml) && !self::_checkSVG($fp, 0, $filesize))
if (($ext === 'svg' || $is_xml) && !self::_checkSVG($fp, 0, $filesize, $ext))
{
fclose($fp);
return false;
@ -89,11 +89,12 @@ class FileContentFilter
* @param resource $fp
* @param int $from
* @param int $to
* @param string $ext
* @return bool
*/
protected static function _checkSVG($fp, $from, $to)
protected static function _checkSVG($fp, $from, $to, $ext)
{
if (self::_matchStream('/(?:<|&lt;)(?:script|iframe|foreignObject|object|embed|handler)|javascript:|xlink:href\s*=\s*"(?!data:)/i', $fp, $from, $to))
if (self::_matchStream('/(?:<|&lt;|:)(?:script|iframe|foreignObject|object|embed|handler)|javascript:|(?:\s|:)href\s*=\s*"(?!data:)/i', $fp, $from, $to))
{
return false;
}

View file

@ -184,6 +184,8 @@ class ConfigParser
if (isset($db_info->use_ssl) && in_array($db_info->use_ssl, ['always', 'optional']))
{
$config['url']['ssl'] = 'always';
$config['session']['use_ssl'] = true;
$config['session']['use_ssl_cookies'] = true;
}
else
{

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load diff

2
common/js/jquery-3.7.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -359,6 +359,7 @@ $lang->filter['invalid_alpha_number'] = 'The format of %s is invalid. Please ent
$lang->filter['invalid_mid'] = 'The format of %s is invalid. Module ID should be begun with a letter. Subsequent characters may be letters, digits or underscore characters.';
$lang->filter['invalid_number'] = 'The format of %s is invalid. Please enter numbers only.';
$lang->filter['invalid_float'] = 'The format of %s is invalid. Please enter numbers only.';
$lang->filter['invalid_file'] = 'The value of %s is not a valid file upload.';
$lang->filter['invalid_extension'] = 'The format of %s is invalid. e.g. gif, jpg, png';
$lang->security_warning_embed = 'Due to security concern, administrators are not allowed to view embedded items.<BR /> To view them, please use another non-administrator ID.';
$lang->msg_pc_to_mobile = 'View mobile optimized version of this page';

View file

@ -359,6 +359,7 @@ $lang->filter['invalid_alpha_number'] = '%s의 형식이 잘못되었습니다.
$lang->filter['invalid_mid'] = '%s의 형식이 잘못되었습니다. 첫 글자는 영문으로 시작해야 하며 \'영문+숫자+_\'로만 입력해야 합니다.';
$lang->filter['invalid_number'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.';
$lang->filter['invalid_float'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.';
$lang->filter['invalid_file'] = '%s의 값은 올바르게 업로드된 파일이 아닙니다.';
$lang->filter['invalid_extension'] = '%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.';
$lang->security_invalid_session = '바르지 않은 접근입니다. 인증을 위해 다시 로그인해야 합니다.';
$lang->security_warning_embed = '보안 문제로 관리자 아이디로는 embed를 볼 수 없습니다. 확인하려면 다른 아이디로 접속하세요';

View file

@ -209,7 +209,7 @@
<a href="#" title="{$lang->cmd_search}"><i class="xi-magnifier"></i><span class="blind">{$lang->cmd_search}</span></a>
</li>
<!-- admin -->
<li cond="$logged_info->is_admin == 'Y'">
<li cond="$logged_info && $logged_info->is_admin == 'Y'">
<a href="{getUrl('', 'module', 'admin')}" target="_blank" title="{$lang->cmd_management}"><i class="xi-cog"></i><span class="blind">{$lang->cmd_management}</span></a>
</li>
<!-- login -->

View file

@ -369,6 +369,7 @@ class Cleanup extends Base
'modules/admin/tpl/css/admin_en.css' => 'deleted:xe',
'modules/admin/tpl/css/admin_jp.css' => 'deleted:xe',
'modules/admin/tpl/css/admin_ko.css' => 'deleted:xe',
'modules/admin/tpl/filter/' => 'deleted:xe',
'modules/autoinstall/ruleset/' => 'deleted:xe',
'modules/autoinstall/tpl/filter/uninstall_package.xml' => 'deleted:xe',
'modules/board/board.wap.php' => 'deleted:xe',
@ -441,6 +442,7 @@ class Cleanup extends Base
'modules/install/tpl/js/install_admin.js' => 'deleted:xe',
'modules/integration_search/skins/default/trackback.html' => 'deleted',
'modules/member/skins/default/filter/find_member_account_by_question.xml' => 'deleted:xe',
'modules/message/tpl/filter/' => 'deleted:xe',
'modules/module/schemas/site_admin.xml' => 'deleted',
'modules/module/tpl/css/module_admin.less' => 'deleted',
'modules/page/page.wap.php' => 'deleted:xe',

View file

@ -20,17 +20,16 @@ class Notification extends Base
public function dispAdminConfigNotification()
{
// Load advanced mailer module (for lang).
$oAdvancedMailerAdminView = \Advanced_mailerAdminView::getInstance();
$oAdvancedMailerController = \Advanced_mailerController::getInstance();
// Load advanced mailer config.
$advanced_mailer_config = $oAdvancedMailerAdminView->getConfig();
$advanced_mailer_config = $oAdvancedMailerController->getConfig();
Context::set('advanced_mailer_config', $advanced_mailer_config);
// Load member config.
$member_config = ModuleModel::getModuleConfig('member');
Context::set('member_config', $member_config);
Context::set('webmaster_name', !empty($member_config->webmaster_name) ? $member_config->webmaster_name : 'webmaster');
Context::set('webmaster_email', $member_config->webmaster_email ?? '');
$default_identity = $oAdvancedMailerController->getDefaultEmailIdentity();
Context::set('webmaster_name', $default_identity[1]);
Context::set('webmaster_email', $default_identity[0]);
// Load module config.
$module_config = ModuleModel::getModuleConfig('module');
@ -89,7 +88,7 @@ class Notification extends Base
$vars = Context::getRequestVars();
// Load advanced mailer module (for lang).
$oAdvancedMailerAdminView = \Advanced_mailerAdminView::getInstance();
$oAdvancedMailerController = \Advanced_mailerController::getInstance();
// Validate the mail sender's information.
if (!$vars->mail_default_name)

View file

@ -159,7 +159,7 @@ $lang->cmd_concat_js_only = 'Combine all JS';
$lang->cmd_concat_css_js = 'Combine both CSS and JS';
$lang->about_concat_scripts = 'Automatically combine CSS and JS scripts into as few files as possible. External scripts are not combined.';
$lang->jquery_version = 'jQuery Version';
$lang->about_jquery_version = 'You can select the default jQuery version for this site. Please note that jQuery 3.x may not be compatible with older features.';
$lang->about_jquery_version = 'You can select the default jQuery version for this site. Older third-party programs may require 2.x, but Rhymix recommends 3.x or higher for security.';
$lang->use_gzip = 'gzip Compression';
$lang->about_use_gzip = 'This option should be left off unless you know for sure that your webserver doesn\'t compress output by default.';
$lang->delay_session = 'Delay session start';

View file

@ -160,7 +160,7 @@ $lang->cmd_concat_js_only = 'JS만 합침';
$lang->cmd_concat_css_js = 'CSS와 JS를 모두 합침';
$lang->about_concat_scripts = 'CSS, JS 파일들을 하나로 합쳐서 전송합니다. 외부에서 로딩하는 스크립트는 합쳐지지 않습니다.';
$lang->jquery_version = 'jQuery 버전';
$lang->about_jquery_version = '기본으로 사용할 jQuery 버전을 선택합니다. jQuery 3.x는 오래된 기능과 호환되지 않을 수 있습니다.';
$lang->about_jquery_version = '기본으로 사용할 jQuery 버전을 선택합니다. 오래된 확장 기능은 jQuery 2.x를 요구할 수 있으나, 보안상 3.x 이상을 추천합니다.';
$lang->use_gzip = 'gzip 압축';
$lang->about_use_gzip = '웹서버가 gzip을 지원하지 않더라도 페이지를 강제로 압축하는 기능입니다. 대부분의 서버에는 필요하지 않습니다.';
$lang->delay_session = '세션 시작 지연';

View file

@ -1,12 +0,0 @@
<filter name="install_ftp_info" module="install" act="procInstallAdminSaveFTPInfo" >
<form>
<node target="ftp_user" required="true" />
<node target="ftp_port" required="false" filter="number" />
<node target="ftp_root_path" required="true" />
<node target="sftp" />
</form>
<response callback_func="completeMessage">
<tag name="error" />
<tag name="message" />
</response>
</filter>

View file

@ -1,9 +0,0 @@
<filter name="install_ftp_path" module="install" act="procInstallAdminSaveFTPPath" confirm_msg_code="confirm_submit">
<form>
<node target="ftp_root_path" required="true" />
</form>
<response callback_func="completeFtpPath">
<tag name="error" />
<tag name="message" />
</response>
</filter>

View file

@ -1,9 +0,0 @@
<filter name="update_env_config" module="install" act="procInstallAdminSaveTimeZone" >
<form>
<node target="time_zone" required="true" />
</form>
<response callback_func="completeMessage">
<tag name="error" />
<tag name="message" />
</response>
</filter>

View file

@ -1,7 +0,0 @@
<filter name="update_lang_select" module="install" act="procInstallAdminSaveLangSelected" >
<form />
<response callback_func="completeMessage">
<tag name="error" />
<tag name="message" />
</response>
</filter>

View file

@ -347,9 +347,14 @@ jQuery(function($){
$.fn.checkToggle = function(){
function check(){
setTimeout(function(){
$(':checked').parent('label').addClass('checked');
$(':not(":checked")').parent('label').removeClass('checked');
},0);
$(':radio, :checkbox').each(function() {
if ($(this).is(':checked')) {
$(this).parent('label').addClass('checked');
} else {
$(this).parent('label').removeClass('checked');
}
});
}, 0);
}
this.change(check);
check();

View file

@ -58,7 +58,21 @@ class BoardAdminController extends Board {
if($args->use_anonymous != 'Y') $args->use_anonymous = 'N';
if($args->anonymous_except_admin != 'Y') $args->anonymous_except_admin = 'N';
if($args->consultation != 'Y') $args->consultation = 'N';
if($args->protect_content != 'Y') $args->protect_content = 'N';
// Protection settings
if ($args->protect_content != 'Y') $args->protect_content = 'N';
if ($args->protect_document_regdate === 'Y')
{
$args->protect_document_regdate = intval($args->protect_document_regdate_limit ?? 0) ?: null;
}
if ($args->protect_comment_regdate === 'Y')
{
$args->protect_comment_regdate = intval($args->protect_comment_regdate_limit ?? 0) ?: null;
}
unset($args->protect_document_regdate_limit);
unset($args->protect_comment_regdate_limit);
// Admin protection settings
if($this->user->isAdmin())
{
if($args->protect_admin_content_update != 'Y') $args->protect_admin_content_update = 'N';

View file

@ -58,7 +58,7 @@ class BoardAdminView extends Board {
// install order (sorting) options
foreach($this->order_target as $key) $order_target[$key] = lang($key);
$order_target['list_order'] = lang('document_srl');
$order_target['list_order'] = lang('default_value');
$order_target['update_order'] = lang('last_update');
Context::set('order_target', $order_target);
}

View file

@ -171,9 +171,10 @@ class BoardController extends Board
// Protect document by comment
if($this->module_info->protect_content == 'Y' || $this->module_info->protect_update_content == 'Y')
{
if($oDocument->get('comment_count') > 0 && !$this->grant->manager)
$comment_limit = $this->module_info->protect_update_content_limit ?? 1;
if($oDocument->get('comment_count') >= $comment_limit && !$this->grant->manager)
{
throw new Rhymix\Framework\Exception('msg_protect_update_content');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_protect_update_content'), $comment_limit));
}
}
@ -358,9 +359,10 @@ class BoardController extends Board
// check protect content
if($this->module_info->protect_content == 'Y' || $this->module_info->protect_delete_content == 'Y')
{
if($oDocument->get('comment_count') > 0 && $this->grant->manager == false)
$comment_limit = $this->module_info->protect_delete_content_limit ?? 1;
if($oDocument->get('comment_count') >= $comment_limit && $this->grant->manager == false)
{
throw new Rhymix\Framework\Exception('msg_protect_delete_content');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_protect_delete_content'), $comment_limit));
}
}
@ -538,10 +540,11 @@ class BoardController extends Board
$comment = CommentModel::getComment($obj->comment_srl);
if($this->module_info->protect_update_comment === 'Y' && $this->grant->manager == false)
{
$childs_limit = $this->module_info->protect_update_comment_limit ?? 1;
$childs = CommentModel::getChildComments($obj->comment_srl);
if(count($childs) > 0)
if(count($childs) >= $childs_limit)
{
throw new Rhymix\Framework\Exception('msg_board_update_protect_comment');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_board_update_protect_comment'), $childs_limit));
}
}
}
@ -594,11 +597,11 @@ class BoardController extends Board
{
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')))
if($comment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_comment_regdate.' day')))
{
$format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage);
$message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($message);
}
}
// check the grant
@ -656,10 +659,11 @@ class BoardController extends Board
$childs = null;
if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false)
{
$childs_limit = $this->module_info->protect_delete_comment_limit ?? 1;
$childs = CommentModel::getChildComments($comment_srl);
if(count($childs) > 0)
if(count($childs) >= $childs_limit)
{
throw new Rhymix\Framework\Exception('msg_board_delete_protect_comment');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_board_delete_protect_comment'), $childs_limit));
}
}
@ -674,11 +678,11 @@ class BoardController extends Board
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')))
if($comment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_comment_regdate.' day')))
{
$format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage);
$message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($message);
}
}
// generate comment controller object

View file

@ -547,7 +547,13 @@ class BoardView extends Board
$args->page = intval(Context::get('page')) ?: null;
$args->list_count = $this->list_count;
$args->page_count = $this->page_count;
if(Context::get('v_mode') == 'recommended') $args->s_voted_count = Rhymix\Modules\Yeokbox\Models\Config::getVoteCount();
if(Context::get('v_mode') == 'recommended') {
$args->s_voted_count = Rhymix\Modules\Yeokbox\Models\Config::getVoteCount();
}
if(Context::get('v_mode') == 'super_recommended') {
$args->s_voted_count = Rhymix\Modules\Yeokbox\Models\Config::getSuperVoteCount();
$args->s_readed_count = Rhymix\Modules\Yeokbox\Models\Config::getReadCount();
}
if (isset($this->module_info->include_days) && $this->module_info->include_days > 0)
{
$args->start_regdate = date('YmdHis', time() - ($this->module_info->include_days * 86400));
@ -873,15 +879,16 @@ class BoardView extends Board
if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
{
$format = lang('msg_protect_regdate_document');
$massage = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage);
$message = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($message);
}
}
if ($this->module_info->protect_content === 'Y' || $this->module_info->protect_update_content === 'Y')
{
if($oDocument->get('comment_count') > 0 && $this->grant->manager == false)
$comment_limit = $this->module_info->protect_update_content_limit ?? 1;
if($oDocument->get('comment_count') >= $comment_limit && $this->grant->manager == false)
{
throw new Rhymix\Framework\Exception('msg_protect_update_content');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_protect_update_content'), $comment_limit));
}
}
@ -913,7 +920,7 @@ class BoardView extends Board
$point_config = ModuleModel::getModulePartConfig('point',$this->module_srl);
if ($point_config)
{
$pointForInsert = intval(is_object($point_config) ? $point_config->insert_document : $point_config["insert_document"]);
$pointForInsert = intval(is_object($point_config) ? ($point_config->insert_document ?? 0) : ($point_config["insert_document"] ?? 0));
}
else
{
@ -1096,17 +1103,18 @@ class BoardView extends Board
{
if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
{
$format = lang('msg_protect_regdate_document');
$massage = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage);
$format = lang('msg_protect_regdate_document');
$message = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($message);
}
}
if($this->module_info->protect_content == "Y" || $this->module_info->protect_delete_content == 'Y')
{
if($oDocument->get('comment_count')>0 && $this->grant->manager == false)
$comment_limit = $this->module_info->protect_delete_content_limit ?? 1;
if($oDocument->get('comment_count') >= $comment_limit && $this->grant->manager == false)
{
throw new Rhymix\Framework\Exception('msg_protect_delete_content');
return $this->dispBoardMessage(sprintf(lang('msg_protect_delete_content'), $comment_limit));
}
}
@ -1291,19 +1299,20 @@ class BoardView extends Board
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')))
if($oComment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_comment_regdate.' day')))
{
$format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage);
$format = lang('msg_protect_regdate_comment');
$message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($message);
}
}
if($this->module_info->protect_update_comment === 'Y' && $this->grant->manager == false)
{
$childs_limit = $this->module_info->protect_update_comment_limit ?? 1;
$childs = CommentModel::getChildComments($comment_srl);
if(count($childs) > 0)
if(count($childs) >= $childs_limit)
{
throw new Rhymix\Framework\Exception('msg_board_update_protect_comment');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_board_update_protect_comment'), $childs_limit));
}
}
@ -1378,20 +1387,21 @@ class BoardView extends Board
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')))
if($oComment->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_comment_regdate.' day')))
{
$format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage);
$message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($message);
}
}
if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false)
{
$childs_limit = $this->module_info->protect_delete_comment_limit ?? 1;
$childs = CommentModel::getChildComments($comment_srl);
if(count($childs) > 0)
if(count($childs) >= $childs_limit)
{
throw new Rhymix\Framework\Exception('msg_board_delete_protect_comment');
throw new Rhymix\Framework\Exception(sprintf(lang('msg_board_delete_protect_comment'), $childs_limit));
}
}

View file

@ -44,7 +44,6 @@ $lang->about_secret = 'Users will be able to write secret posts or comments.';
$lang->about_admin_mail = 'Send an e-mail when a new post or comment is submitted. Separate multiple recipients with a comma.';
$lang->about_list_config = 'If using list-style skin, you may arrange items to display. However, this feature might not be availble for non-official skins. If you double-click target items and display items, then you can add / remove them';
$lang->about_use_status = 'Please select status that can be selected when you write a post.';
$lang->about_protect_comment = 'Prevent updating or deleting a comment if it has children.';
$lang->about_update_log = 'Store a log of every version of a post every time it is updated.';
$lang->skip_bottom_list_for_olddoc = 'Do not calculate the bottom list exactly when viewing an old post.';
$lang->skip_bottom_list_for_robot = 'Do not calculate the bottom list exactly when a robot is visiting.';
@ -59,7 +58,7 @@ $lang->hide_category = 'Hide categories';
$lang->about_hide_category = 'Temporarily disable categories. Existing categories will not be deleted.<br>Unless you select the option below, users may not be able to write anymore.';
$lang->allow_no_category = 'Do not require category';
$lang->about_allow_no_category = 'Allow posting without selecting a category.<br>Admins are never required to select a category.';
$lang->protect_content = 'Protect Content';
$lang->protect_content = 'Protect Post';
$lang->protect_comment = 'Protect Comment';
$lang->protect_admin_content = 'Protect Admin Content';
$lang->protect_regdate = 'Update/Delete Time Limit';
@ -73,15 +72,19 @@ $lang->about_inline_data_url_limit = 'Restrict data: URLs that can be used to ev
$lang->update_order_on_comment = 'Update Post on New Comment';
$lang->about_update_order_on_comment = 'When a new comment is posted, update the update timestamp of the parent post. This is needed for forums.';
$lang->about_filter_specialchars = 'Prevent use of excessive Unicode accents, RLO characters, and other symbols that hinder readability.';
$lang->about_protect_regdate = 'Prevent updating or deleting a post or comment after a certain amount of time has passed. (Unit: day)';
$lang->about_protect_content = 'Prevent updating a post if there are comments on it.';
$lang->about_protect_content_update = 'Prevent updating a post if it has %d or more comments.';
$lang->about_protect_content_delete = 'Prevent deleting a post if it has %d or more comments.';
$lang->about_protect_comment_update = 'Prevent updating a comment if it has %d or more replies.';
$lang->about_protect_comment_delete = 'Prevent deleting a comment if it has %d or more replies.';
$lang->about_protect_document_regdate = 'Prevent updating or deleting a post after %d days.';
$lang->about_protect_comment_regdate = 'Prevent updating or deleting a comment after %d days.';
$lang->about_protect_admin_content = 'Prevent updating or deleting a post or comment written by the administrator, even by a user who is permitted to manage the board.';
$lang->msg_protect_delete_content = 'You cannot delete a post with comments on it.';
$lang->msg_protect_update_content = 'You cannot update a post with comments on it.';
$lang->msg_protect_update_content = 'You cannot update a post with %d or more comments on it.';
$lang->msg_protect_delete_content = 'You cannot delete a post with %d or more comments on it.';
$lang->msg_board_update_protect_comment = 'You cannot update a comment with %d or more replies on it.';
$lang->msg_board_delete_protect_comment = 'You cannot delete a comment with %d or more replies on it.';
$lang->msg_admin_document_no_modify = 'You cannot edit the administrator\'s post.';
$lang->msg_admin_comment_no_modify = 'You cannot edit the administrator\'s comment.';
$lang->msg_board_delete_protect_comment = 'You cannot delete a comment when there are replies.';
$lang->msg_board_update_protect_comment = 'You cannot update a comment when there are replies.';
$lang->msg_protect_regdate_document = 'You cannot update or delete a post after %d days.';
$lang->msg_protect_regdate_comment = 'You cannot update or delete a comment after %d days.';
$lang->msg_dont_have_update_log = 'This post has no update log.';

View file

@ -44,7 +44,6 @@ $lang->about_secret = '게시판 및 댓글의 비밀글 기능을 사용할 수
$lang->about_admin_mail = '새 글이나 댓글이 등록되면 지정된 메일 주소로 알림을 받습니다. 여러 메일 주소를 지정하려면 쉼표(,)로 구분하세요.';
$lang->about_list_config = '게시판의 목록형식 사용시 원하는 항목들로 배치를 할 수 있습니다. 단 스킨에서 지원하지 않는 경우 불가능합니다. 대상항목/ 표시항목의 항목을 더블클릭하면 추가/ 제거가 됩니다.';
$lang->about_use_status = '글 작성 시 선택할 수 있는 상태를 지정해주세요.';
$lang->about_protect_comment = '댓글의 댓글이 있을경우 해당댓글을 삭제 및 수정을 할 수 없도록 합니다.';
$lang->about_update_log = '게시글을 수정할 경우 수정한 내역을 저장하도록 합니다.';
$lang->skip_bottom_list_for_olddoc = '오래된 게시물 열람시 하단 목록을 정확하게 계산하지 않음';
$lang->skip_bottom_list_for_robot = '로봇 방문시 하단 목록을 정확하게 계산하지 않음';
@ -73,15 +72,19 @@ $lang->about_inline_data_url_limit = 'data: URL을 사용하여 첨부 제한을
$lang->update_order_on_comment = '댓글 작성시 글 수정 시각 갱신';
$lang->about_update_order_on_comment = '댓글이 작성되면 해당 글의 수정 시각을 갱신합니다. 포럼형 게시판, 최근 댓글 표시 기능 등에 필요합니다.';
$lang->about_filter_specialchars = '가독성에 악영향을 주는 과도한 유니코드 악센트 기호의 조합, RLO 문자 등의 사용을 금지합니다.';
$lang->about_protect_regdate = '글이나 댓글을 작성한 후 일정 기간이 지나면 수정 또는 삭제할 수 없도록 합니다. (단위 : day)';
$lang->about_protect_content = '댓글이 달린 글은 수정 또는 삭제할 수 없도록 합니다.';
$lang->about_protect_content_update = '댓글이 %d개 이상 달린 글은 수정할 수 없도록 합니다.';
$lang->about_protect_content_delete = '댓글이 %d개 이상 달린 글은 삭제할 수 없도록 합니다.';
$lang->about_protect_comment_update = '대댓글이 %d개 이상 달린 댓글은 수정할 수 없도록 합니다.';
$lang->about_protect_comment_delete = '대댓글이 %d개 이상 달린 댓글은 삭제할 수 없도록 합니다.';
$lang->about_protect_document_regdate = '작성 후 %d일 이상 지난 글은 수정 또는 삭제할 수 없도록 합니다.';
$lang->about_protect_comment_regdate = '작성 후 %d일 이상 지난 댓글은 수정 또는 삭제할 수 없도록 합니다.';
$lang->about_protect_admin_content = '최고관리자가 작성한 글이나 댓글은 게시판 관리 권한이 있는 회원이라도 수정 또는 삭제할 수 없도록 합니다.';
$lang->msg_protect_delete_content = '댓글이 달린 글은 삭제할 수 없습니다.';
$lang->msg_protect_update_content = '댓글이 달린 글은 수정할 수 없습니다.';
$lang->msg_protect_update_content = '댓글이 %d개 이상 달린 글은 수정할 수 없습니다.';
$lang->msg_protect_delete_content = '댓글이 %d개 이상 달린 글은 삭제할 수 없습니다.';
$lang->msg_board_update_protect_comment = '대댓글이 %d개 이상 달린 댓글은 수정할 수 없습니다.';
$lang->msg_board_delete_protect_comment = '대댓글이 %d개 이상 달린 댓글은 삭제할 수 없습니다.';
$lang->msg_admin_document_no_modify = '최고관리자의 게시물을 수정할 권한이 없습니다.';
$lang->msg_admin_comment_no_modify = '최고관리자의 댓글을 수정할 권한이 없습니다.';
$lang->msg_board_delete_protect_comment = '대댓글이 달린 댓글은 삭제할 수 없습니다.';
$lang->msg_board_update_protect_comment = '대댓글이 달린 댓글은 수정할 수 없습니다.';
$lang->msg_protect_regdate_document = '%d일 이상 지난 글은 수정 또는 삭제할 수 없습니다.';
$lang->msg_protect_regdate_comment = '%d일 이상 지난 댓글은 수정 또는 삭제할 수 없습니다.';
$lang->msg_dont_have_update_log = '업데이트 로그가 기록되어 있지 않은 게시글입니다.';

View file

@ -72,8 +72,8 @@ $lang->about_filter_specialchars = '禁止使用影响阅读的内容的符号
$lang->about_non_login_vote = '非会员也可以推荐。';
$lang->about_protect_regdate = '发布帖子或回复过一定时间的话无法修改或删除。(单位:天)';
$lang->about_protect_content = '无法删除或修改有回复的帖子。';
$lang->msg_protect_delete_content = '无法删除有回复的帖子。';
$lang->msg_protect_update_content = '无法修改有回复的帖子。';
$lang->msg_protect_delete_content = '评论数超过 %d 条的帖子无法删除。';
$lang->msg_protect_update_content = '评论数超过 %d 条的帖子无法编辑。';
$lang->msg_admin_document_no_modify = '无法修改管理员的帖子。';
$lang->msg_admin_comment_no_modify = '无法修改管理员的回复。';
$lang->msg_board_delete_protect_comment = '回复里有他人回复的时候无法删除。';

View file

@ -362,17 +362,52 @@
<div class="x_control-group">
<label class="x_control-label">{$lang->protect_content}</label>
<div class="x_controls">
<label class="x_inline" for="protect_delete_content"><input type="checkbox" name="protect_delete_content" id="protect_delete_content" value="Y" checked="checked"|cond="$module_info->protect_delete_content == 'Y'" /> {$lang->cmd_delete}</label>
<label class="x_inline" for="protect_update_content"><input type="checkbox" name="protect_update_content" id="protect_update_content" value="Y" checked="checked"|cond="$module_info->protect_update_content == 'Y'" /> {$lang->cmd_modify}</label>
<p>{$lang->about_protect_content}</p>
<label for="protect_update_content">
<input type="checkbox" name="protect_update_content" id="protect_update_content" value="Y" checked="checked"|cond="$module_info->protect_update_content == 'Y'" />
{array_first(explode('%d', $lang->about_protect_content_update))}
<input type="number" min="0" name="protect_update_content_limit" value="{$module_info->protect_update_content_limit ?? 1}" style="width:50px" />
{array_last(explode('%d', $lang->about_protect_content_update))}
</label>
<label for="protect_delete_content">
<input type="checkbox" name="protect_delete_content" id="protect_delete_content" value="Y" checked="checked"|cond="$module_info->protect_delete_content == 'Y'" />
{array_first(explode('%d', $lang->about_protect_content_delete))}
<input type="number" min="0" name="protect_delete_content_limit" value="{$module_info->protect_delete_content_limit ?? 1}" style="width:50px" />
{array_last(explode('%d', $lang->about_protect_content_delete))}
</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->protect_comment}</label>
<div class="x_controls">
<label class="x_inline" for="protect_delete_comment"><input type="checkbox" name="protect_delete_comment" id="protect_delete_comment" value="Y" checked="checked"|cond="$module_info->protect_delete_comment == 'Y'" /> {$lang->cmd_delete}</label>
<label class="x_inline" for="protect_update_comment"><input type="checkbox" name="protect_update_comment" id="protect_update_comment" value="Y" checked="checked"|cond="$module_info->protect_update_comment == 'Y'" /> {$lang->cmd_modify}</label>
<p>{$lang->about_protect_comment}</p>
<label for="protect_update_comment">
<input type="checkbox" name="protect_update_comment" id="protect_update_comment" value="Y" checked="checked"|cond="$module_info->protect_update_comment == 'Y'" />
{array_first(explode('%d', $lang->about_protect_comment_update))}
<input type="number" min="0" name="protect_update_comment_limit" value="{$module_info->protect_update_comment_limit ?? 1}" style="width:50px" />
{array_last(explode('%d', $lang->about_protect_comment_update))}
</label>
<label for="protect_delete_comment">
<input type="checkbox" name="protect_delete_comment" id="protect_delete_comment" value="Y" checked="checked"|cond="$module_info->protect_delete_comment == 'Y'" />
{array_first(explode('%d', $lang->about_protect_comment_delete))}
<input type="number" min="0" name="protect_delete_comment_limit" value="{$module_info->protect_delete_comment_limit ?? 1}" style="width:50px" />
{array_last(explode('%d', $lang->about_protect_comment_delete))}
</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->protect_regdate}</label>
<div class="x_controls">
<label for="protect_document_regdate">
<input type="checkbox" name="protect_document_regdate" id="protect_document_regdate" value="Y" checked="checked"|cond="!empty($module_info->protect_document_regdate)" />
{array_first(explode('%d', $lang->about_protect_document_regdate))}
<input type="number" min="0" name="protect_document_regdate_limit" value="{$module_info->protect_document_regdate ?? ''}" style="width:50px" />
{array_last(explode('%d', $lang->about_protect_document_regdate))}
</label>
<label for="protect_comment_regdate">
<input type="checkbox" name="protect_comment_regdate" id="protect_comment_regdate" value="Y" checked="checked"|cond="!empty($module_info->protect_comment_regdate)" />
{array_first(explode('%d', $lang->about_protect_comment_regdate))}
<input type="number" min="0" name="protect_comment_regdate_limit" value="{$module_info->protect_comment_regdate ?? ''}" style="width:50px" />
{array_last(explode('%d', $lang->about_protect_comment_regdate))}
</label>
</div>
</div>
<!--@if($this->user->isAdmin())-->
@ -385,14 +420,6 @@
</div>
</div>
<!--@end-->
<div class="x_control-group">
<label class="x_control-label">{$lang->protect_regdate}</label>
<div class="x_controls">
{$lang->document} : <input type="number" min="0" name="protect_document_regdate" id="protect_document_regdate" value="{$module_info->protect_document_regdate}" />
{$lang->comment} : <input type="number" min="0" name="protect_comment_regdate" id="protect_comment_regdate" value="{$module_info->protect_comment_regdate}" />
<p>{$lang->about_protect_regdate}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="comment_delete_message">{$lang->comment_delete_message}</label>
<div class="x_controls">

View file

@ -58,6 +58,12 @@ class CommentController extends Comment
}
}
}
$yeokka_member_srl = Rhymix\Modules\Yeokbox\Models\Config::getConfig()->yeokka_member_srl;
$logged_info = Context::get('logged_info');
if($logged_info->member_srl != $yeokka_member_srl && $oComment->getRegdateTime() < (time() - (86400 * 7)))
{
throw new Rhymix\Framework\Exception('작성 이후 7일 이상이 경과한 댓글은 추천할 수 없습니다.');
}
$point = 1;
$allow_same_ip = ($comment_config->allow_vote_from_same_ip ?? 'N') === 'Y';

View file

@ -112,15 +112,15 @@ class CommentItem extends BaseObject
}
$logged_info = Context::get('logged_info');
if (!$logged_info->member_srl)
if (!$logged_info || !$logged_info->member_srl)
{
return $this->grant_cache = false;
}
if ($logged_info->is_admin == 'Y')
if ($logged_info && $logged_info->is_admin == 'Y')
{
return $this->grant_cache = true;
}
if ($this->get('member_srl') && abs($this->get('member_srl')) == $logged_info->member_srl)
if ($logged_info && $this->get('member_srl') && abs($this->get('member_srl')) == $logged_info->member_srl)
{
return $this->grant_cache = true;
}
@ -292,7 +292,7 @@ class CommentItem extends BaseObject
// return if the currently logged-in user is an author of the comment.
$logged_info = Context::get('logged_info');
if($logged_info->member_srl == $this->get('member_srl'))
if($logged_info && $logged_info->member_srl && $logged_info->member_srl == abs($this->get('member_srl')))
{
return;
}
@ -306,7 +306,7 @@ class CommentItem extends BaseObject
$title .= cut_str(strip_tags($content), 30, '...');
$content = sprintf('%s<br /><br />from : <a href="%s#comment_%s" target="_blank">%s</a>', $content, getFullUrl('', 'document_srl', $this->get('document_srl')), $this->get('comment_srl'), getFullUrl('', 'document_srl', $this->get('document_srl')));
$receiver_srl = $this->get('member_srl');
$sender_member_srl = $logged_info->member_srl;
$sender_member_srl = ($logged_info && $logged_info->member_srl) ? $logged_info->member_srl : $this->get('member_srl');
// send a message
$oCommunicationController = getController('communication');
@ -376,17 +376,24 @@ class CommentItem extends BaseObject
function getMyVote()
{
if(!$this->comment_srl) return false;
if(isset($_SESSION['voted_comment'][$this->comment_srl]))
if (!$this->comment_srl)
{
return false;
}
if (isset($_SESSION['voted_comment'][$this->comment_srl]))
{
return $_SESSION['voted_comment'][$this->comment_srl];
}
$logged_info = Context::get('logged_info');
if(!$logged_info->member_srl) return false;
if (!$logged_info || !$logged_info->member_srl)
{
return false;
}
$args = new stdClass();
if($logged_info->member_srl)
if ($logged_info && $logged_info->member_srl)
{
$args->member_srl = $logged_info->member_srl;
}
@ -413,7 +420,7 @@ class CommentItem extends BaseObject
}
$logged_info = Context::get('logged_info');
if (!$logged_info->member_srl)
if (!$logged_info || !$logged_info->member_srl)
{
return false;
}
@ -424,7 +431,7 @@ class CommentItem extends BaseObject
}
$args = new stdClass();
if ($logged_info->member_srl)
if ($logged_info && $logged_info->member_srl)
{
$args->member_srl = $logged_info->member_srl;
}

View file

@ -113,7 +113,7 @@ class CommentModel extends Comment
$url = getUrl('', 'module', 'admin', 'act', 'dispCommentAdminList', 'search_target', 'ipaddress', 'search_keyword', $oComment->getIpAddress());
$oCommentController->addCommentPopupMenu($url, 'cmd_search_by_ipaddress', '', 'TraceByIpaddress');
$url = sprintf("var params = new Array(); params['ipaddress_list']='%s'; exec_xml('spamfilter', 'procSpamfilterAdminInsertDeniedIP', params, completeCallModuleAction)", $oComment->getIpAddress());
$url = sprintf("var params = new Array(); params['ipaddress_list']='%s'; exec_json('spamfilter.procSpamfilterAdminInsertDeniedIP', params)", $oComment->getIpAddress());
$oCommentController->addCommentPopupMenu($url, 'cmd_add_ip_to_spamfilter', '', 'javascript');
}
}

View file

@ -70,6 +70,12 @@ class DocumentController extends Document
}
}
}
$yeokka_member_srl = Rhymix\Modules\Yeokbox\Models\Config::getConfig()->yeokka_member_srl;
$logged_info = Context::get('logged_info');
if($logged_info->member_srl != $yeokka_member_srl && $oDocument->getRegdateTime() < (time() - (86400 * 7)))
{
throw new Rhymix\Framework\Exception('작성 이후 7일 이상이 경과한 글은 추천할 수 없습니다.');
}
$point = 1;
$allow_same_ip = ($document_config->allow_vote_from_same_ip ?? 'N') === 'Y';
@ -902,7 +908,7 @@ class DocumentController extends Document
}
// Handle extra vars that support file upload.
if ($extra_item->type === 'file' && is_array($value))
if ($extra_item->type === 'file' && $value)
{
$ev_output = $extra_item->uploadFile($value, $obj->document_srl, 'doc');
if (!$ev_output->toBool())
@ -1300,16 +1306,20 @@ class DocumentController extends Document
if ($extra_item->type === 'file')
{
// New upload
if (is_array($value) && isset($value['name']))
if (is_array($value) && isset($value['tmp_name']))
{
// Delete old file
if (isset($old_extra_vars[$idx]->value))
{
$fc_output = FileController::getInstance()->deleteFile($old_extra_vars[$idx]->value);
if (!$fc_output->toBool())
$old_file = FileModel::getFile($old_extra_vars[$idx]->value);
if ($old_file && $old_file->upload_target_srl == $obj->document_srl)
{
$oDB->rollback();
return $fc_output;
$fc_output = FileController::getInstance()->deleteFile($old_file->file_srl);
if (!$fc_output->toBool())
{
$oDB->rollback();
return $fc_output;
}
}
}
// Insert new file
@ -1334,21 +1344,22 @@ class DocumentController extends Document
return $ev_output;
}
// Delete old file
$fc_output = FileController::getInstance()->deleteFile($old_extra_vars[$idx]->value);
if (!$fc_output->toBool())
$old_file = FileModel::getFile($old_extra_vars[$idx]->value);
if ($old_file && $old_file->upload_target_srl == $obj->document_srl)
{
$oDB->rollback();
return $fc_output;
$fc_output = FileController::getInstance()->deleteFile($old_file->file_srl);
if (!$fc_output->toBool())
{
$oDB->rollback();
return $fc_output;
}
}
}
}
// Leave current file unchanged
elseif (!$value)
elseif (isset($old_extra_vars[$idx]->value))
{
if (isset($old_extra_vars[$idx]->value))
{
$value = $old_extra_vars[$idx]->value;
}
$value = $old_extra_vars[$idx]->value;
}
}
}

View file

@ -201,11 +201,11 @@ class DocumentItem extends BaseObject
{
return $this->grant_cache = false;
}
if ($logged_info->is_admin == 'Y')
if ($logged_info && $logged_info->is_admin == 'Y')
{
return $this->grant_cache = true;
}
if ($this->get('member_srl') && abs($this->get('member_srl')) == $logged_info->member_srl)
if ($logged_info && $this->get('member_srl') && abs($this->get('member_srl')) == $logged_info->member_srl)
{
return $this->grant_cache = true;
}
@ -411,7 +411,7 @@ class DocumentItem extends BaseObject
// Return if the currently logged-in user is an author
$logged_info = Context::get('logged_info');
if($logged_info->member_srl == $this->get('member_srl'))
if($logged_info && $logged_info->member_srl && $logged_info->member_srl == abs($this->get('member_srl')))
{
return;
}
@ -421,7 +421,7 @@ class DocumentItem extends BaseObject
$content = sprintf('%s<br><br>from : <a href="%s" target="_blank">%s</a>',$content, getFullUrl('', 'document_srl', $this->document_srl), getFullUrl('', 'document_srl', $this->document_srl));
// Send a message
$sender_member_srl = $logged_info->member_srl ?: $this->get('member_srl');
$sender_member_srl = ($logged_info && $logged_info->member_srl) ? $logged_info->member_srl : $this->get('member_srl');
getController('communication')->sendMessage($sender_member_srl, $this->get('member_srl'), $title, $content, false, null, false);
}
@ -514,17 +514,17 @@ class DocumentItem extends BaseObject
}
$logged_info = Context::get('logged_info');
if(!$logged_info->member_srl)
if (!$logged_info || !$logged_info->member_srl)
{
$module_info = ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl'));
if($module_info->non_login_vote !== 'Y')
if(!isset($module_info->non_login_vote) || $module_info->non_login_vote !== 'Y')
{
return false;
}
}
$args = new stdClass;
if($logged_info->member_srl)
if ($logged_info && $logged_info->member_srl)
{
$args->member_srl = $logged_info->member_srl;
}
@ -554,7 +554,7 @@ class DocumentItem extends BaseObject
}
$logged_info = Context::get('logged_info');
if(!$logged_info->member_srl)
if(!$logged_info || !$logged_info->member_srl)
{
return false;
}
@ -565,7 +565,7 @@ class DocumentItem extends BaseObject
}
$args = new stdClass();
if($logged_info->member_srl)
if($logged_info && $logged_info->member_srl)
{
$args->member_srl = $logged_info->member_srl;
}
@ -1027,7 +1027,7 @@ class DocumentItem extends BaseObject
// Cache the vote log for all comments.
$logged_info = Context::get('logged_info');
if ($logged_info->member_srl)
if ($logged_info && $logged_info->member_srl)
{
$comment_srls = array();
foreach ($comment_list as $comment_srl => $comment)
@ -1650,6 +1650,10 @@ class DocumentItem extends BaseObject
return ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl'))->browser_title;
}
/**
* Get the title of the module to which the document belongs.
* @return string
*/
function getBrowserTitle()
{
return $this->getModuleName();

View file

@ -111,6 +111,7 @@ class DocumentModel extends Document
foreach($GLOBALS['XE_EXTRA_KEYS'][$module_srl] as $idx => $key)
{
$document_extra_vars[$idx] = clone($key);
$document_extra_vars[$idx]->parent_srl = $document_srl;
// set variable value in user language
if(isset($document_extra_values[$idx][$user_lang_code]))
@ -600,7 +601,7 @@ class DocumentModel extends Document
$url = getUrl('','module','admin','act','dispDocumentAdminList','search_target','ipaddress','search_keyword',$oDocument->getIpAddress());
$oDocumentController->addDocumentPopupMenu($url,'cmd_search_by_ipaddress',$icon_path,'TraceByIpaddress');
$url = sprintf("var params = new Array(); params['ipaddress_list']='%s'; exec_xml('spamfilter', 'procSpamfilterAdminInsertDeniedIP', params, completeCallModuleAction)", $oDocument->getIpAddress());
$url = sprintf("var params = new Array(); params['ipaddress_list']='%s'; exec_json('spamfilter.procSpamfilterAdminInsertDeniedIP', params)", $oDocument->getIpAddress());
$oDocumentController->addDocumentPopupMenu($url,'cmd_add_ip_to_spamfilter','','javascript');
}
}
@ -1430,6 +1431,10 @@ class DocumentModel extends Document
{
$args->s_voted_count = intval($searchOpt->s_voted_count);
}
if (isset($searchOpt->s_readed_count) && $searchOpt->s_readed_count > 0)
{
$args->s_readed_count = intval($searchOpt->s_readed_count);
}
// get directly module_srl by mid
if(isset($searchOpt->mid) && $searchOpt->mid)
@ -1562,13 +1567,13 @@ class DocumentModel extends Document
if($searchOpt->isExtraVars)
{
$args->sort_eid = $args->sort_index;
$args->sort_lang = Context::getLangType();
if ($searchOpt->isExtraVarsSortAsNumber ?? false)
{
$args->sort_index = 'extra_sort.sort_value';
}
else
{
$args->sort_lang = Context::getLangType();
$args->sort_index = 'extra_sort.value';
}
}

View file

@ -122,13 +122,12 @@ $lang->declared_message_title = 'A post has been reported.';
$lang->declared_cancel_message_title = 'Cancel the reported a post.';
$lang->declaring_user = 'Reporter';
$lang->improper_document_declare_reason = 'Reason';
$lang->improper_document_reasons['advertisement'] = 'Advertisements that do not fit the topics or themes.';
$lang->improper_document_reasons['theme'] = 'Posts that do not fit the topics or themes.';
$lang->improper_document_reasons['bad_word'] = 'Too much bad words.';
$lang->improper_document_reasons['violence'] = 'Violence.';
$lang->improper_document_reasons['racism'] = 'Racism.';
$lang->improper_document_reasons['pornography'] = 'Pornography.';
$lang->improper_document_reasons['privacy'] = 'Privacy issue.';
$lang->improper_document_reasons['do_not_fight'] = '1. Do not fight';
$lang->improper_document_reasons['sensitive_content'] = '2. Sensitive content';
$lang->improper_document_reasons['spoiler'] = '3. Spoiler';
$lang->improper_document_reasons['tas_export'] = '4. TAS export';
$lang->improper_document_reasons['tas_swear'] = '5. TAS swear';
$lang->improper_document_reasons['ad'] = '6. Advertisement';
$lang->improper_document_reasons['others'] = 'Others (Write your own)';
$lang->about_improper_document_declare = 'Write here why you report this article as an improper document.';
$lang->allow_vote_from_same_ip = 'Allow voting from same IP';

View file

@ -113,14 +113,13 @@ $lang->declared_message_title = '신고가 접수되었습니다.';
$lang->declared_cancel_message_title = '신고가 취소되었습니다.';
$lang->declaring_user = '신고자';
$lang->improper_document_declare_reason = '신고 이유';
$lang->improper_document_reasons['advertisement'] = '주제나 흐름에 맞지 않는 광고 글입니다.';
$lang->improper_document_reasons['theme'] = '주제에 맞지 않는 글입니다.';
$lang->improper_document_reasons['bad_word'] = '과도한 욕설을 담고 있습니다.';
$lang->improper_document_reasons['violence'] = '폭력적인 내용을 담고 있습니다.';
$lang->improper_document_reasons['racism'] = '인종차별적인 내용을 담고 있습니다.';
$lang->improper_document_reasons['pornography'] = '음란물을 포함하고 있습니다.';
$lang->improper_document_reasons['privacy'] = '민감한 개인정보가 노출 되어있습니다.';
$lang->improper_document_reasons['others'] = '기타(직접작성)';
$lang->improper_document_reasons['do_not_fight'] = '1. 싸우지 마세요 위반';
$lang->improper_document_reasons['sensitive_content'] = '2. 후방글에는 반드시 후방 주의를 달아주세요 위반';
$lang->improper_document_reasons['spoiler'] = '3. 스포글에도 반드시 스포 주의 달아주세요 위반';
$lang->improper_document_reasons['tas_export'] = '4. 타스 내수용 수출';
$lang->improper_document_reasons['tas_swear'] = '5. 타스 비방/욕설';
$lang->improper_document_reasons['ad'] = '6. 광고/스팸글';
$lang->improper_document_reasons['others'] = '기타(직접 작성)';
$lang->about_improper_document_declare = '게시글을 신고하신 이유를 간단히 적어서 제출해주시면 관리자 검토 후 조치하겠습니다.';
$lang->allow_vote_from_same_ip = '동일 IP 추천 허용';
$lang->allow_vote_non_member = '비회원 추천 허용';

View file

@ -71,12 +71,11 @@ $lang->declared_message_title = 'Đã tiếp nhận báo cáo.';
$lang->declared_cancel_message_title = 'Báo cáo đã bị hủy.';
$lang->declaring_user = 'Người báo';
$lang->improper_document_declare_reason = 'Lý do báo';
$lang->improper_document_reasons['advertisement'] = 'Đây là bài viết quảng cáo không phù hợp với chủ đề hoặc nội dung.';
$lang->improper_document_reasons['theme'] = 'Bài viết không hợp với chủ đề.';
$lang->improper_document_reasons['bad_word'] = 'Có chứa những lời chửi thề.';
$lang->improper_document_reasons['violence'] = 'Có nội dung bạo lực.';
$lang->improper_document_reasons['racism'] = 'Có nội dung phân biệt chủng tộc.';
$lang->improper_document_reasons['pornography'] = 'Có nội dung khiêu dâm.';
$lang->improper_document_reasons['privacy'] = 'Thông tin cá nhân nhạy cảm được tiết lộ.';
$lang->improper_document_reasons['do_not_fight'] = '1. Không gây gổ';
$lang->improper_document_reasons['sensitive_content'] = '2. Nội dung nhạy cảm';
$lang->improper_document_reasons['spoiler'] = '3. Tiết lộ nội dung';
$lang->improper_document_reasons['tas_export'] = '4. Xuất khẩu TAS';
$lang->improper_document_reasons['tas_swear'] = '5. Lời lẽ thô tục TAS';
$lang->improper_document_reasons['ad'] = '6. Quảng cáo/Spam';
$lang->improper_document_reasons['others'] = 'Khác(Tự viết)';
$lang->about_improper_document_declare = 'Hãy viết ngắn gọn lý do tại sao lại báo cáo bài viết rồi gửi cho quản lý thì quản lý sẽ kiểm tra và xử lý.';

View file

@ -22,8 +22,8 @@
<condition operation="like" column="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" pipe="or" />
<condition operation="equal" column="member_srl" var="s_member_srl" pipe="and" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -23,8 +23,8 @@
<condition operation="like" column="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" pipe="or" />
<condition operation="equal" column="member_srl" var="s_member_srl" pipe="and" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -26,8 +26,8 @@
<condition operation="like" column="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" pipe="or" />
<condition operation="equal" column="member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -32,8 +32,8 @@
<condition operation="like" column="d.tags" var="s_tags" pipe="or" />
<condition operation="equal" column="d.is_secret" var="s_is_secret" pipe="or" />
<condition operation="equal" column="d.member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="d.readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="d.voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="d.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="d.voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="d.blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="d.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="d.trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -26,8 +26,8 @@
<condition operation="like" column="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" pipe="or" />
<condition operation="equal" column="member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -29,8 +29,8 @@
<condition operation="like" column="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" pipe="or" />
<condition operation="equal" column="member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -35,8 +35,8 @@
<condition operation="like" column="documents.homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="documents.tags" var="s_tags" pipe="or" />
<condition operation="equal" column="documents.member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="documents.blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="documents.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="documents.trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -32,8 +32,8 @@
<condition operation="like" column="d.tags" var="s_tags" pipe="or" />
<condition operation="equal" column="d.is_secret" var="s_is_secret" pipe="or" />
<condition operation="equal" column="d.member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="d.readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="d.voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="d.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="d.voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="d.blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="d.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="d.trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -20,8 +20,8 @@
<condition operation="like" column="documents.tags" var="s_tags" pipe="or" />
<condition operation="equal" column="documents.is_notice" var="s_is_notice" pipe="or" />
<condition operation="equal" column="documents.member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="documents.blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="documents.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="documents.trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -31,8 +31,8 @@
<condition operation="like" column="documents.tags" var="s_tags" pipe="or" />
<condition operation="equal" column="documents.is_secret" var="s_is_secret" pipe="or" />
<condition operation="equal" column="documents.member_srl" var="s_member_srl" pipe="or" />
<condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="or" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" />
<condition operation="more" column="documents.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="and" />
<condition operation="less" column="documents.blamed_count" var="s_blamed_count" pipe="or" />
<condition operation="more" column="documents.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="documents.trackback_count" var="s_trackback_count" pipe="or" />

View file

@ -89,8 +89,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
</div>
</form>
<form action="./" class="x_pagination">
<input type="hidden" name="error_return_url" value="" />
<form action="./" class="x_pagination" no-error-return-url="true">
<input type="hidden" name="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" />
<input cond="$search_keyword" type="hidden" name="search_keyword" value="{$search_keyword}" />
@ -126,10 +125,9 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<li class="x_disabled"|cond="$page == $page_navigation->last_page"><a href="{getUrl('page', $page_navigation->last_page)}" title="{$page_navigation->last_page}">{$lang->last_page} &raquo;</a></li>
</ul>
</form>
<form action="./" method="get" class="search center x_input-append x_clearfix">
<form action="./" method="get" class="search center x_input-append x_clearfix" no-error-return-url="true">
<input type="hidden" name="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" />
<input type="hidden" name="error_return_url" value="" />
<select name="module_srl" style="margin-right:4px">
<option value="">{lang('all')}</option>
<!--@foreach($module_list as $item)-->
@ -149,8 +147,8 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<input type="hidden" name="module" value="document" />
<input type="hidden" name="act" value="procDocumentManageCheckedDocument" />
<input type="hidden" name="type" value="" />
<input type="hidden" name="module_srl" value="" />
<input type="hidden" name="success_return_url" value="{getUrl('', 'module', 'admin', 'act', 'dispDocumentAdminList', 'is_secret', $is_secret, 'search_target', $search_target, 'search_keyword', $search_keyword, 'page', $page)}" />
<input type="hidden" name="module_srl" value="{$module_srl}" />
<input type="hidden" name="success_return_url" value="{getUrl('', 'module', 'admin', 'act', 'dispDocumentAdminList', 'module_srl', $module_srl, 'is_secret', $is_secret, 'search_target', $search_target, 'search_keyword', $search_keyword, 'page', $page)}" />
<input type="hidden" name="xe_validator_id" value="modules/document/tpl/document_list/1" />
<div class="x_modal-header">
<h1>{$lang->document_manager}: <span class="_sub"></span></h1>

View file

@ -387,6 +387,7 @@ class EditorModel extends Editor
}
else
{
$logged_info = new Rhymix\Framework\Helpers\SessionHelper();
$group_list = array();
}
@ -507,7 +508,7 @@ class EditorModel extends Editor
$logged_info = Context::get('logged_info');
$auto_save_args->member_srl = $logged_info->member_srl;
}
elseif($_COOKIE['autosave_certify_key_' . $auto_save_args->module_srl])
elseif(!empty($_COOKIE['autosave_certify_key_' . $auto_save_args->module_srl]))
{
$auto_save_args->certify_key = $_COOKIE['autosave_certify_key_' . $auto_save_args->module_srl];
}
@ -647,8 +648,8 @@ class EditorModel extends Editor
unset($component_list->{$key});
continue;
}
if($logged_info->is_admin == "Y") continue;
if($val->target_group)
if($logged_info && $logged_info->is_admin == "Y") continue;
if(isset($val->target_group) && $val->target_group)
{
if(!Context::get('is_logged'))
{
@ -664,7 +665,7 @@ class EditorModel extends Editor
if(!$is_granted) $val->enabled = "N";
}
}
if($val->enabled != "N" && $val->mid_list)
if($val->enabled != "N" && !empty($val->mid_list))
{
$mid = Context::get('mid');
if(!in_array($mid, $val->mid_list)) $val->enabled = "N";

View file

@ -10,7 +10,7 @@
<div cond="$allow_fileupload" id="xefu-container-{$editor_sequence}" class="xefu-container xe-clearfix"
data-editor-sequence="{$editor_sequence}"
data-editor-status="{json_encode(FileModel::getInstance()->getFileList($editor_sequence), JSON_UNESCAPED_UNICODE)}"
data-max-file-size="{$logged_info->is_admin === 'Y' ? 0 : $file_config->allowed_filesize}"
data-max-file-size="{$this->user->isAdmin() ? 0 : $file_config->allowed_filesize}"
data-max-chunk-size="{$file_config->allowed_chunk_size ?: 0}"
data-autoinsert-types="{json_encode($editor_autoinsert_types)}"
data-autoinsert-position="{$editor_autoinsert_position ?: 'paragraph'}">

View file

@ -25,6 +25,7 @@ class Value
public $input_id = '';
public $input_name = '';
public $parent_type = 'document';
public $parent_srl = null;
public $type = 'text';
public $value = null;
public $name = '';
@ -159,7 +160,7 @@ class Value
*/
public function getValueHTML(): string
{
return self::_getTypeValueHTML($this->type, $this->value);
return self::_getTypeValueHTML($this->type, $this->value, $this->parent_type, $this->parent_srl);
}
/**
@ -280,7 +281,7 @@ class Value
$values = [$value];
}
// Check if a required value is empty.
// Check that a required value is not empty.
if ($this->is_required === 'Y')
{
if ($this->type === 'file' && !$value && $old_value)
@ -298,7 +299,7 @@ class Value
}
}
// Check if a strict value is not one of the specified options.
// Check that a strict value equals one of the specified options.
if ($this->is_strict === 'Y' && $value)
{
if ($this->canHaveOptions())
@ -321,6 +322,15 @@ class Value
}
}
// Check that a file value is actually an uploaded file.
if ($this->type === 'file' && $value)
{
if (!isset($value['tmp_name']) || !is_uploaded_file($value['tmp_name']))
{
return new BaseObject(-1, sprintf(lang('common.filter.invalid_file'), Context::replaceUserLang($this->name)));
}
}
return new BaseObject;
}
@ -442,9 +452,11 @@ class Value
*
* @param string $type
* @param string|array $value
* @param string $parent_type
* @param ?int $parent_srl
* @return string
*/
protected static function _getTypeValueHTML(string $type, $value): string
protected static function _getTypeValueHTML(string $type, $value, string $parent_type, ?int $parent_srl = null): string
{
// Return if the value is empty.
$value = self::_getTypeValue($type, $value);
@ -511,10 +523,14 @@ class Value
if ($value)
{
$file = FileModel::getFile($value);
if ($file)
if ($file && $file->upload_target_srl == $parent_srl)
{
return sprintf('<span><a href="%s">%s</a> (%s)</span>', \RX_BASEURL . ltrim($file->download_url, './'), $file->source_filename, FileHandler::filesize($file->file_size));
}
elseif ($file)
{
return sprintf('<span>%s (%s)</span>', $file->source_filename, FileHandler::filesize($file->file_size));
}
else
{
return '';

View file

@ -551,7 +551,7 @@ class FileController extends File
{
$download_type = 'inline';
}
if (Context::get('force_download') === 'Y')
if ($mime_type === 'image/svg+xml' || Context::get('force_download') === 'Y')
{
$download_type = 'attachment';
}
@ -936,6 +936,14 @@ class FileController extends File
}
}
// Sanitize SVG
if(!$manual_insert && !$this->user->isAdmin() && ($file_info['type'] === 'image/svg+xml' || $file_info['extension'] === 'svg'))
{
$dirty_svg = Rhymix\Framework\Storage::read($file_info['tmp_name']);
$clean_svg = Rhymix\Framework\Security::sanitize($dirty_svg, 'svg');
Rhymix\Framework\Storage::write($file_info['tmp_name'], $clean_svg);
}
// Adjust
if(!$manual_insert)
{

View file

@ -204,6 +204,13 @@ class installController extends install
// Set the default umask.
$config['file']['umask'] = Rhymix\Framework\Storage::recommendUmask();
// Set default security settings.
if ($config['url']['ssl'] === 'always')
{
$config['session']['use_ssl'] = true;
$config['session']['use_ssl_cookies'] = true;
}
// Load the new configuration.
Rhymix\Framework\Config::setAll($config);
Context::loadDBInfo($config);

View file

@ -28,6 +28,11 @@ class installView extends install
// Specify the template path.
$this->setTemplatePath($this->module_path.'tpl');
// Set default frontend configurations.
config('view.jquery_version', 3);
config('view.minify_scripts', 'none');
config('view.concat_scripts', 'none');
// Check the environment.
$oInstallController = getController('install');
self::$checkEnv = $oInstallController->checkInstallEnv();

View file

@ -1,7 +1,7 @@
<?php
$lang->krzip = 'Korean Postal Code';
$lang->cmd_krzip_api_type = 'Select API Provider';
$lang->cmd_krzip_daumapi = 'Daum-Kakao API';
$lang->cmd_krzip_daumapi = 'Kakao API';
$lang->cmd_krzip_epostapi = 'Korea Post API';
$lang->cmd_krzip_postcodify = 'Postcodify';
$lang->cmd_krzip_regkey = 'Registration Key';

View file

@ -1,7 +1,7 @@
<?php
$lang->krzip = '한국 우편번호';
$lang->cmd_krzip_api_type = 'API 선택';
$lang->cmd_krzip_daumapi = '다음 우편번호';
$lang->cmd_krzip_daumapi = '카카오 우편번호';
$lang->cmd_krzip_epostapi = '우체국 우편번호';
$lang->cmd_krzip_postcodify = 'Postcodify';
$lang->cmd_krzip_regkey = '등록키';

View file

@ -24,7 +24,7 @@
guide : $this.find(".krzip-guide")
};
var krzip = new daum.Postcode({
var krzip = new kakao.Postcode({
oncomplete: function (response) {
var fullAddr = "", extraAddr = "";

View file

@ -1,8 +1,8 @@
<!--// 다음 우편번호 API -->
<!--// 다음/카카오 우편번호 API -->
<!--// https://github.com/daumPostcode/QnA -->
<!--// HEADER -->
<load target="//t1.kakaocdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js" />
<load target="./css/default.css" />
<load target="http://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js" cond="!\RX_SSL" />
<load target="https://t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js" cond="\RX_SSL" />
<load target="./js/daumapi.js" />
<!--// BODY -->

View file

@ -22,50 +22,44 @@ class LayoutAdminView extends Layout
*/
function dispLayoutAdminInstalledList()
{
$type = Context::get('type');
$type = ($type != 'M') ? 'P' : 'M';
$type = Context::get('type') === 'M' ? 'M' : 'P';
// Set a layout list
$oLayoutModel = getModel('layout');
$layout_list = $oLayoutModel->getDownloadedLayoutList($type, true);
if(!is_array($layout_list))
// Get installed layout list
$layout_list = LayoutModel::getDownloadedLayoutList($type, true);
if (!is_array($layout_list))
{
$layout_list = array();
$layout_list = [];
}
if($type == 'P')
// Get instance list
$columns = ['layout_srl', 'layout', 'module_srl', 'title', 'regdate'];
$instances = LayoutModel::getLayoutInstanceList(0, $type, null, $columns);
$instance_list = [];
foreach ($instances as $instance)
{
// get Theme layout
$oAdminModel = getAdminModel('admin');
$themeList = $oAdminModel->getThemeList();
$themeLayoutList = array();
foreach($themeList as $themeInfo)
{
if(strpos($themeInfo->layout_info->name, '.') === false) continue;
$themeLayoutList[] = $oLayoutModel->getLayoutInfo($themeInfo->layout_info->name, null, 'P');
}
$layout_list = array_merge($layout_list, $themeLayoutList);
$layout_list[] = $oLayoutModel->getLayoutInfo('faceoff', null, 'P');
$instance_list[$instance->layout][] = $instance;
}
Context::set('instance_list', $instance_list);
$pcLayoutCount = $oLayoutModel->getInstalledLayoutCount('P');
$mobileLayoutCount = $oLayoutModel->getInstalledLayoutCount('M');
// Get installed layout count by type
$pcLayoutCount = LayoutModel::getInstalledLayoutCount('P');
$mobileLayoutCount = LayoutModel::getInstalledLayoutCount('M');
Context::set('pcLayoutCount', $pcLayoutCount);
Context::set('mobileLayoutCount', $mobileLayoutCount);
$this->setTemplateFile('installed_layout_list');
// Security?
$security = new Security($layout_list);
$layout_list = $security->encodeHTML('..', '..author..');
//Security
$security = new Security();
$security->encodeHTML('layout_list..layout','layout_list..title');
foreach($layout_list as $no => $layout_info)
$security->encodeHTML('layout_list..layout','layout_list..title','instance_list..');
foreach ($layout_list as $no => $layout_info)
{
$layout_list[$no]->description = nl2br(trim($layout_info->description));
}
Context::set('layout_list', $layout_list);
// Set template file
$this->setTemplateFile('installed_layout_list');
}
/**
@ -74,19 +68,17 @@ class LayoutAdminView extends Layout
*/
function dispLayoutAdminAllInstanceList()
{
$type = Context::get('type');
$type = Context::get('type') === 'M' ? 'M' : 'P';
if(!in_array($type, array('P', 'M'))) $type = 'P';
$oLayoutModel = getModel('layout');
$pcLayoutCount = $oLayoutModel->getInstalledLayoutCount('P');
$mobileLayoutCount = $oLayoutModel->getInstalledLayoutCount('M');
// Get installed layout count
$pcLayoutCount = LayoutModel::getInstalledLayoutCount('P');
$mobileLayoutCount = LayoutModel::getInstalledLayoutCount('M');
Context::set('pcLayoutCount', $pcLayoutCount);
Context::set('mobileLayoutCount', $mobileLayoutCount);
// Get layout instance list
$columnList = array('layout_srl', 'layout', 'module_srl', 'title', 'regdate');
$_layout_list = $oLayoutModel->getLayoutInstanceList(0, $type, null, $columnList);
$_layout_list = LayoutModel::getLayoutInstanceList(0, $type, null, $columnList);
$layout_list = array();
foreach($_layout_list as $item)
@ -94,7 +86,7 @@ class LayoutAdminView extends Layout
if(!$layout_list[$item->layout])
{
$layout_list[$item->layout] = array();
$layout_info = $oLayoutModel->getLayoutInfo($item->layout, null, $type);
$layout_info = LayoutModel::getLayoutInfo($item->layout, null, $type);
if ($layout_info)
{
$layout_list[$item->layout]['title'] = $layout_info->title;
@ -108,10 +100,10 @@ class LayoutAdminView extends Layout
Context::set('layout_list', $layout_list);
$this->setTemplateFile('layout_all_instance_list');
$security = new Security();
$security->encodeHTML('layout_list..');
$this->setTemplateFile('layout_all_instance_list');
}
/**

View file

@ -81,11 +81,7 @@ class LayoutModel extends Layout
}
$token = explode('|@|', $val->layout);
if(count($token) == 2)
{
$thumbnailPath = sprintf('./themes/%s/layouts/%s/thumbnail.png' , $token[0], $token[1]);
}
else if($layoutType == 'M')
if($layoutType == 'M')
{
$thumbnailPath = sprintf('./m.layouts/%s/thumbnail.png' , $val->layout);
}
@ -167,7 +163,7 @@ class LayoutModel extends Layout
if($layout)
{
if(count($instanceList) < 1 && $downloadedList[$layout])
if(count($instanceList) < 1 && isset($downloadedList[$layout]))
{
$insertArgs = new stdClass();
$insertArgs->layout_srl = getNextSequence();
@ -227,26 +223,13 @@ class LayoutModel extends Layout
*/
public static function isExistsLayoutFile($layout, $layoutType)
{
//TODO If remove a support themes, remove this codes also.
if($layoutType == 'P')
{
$pathPrefix = RX_BASEDIR . 'layouts/';
$themePathFormat = RX_BASEDIR . 'themes/%s/layouts/%s';
$path = RX_BASEDIR . 'layouts/' . $layout;
}
else
{
$pathPrefix = RX_BASEDIR . 'm.layouts/';
$themePathFormat = RX_BASEDIR . 'themes/%s/m.layouts/%s';
}
if(strpos($layout, '|@|') !== FALSE)
{
list($themeName, $layoutName) = explode('|@|', $layout);
$path = sprintf($themePathFormat, $themeName, $layoutName);
}
else
{
$path = $pathPrefix . $layout;
$path = RX_BASEDIR . 'm.layouts/' . $layout;
}
if (file_exists($path . '/layout.html') && is_readable($path . '/layout.html'))
@ -333,12 +316,7 @@ class LayoutModel extends Layout
*/
public function getLayoutPath($layout_name = "", $layout_type = "P")
{
$layout_parse = explode('|@|', $layout_name ?? '');
if(count($layout_parse) > 1)
{
$class_path = './themes/'.$layout_parse[0].'/layouts/'.$layout_parse[1].'/';
}
else if($layout_name == 'faceoff')
if($layout_name == 'faceoff')
{
$class_path = './modules/layout/faceoff/';
}
@ -383,7 +361,7 @@ class LayoutModel extends Layout
// Get information of the layout
$layout_info = self::getLayoutInfo($layout, null, $layout_type);
if(!$layout_info)
if (!$layout_info || !self::isExistsLayoutFile($layout, $layout_type))
{
continue;
}

View file

@ -17,10 +17,11 @@
</tr>
</thead>
<tbody>
<tr loop="$layout_list => $key, $layout">
<block cond="$layout->title">
<!--@foreach($layout_list as $layout)-->
<tr>
<!--@if($layout->title)-->
<td class="title">
<p><a href="{getUrl('act', 'dispLayoutAdminInstanceList', 'type', $type, 'layout', $layout->layout)}">{$layout->title}</a></p>
<p><a href="{getUrl('act', 'dispLayoutAdminInstanceList', 'type', $type, 'layout', $layout->layout)}" style="font-weight:bold;color:#000">{$layout->title}</a></p>
<p>{$layout->description}</p>
<p cond="$layout->need_update == 'Y'" class="update">
{$lang->msg_avail_easy_update} <a href="{$layout->update_url}&amp;return_url={urlencode(getRequestUriByServerEnviroment())}">{$lang->msg_do_you_like_update}</a>
@ -40,9 +41,10 @@
</block>
</td>
<td class="rx_detail_marks">{$layout->path}</td>
<td class="nowr rx_detail_marks"><a cond="$layout->remove_url" class="x_btn x_btn-link" href="{$layout->remove_url}&amp;return_url={urlencode(getRequestUriByServerEnviroment())}">{$lang->cmd_delete}</a></td>
</block>
<block cond="!$layout->title">
<td class="nowr rx_detail_marks">
<a cond="$layout->remove_url" class="x_btn x_btn-link" href="{$layout->remove_url}&amp;return_url={urlencode(getRequestUriByServerEnviroment())}">{$lang->cmd_delete}</a>
</td>
<!--@else-->
<td class="title">
<p><a href="{getUrl('act', 'dispLayoutAdminInstanceList', 'type', $type, 'layout', $layout->layout)}">{$layout->layout}</a></p>
<p cond="$layout->need_update == 'Y'" class="update">
@ -52,7 +54,31 @@
<td>-</td>
<td>-</td>
<td class="rx_detail_marks">{$layout->path}</td>
</block>
<td class="rx_detail_marks"></td>
<!--@endif-->
</tr>
<!--@if(isset($instance_list[$layout->layout]))-->
<!--@foreach($instance_list[$layout->layout] as $instance)-->
<tr>
<td colspan="2" style="padding-left:20px;">
<i class="xi-reply-l" style="transform:rotate(180deg);"></i> &nbsp;
<a href="{getUrl(['module' => 'admin', 'act' => 'dispLayoutAdminModify', 'layout_srl' => $instance->layout_srl])}">
{$instance->title}
</a>
</td>
<td>
<!--@if($instance->is_edited)-->
<a href="{getUrl(['module' => 'admin', 'act' => 'dispLayoutAdminEdit', 'layout_srl' => $instance->layout_srl])}">{$lang->cmd_edit}</a>
<!--@else-->
<span style="color:#999">편집</span>
<!--@endif-->
<a href="{getUrl(['module' => 'layout', 'act' => 'dispLayoutAdminCopyLayout', 'layout_srl' => $instance->layout_srl])}" onclick="popopen(this.href);return false;" title="{$lang->cmd_copy}">{$lang->cmd_copy}</a></td>
</td>
<td class="rx_detail_marks"></td>
<td class="rx_detail_marks"></td>
</tr>
<!--@endforeach-->
<!--@endif-->
<!--@endforeach-->
</tbody>
</table>

View file

@ -1,6 +1,6 @@
<ul class="x_nav x_nav-tabs">
<li class="x_active"|cond="$type != 'M'"><a href="{getUrl('act', 'dispLayoutAdminInstalledList', 'type', 'P')}">PC({$pcLayoutCount})</a></li>
<li class="x_active"|cond="$type == 'M'"><a href="{getUrl('act', 'dispLayoutAdminInstalledList', 'type', 'M')}">Mobile({$mobileLayoutCount})</a></li>
<li class="x_active"|cond="$type != 'M'"><a href="{getUrl('act', 'dispLayoutAdminInstalledList', 'type', 'P')}">PC ({$pcLayoutCount})</a></li>
<li class="x_active"|cond="$type == 'M'"><a href="{getUrl('act', 'dispLayoutAdminInstalledList', 'type', 'M')}">Mobile ({$mobileLayoutCount})</a></li>
</ul>
<div>
<a class="active"|cond="$act == 'dispLayoutAdminAllInstanceList'" href="{getUrl('act', 'dispLayoutAdminAllInstanceList', 'layout_srl', '')}">{$lang->instance_layout}</a> <i>|</i>

View file

@ -118,6 +118,7 @@
<action name="procMemberAdminUpdateGroupOrder" type="controller" />
<action name="procMemberAdminUpdateMembersGroup" type="controller" ruleset="manageMemberGroup" />
<action name="procMemberAdminDeleteMembers" type="controller" />
<action name="procMemberAdminLoginAs" type="controller" />
</actions>
<eventHandlers>
<eventHandler after="document.getDocumentMenu" class="controller" method="triggerGetDocumentMenu" />

View file

@ -114,6 +114,7 @@ $lang->search_target_list['last_login_less'] = 'Last Login Date (less)';
$lang->search_target_list['last_login_ipaddress'] = 'Last Login IP address';
$lang->search_target_list['birthday'] = 'Birthday';
$lang->search_target_list['extra_vars'] = 'User Defined';
$lang->search_target_list['description'] = 'Admin Memo';
$lang->cmd_modify_new_auth_email_address = 'New email address';
$lang->cmd_set_design_info = 'Desgin';
$lang->cmd_login = 'Login';
@ -406,3 +407,6 @@ $lang->member_unauthenticated = 'Unauthenticated';
$lang->member_number = 'Member identification number';
$lang->msg_change_after_click = 'Change after clicking link below';
$lang->msg_password_changed = 'Your password has been changed.';
$lang->cmd_login_as = 'Login as this member';
$lang->msg_confirm_login_as = 'Are you sure you want to login as this member? Your current admin session will be terminated.';

View file

@ -116,6 +116,7 @@ $lang->search_target_list['last_login_less'] = '최근 로그인 일시(이하)'
$lang->search_target_list['last_login_ipaddress'] = '최근 로그인 IP 주소';
$lang->search_target_list['birthday'] = '생일';
$lang->search_target_list['extra_vars'] = '사용자 정의';
$lang->search_target_list['description'] = '관리자 메모';
$lang->cmd_modify_new_auth_email_address = '신규 메일 주소로 변경 후 인증 메일 발송';
$lang->cmd_set_design_info = '디자인';
$lang->cmd_login = '로그인';
@ -410,3 +411,6 @@ $lang->member_unauthenticated = '미인증';
$lang->member_number = '회원 번호';
$lang->msg_change_after_click = '아래 링크 클릭 후 변경 가능';
$lang->msg_password_changed = '비밀번호가 변경되었습니다.';
$lang->cmd_login_as = '해당 회원으로 로그인';
$lang->msg_confirm_login_as = '해당 회원으로 로그인하시겠습니까? 현재 관리자 세션이 종료됩니다.';

View file

@ -1802,6 +1802,47 @@ class MemberAdminController extends Member
return new BaseObject();
}
/**
* Login as a specific member (admin only)
* @return void|BaseObject
*/
function procMemberAdminLoginAs()
{
// Check admin permission and CSRF token
$logged_info = Context::get('logged_info');
if(!$logged_info || $logged_info->is_admin !== 'Y' || !Rhymix\Framework\Security::checkCSRF())
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
$member_srl = Context::get('member_srl');
if(!$member_srl)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
// Get target member info
$member_info = MemberModel::getMemberInfoByMemberSrl($member_srl);
if(!$member_info || !$member_info->member_srl)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
// Do not allow login as the super admin (member_srl = 4)
if(intval($member_info->member_srl) === 4)
{
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
// Perform login as the target member
// Session::login() sets the basic session variables, and setSessionInfo() populates Context with member details
Rhymix\Framework\Session::login($member_info->member_srl);
$oMemberController = getController('member');
$oMemberController->setSessionInfo();
$this->setRedirectUrl(getNotEncodedUrl(''));
}
}
/* End of file member.admin.controller.php */
/* Location: ./modules/member/member.admin.controller.php */

View file

@ -121,6 +121,9 @@ class MemberAdminModel extends Member
case 'extra_vars' :
$args->s_extra_vars = $search_keyword;
break;
case 'description' :
$args->s_description = $search_keyword;
break;
}
}

View file

@ -1837,6 +1837,7 @@ class MemberController extends Member
}
Context::set('auth_args', $args);
// Prepare member information to be included in the email #2594 #2663
$memberInfo = array();
if (in_array('user_id', $member_config->identifiers))
{
@ -1846,6 +1847,21 @@ class MemberController extends Member
{
$memberInfo[$lang->email_address] = $member_info->email_address;
}
if (in_array('phone_number', $member_config->identifiers))
{
$phone_number = $member_info->phone_number;
if($member_config->phone_number_hide_country !== 'Y')
{
$phone_number = Rhymix\Framework\i18n::formatPhoneNumber($phone_number, $member_info->phone_country);
}
elseif($member_config->phone_number_default_country === 'KOR' && ($member_info->phone_country === 'KOR' || $member_info->phone_country == '82'))
{
$phone_number = Rhymix\Framework\Korea::formatPhoneNumber($phone_number);
}
$memberInfo[$lang->phone_number] = $phone_number;
}
$memberInfo[$lang->user_name] = $member_info->user_name;
$memberInfo[$lang->nick_name] = $member_info->nick_name;
Context::set('memberInfo', $memberInfo);
if(!$member_config->skin) $member_config->skin = "default";
@ -2383,7 +2399,7 @@ class MemberController extends Member
* @param string $autologin_key
* @return int|false
*/
function doAutologin($autologin_key = null)
public static function doAutoLogin($autologin_key = null)
{
// Validate the key.
if (strlen($autologin_key) == 48)
@ -2426,6 +2442,28 @@ class MemberController extends Member
return false;
}
// Get the member info and check it.
$member_info = MemberModel::getMemberInfo($output->data->member_srl);
if (!$member_info)
{
return false;
}
if (!empty($member_info->denied) && $member_info->denied === 'Y')
{
return false;
}
if (!empty($member_info->limit_date) && substr($member_info->limit_date, 0, 8) >= date('Ymd'))
{
return false;
}
// Call a trigger before auto-login.
$trigger_output = ModuleHandler::triggerCall('member.doAutoLogin', 'before', $member_info);
if (!$trigger_output->toBool())
{
return false;
}
// If the current security key matches, generate a new key.
// If the previous key matches, don't update until the client has the current key.
// Resending the current key in this case will be handled by the Session class.
@ -2458,13 +2496,10 @@ class MemberController extends Member
}
// Update the last login time.
executeQuery('member.updateLastLogin', (object)['member_srl' => $output->data->member_srl]);
self::clearMemberCache($output->data->member_srl);
self::updateLastLogin($output->data->member_srl);
// Call a trigger after validate security key (after)
$trigger_obj = new stdClass();
$trigger_obj->member_srl = $output->data->member_srl;
ModuleHandler::triggerCall('member.doAutoLogin', 'after', $trigger_obj);
// Call a trigger after validate security key.
ModuleHandler::triggerCall('member.doAutoLogin', 'after', $member_info);
// Return the member_srl.
return intval($output->data->member_srl);
@ -2636,11 +2671,6 @@ class MemberController extends Member
}
}
// Update the latest login time
$args->member_srl = $member_info->member_srl;
$output = executeQuery('member.updateLastLogin', $args);
self::clearMemberCache($args->member_srl);
// Check if there is recoding table.
$oDB = DB::getInstance();
if($oDB->isTableExists('member_count_history') && $config->enable_login_fail_report != 'N')
@ -2698,6 +2728,7 @@ class MemberController extends Member
// Log in!
Rhymix\Framework\Session::login($member_info->member_srl);
self::updateLastLogin($member_info->member_srl);
$this->setSessionInfo();
// Log out all other sessions if so configured.
@ -2712,10 +2743,23 @@ class MemberController extends Member
return $output;
}
/**
* Update the last login timestamp of a member.
*
* @param int $member_srl
* @return object
*/
public static function updateLastLogin(int $member_srl)
{
$output = executeQuery('member.updateLastLogin', ['member_srl' => $member_srl]);
self::clearMemberCache($member_srl);
return $output;
}
/**
* Update or create session information
*/
function setSessionInfo()
public function setSessionInfo()
{
// If your information came through the current session information to extract information from the users
$member_info = Rhymix\Framework\Session::getMemberInfo(true);
@ -3105,7 +3149,7 @@ class MemberController extends Member
*
* @param bool $deprecated_allow_update_other
*/
function updateMember($args, $deprecated_allow_update_other = FALSE)
function updateMember($args, $deprecated_allow_update_other = FALSE, $manual_updated = FALSE)
{
// Call a trigger (before)
$output = ModuleHandler::triggerCall('member.updateMember', 'before', $args);
@ -3131,7 +3175,7 @@ class MemberController extends Member
{
unset($args->is_admin);
unset($args->limit_date);
unset($args->description);
if(!$manual_updated) unset($args->description);
if (!$deprecated_allow_update_other)
{
unset($args->denied);
@ -3345,7 +3389,7 @@ class MemberController extends Member
if(!$args->user_name) $args->user_name = $orgMemberInfo->user_name;
if(!$args->user_id) $args->user_id = $orgMemberInfo->user_id;
if(!$args->nick_name) $args->nick_name = $orgMemberInfo->nick_name;
if($logged_info->is_admin !== 'Y')
if($logged_info->is_admin !== 'Y' && !$manual_updated)
{
$args->description = $orgMemberInfo->description;
}

View file

@ -19,6 +19,7 @@
<condition operation="like" column="phone_number" var="s_phone_number" pipe="or" />
<condition operation="like" column="birthday" var="s_birthday" pipe="or" />
<condition operation="like" column="extra_vars" var="s_extra_vars" pipe="or" />
<condition operation="like" column="description" var="s_description" pipe="or" />
<condition operation="like_prefix" column="regdate" var="s_regdate" pipe="or" />
<condition operation="like_prefix" column="ipaddress" var="s_ipaddress" pipe="or" />
<condition operation="like_prefix" column="last_login" var="s_last_login" pipe="or" />

View file

@ -22,6 +22,7 @@
<condition operation="like" column="member.phone_number" var="s_phone_number" pipe="or" />
<condition operation="like" column="member.birthday" var="s_birthday" pipe="or" />
<condition operation="like" column="member.extra_vars" var="s_extra_vars" pipe="or" />
<condition operation="like" column="member.description" var="s_description" pipe="or" />
<condition operation="like_prefix" column="member.regdate" var="s_regdate" pipe="or" />
<condition operation="like_prefix" column="member.ipaddress" var="s_ipaddress" pipe="or" />
<condition operation="like_prefix" column="member.last_login" var="s_last_login" pipe="or" />

View file

@ -2,7 +2,13 @@
<hr noshade="noshade" />
<ul>
<li>{$lang->site} : <a href="{getUrl()}" target="_blank">{getUrl()}</a></li>
<li loop="$memberInfo=>$name,$value" cond="!is_object($value)&&!is_array($value)">{$name} : {$value}</li>
<!--@if($memberInfo[$lang->user_id])-->
<li>{$lang->user_id} : {$memberInfo[$lang->user_id]}</li>
<!--@elseif($memberInfo[$lang->email_address])-->
<li>{$lang->email_address} : {$memberInfo[$lang->email_address]}</li>
<!--@elseif($memberInfo[$lang->phone_number])-->
<li>{$lang->phone_number} : {$memberInfo[$lang->phone_number]}</li>
<!--@end-->
<li>{$lang->password} : <span style="color:red">{$auth_args->new_password}</span></li>
</ul>
<hr noshade="noshade" />

View file

@ -97,7 +97,12 @@
{zdate($member_info['last_login'], 'Y-m-d')}
</td>
<td class="rx_detail_marks">{$member_info['group_list']}&nbsp;</td>
<td class="nowr"><a href="{getUrl('', 'module', 'admin', 'act', 'dispMemberAdminInsert', 'member_srl', $member_info['member_srl'])}">{$lang->inquiry}/{$lang->cmd_modify}</a></td>
<td class="nowr">
<a href="{getUrl('', 'module', 'admin', 'act', 'dispMemberAdminInsert', 'member_srl', $member_info['member_srl'])}">{$lang->inquiry}/{$lang->cmd_modify}</a><br />
<!--@if($member_info['member_srl'] != 4 && $logged_info->member_srl == 4)-->
<a href="#" class="_login_as" data-member-srl="{$member_info['member_srl']}">{$lang->cmd_login_as}</a>
<!--@end-->
</td>
{@$used_values = ''}
<!--@foreach($usedIdentifiers as $name=>$title)-->
{@$used_values .= "\t".$member_info[$name]}
@ -245,5 +250,19 @@ jQuery(function($){
}
}
});
// Login as member
$('a._login_as').click(function(e){
e.preventDefault();
if(!confirm('{$lang->msg_confirm_login_as}')) return;
var member_srl = $(this).data('member-srl');
var $form = $('#loginAsForm');
$form.find('input[name=member_srl]').val(member_srl);
$form.submit();
});
});
</script>
<form id="loginAsForm" action="./" method="post" style="display:none">
<input type="hidden" name="module" value="member" />
<input type="hidden" name="act" value="procMemberAdminLoginAs" />
<input type="hidden" name="member_srl" value="" />
</form>

View file

@ -51,23 +51,14 @@ class MenuAdminView extends Menu
$resultModuleList = $oMenuAdminModel->getModuleListInSitemap($site_srl);
Context::set('module_list', $resultModuleList);
// Get installed layout list
$oLayoutModel = getModel('layout');
$layoutList = $oLayoutModel->getLayoutList();
Context::set('layout_list', $layoutList);
// choice theme file
$theme_file = RX_BASEDIR.'files/theme/theme_info.php';
if(is_readable($theme_file))
{
include($theme_file);
Context::set('current_layout', $theme_info->layout);
}
else
{
$oModuleModel = getModel('module');
$default_mid = $oModuleModel->getDefaultMid();
Context::set('current_layout', $default_mid->layout_srl);
}
// Get current layout information
$default_mid = ModuleModel::getDefaultMid();
Context::set('current_layout', $default_mid->layout_srl);
// get default group list
$oMemberModel = getModel('member');

View file

@ -1,7 +0,0 @@
<filter name="insert_config" module="message" act="procMessageAdminInsertConfig" confirm_msg_code="confirm_submit">
<form />
<response callback_func="completeMessage">
<tag name="error" />
<tag name="message" />
</response>
</filter>

View file

@ -5,41 +5,27 @@ function doGetSkinColorset(skin, type) {
'skin' : skin,
'type': type,
};
var response_tags = [ 'error', 'message', 'tpl' ];
function on_complete(ret) {
var $container = jQuery('#colorset');
if(type == 'M'){
$container = jQuery('#mcolorset');
}
Rhymix.ajax('message.getMessageAdminColorset', params).then(function(ret) {
var $container = type == 'M' ? $('#mcolorset') : $('#colorset');
var old_h = $container.is(':visible') ? $container.outerHeight() : 0;
if(ret.tpl == ''){
if (ret.tpl == '') {
$container.hide();
}else{
} else {
$container.show();
var $colorset = jQuery('#message_colorset');
if(type == 'M'){
$colorset = jQuery('#message_mcolorset');
}
var $colorset = (type == 'M') ? $('#message_mcolorset') : $('#message_colorset');
$colorset.html(ret.tpl);
}
var new_h = $container.is(':visible') ? $container.outerHeight() : 0;
try {
fixAdminLayoutFooter(new_h - old_h)
} catch (e) {};
}
exec_xml('message', 'getMessageAdminColorset', params, on_complete, response_tags);
});
}
jQuery(function($){
$(function() {
doGetSkinColorset($('#skin').val());
doGetSkinColorset($('#mskin').val(), 'M');
});

View file

@ -1012,7 +1012,7 @@ class ModuleModel extends Module
$skin_list[$skin_name] = $skin_info;
}
$tmpPath = strtr($path, array('/' => ' '));
$tmpPath = strtr($path, array('/' => ' ', '\\' => ' '));
$tmpPath = trim($tmpPath);
$module = array_last(explode(' ', $tmpPath));

View file

@ -14,7 +14,7 @@ $lang->ncenterlite_type_scrap = '스크랩 알림';
$lang->ncenterlite_type_message = '쪽지 알림';
$lang->ncenterlite_type_test = '테스트 알림';
$lang->ncenterlite_type_admin_content = '관리자 알림';
$lang->ncenterlite_type_custom = '기타 알림';
$lang->ncenterlite_type_custom = '글 작성 알림';
$lang->ncenterlite_comment_noti = $lang->ncenterlite_type_comment;
$lang->ncenterlite_comment_comment_noti = $lang->ncenterlite_type_comment_comment;
$lang->ncenterlite_mention_noti = $lang->ncenterlite_type_mention;
@ -45,7 +45,7 @@ $lang->ncenterlite_message_noti_about = '새 쪽지가 도착하면 알림을
$lang->ncenterlite_vote_noti_about = '내 글이나 댓글이 추천을 받으면 알림을 받습니다.';
$lang->ncenterlite_scrap_noti_about = '누군가 내 글을 스크랩하면 알림을 받습니다.';
$lang->ncenterlite_admin_content_noti_about = '관리자 알림을 받습니다.';
$lang->ncenterlite_custom_noti_about = '기타 알림을 받습니다.';
$lang->ncenterlite_custom_noti_about = '팔로우한 회원의 작성 글 알림을 받습니다.(현재 여까/핫산 한정)';
$lang->ncneterlite_block_individual = '개별 문서/댓글 알림 차단';
$lang->ncneterlite_block_individual_about = '개별적으로 문서/댓글을 차단할 수 있습니다.';
$lang->ncenterlite_activate = '사용';

View file

@ -75,11 +75,12 @@ class Ncenterlite extends ModuleObject
{
return true;
}
/*
if($oDB->isColumnExists('ncenterlite_user_set','custom_notify'))
{
return true;
}
*/
// Extra data column
if (!$oDB->isColumnExists('ncenterlite_notify', 'data'))
@ -165,11 +166,12 @@ class Ncenterlite extends ModuleObject
{
$oDB->dropColumn('ncenterlite_user_set', 'admin_content_notify');
}
/*
if($oDB->isColumnExists('ncenterlite_user_set','custom_notify'))
{
$oDB->dropColumn('ncenterlite_user_set', 'custom_notify');
}
*/
// Composite index to speed up getNotifyList
if(!$oDB->isIndexExists('ncenterlite_notify', 'idx_member_srl_and_readed'))

View file

@ -123,6 +123,7 @@ class NcenterliteModel extends Ncenterlite
'vote' => 0,
'scrap' => 0,
'message' => 0,
'custom' => 0,
);
}

View file

@ -10,6 +10,7 @@
<column name="vote_notify" var="vote_notify" notnull="notnull" />
<column name="scrap_notify" var="scrap_notify" notnull="notnull" />
<column name="message_notify" var="message_notify" notnull="notnull" />
<column name="custom_notify" var="custom_notify" notnull="notnull" />
<column name="regdate" var="regdate" default="curdate()" />
</columns>
</query>

View file

@ -9,6 +9,7 @@
<column name="vote_notify" var="vote_notify" notnull="notnull" />
<column name="scrap_notify" var="scrap_notify" notnull="notnull" />
<column name="message_notify" var="message_notify" notnull="notnull" />
<column name="custom_notify" var="custom_notify" notnull="notnull" />
<column name="regdate" var="regdate" default="curdate()" />
</columns>
<conditions>

View file

@ -6,5 +6,6 @@
<column name="vote_notify" type="varchar" size="40" notnull="notnull" />
<column name="scrap_notify" type="varchar" size="40" notnull="notnull" />
<column name="message_notify" type="varchar" size="40" notnull="notnull" />
<column name="custom_notify" type="varchar" size="40" notnull="notnull" />
<column name="regdate" type="date" index="idx_regdate" />
</table>

View file

@ -175,7 +175,7 @@ class PageAdminController extends Page
$oDocumentController = getController('document');
$obj = new stdClass();
$obj->module_srl = $module_srl;
$obj->list_count = 99999999;
$obj->list_count = 0;
$output = $oDocumentModel->getDocumentList($obj);
if(count($output->data))
{

View file

@ -19,16 +19,17 @@ class PageMobile extends PageView
Context::set('document_srl', $document_srl);
}
Context::set('oDocument', $oDocument);
Context::set('page_content', $oDocument->getContent(false, false));
$oTemplate = Rhymix\Framework\Template::getInstance();
$template_path = $this->getTemplatePath();
$template_path = $this->getTemplatePath() ?: ($this->module_path . 'tpl');
if (preg_match('!/skins/!', $template_path))
{
$page_content = $oTemplate->compile($this->getTemplatePath(), 'content');
$page_content = $oTemplate->compile($template_path, 'content');
}
else
{
$page_content = $oTemplate->compile($this->getTemplatePath(), 'mobile');
$page_content = $oTemplate->compile($template_path, 'mobile');
}
return $page_content;

View file

@ -6,7 +6,7 @@
<param name="module_srl" target="module_srl" />
<param name="mid" target="mid" />
<param name="mcontent" target="content" />
<parma name="type" target="type" />
<param name="type" target="type" />
</parameter>
<response callback_func="completeInsertMobilePageContent">
<tag name="error" />

View file

@ -141,7 +141,7 @@ class SpamfilterModel extends Spamfilter
if (strpos($custom_message, '%s') !== false)
{
$custom_message = sprintf($custom_message, escape($hit, false));
$custom_message = sprintf($custom_message, substr(sha1($word), 0, 7));
}
return new BaseObject(-1, $custom_message);
@ -222,11 +222,11 @@ class SpamfilterModel extends Spamfilter
{
return false;
}
if ($user->is_admin === 'Y')
if ($user && $user->is_admin === 'Y')
{
return false;
}
if ($config->captcha->target_users !== 'everyone' && $user->member_srl)
if ($config->captcha->target_users !== 'everyone' && $user && $user->member_srl)
{
return false;
}

View file

@ -12,8 +12,9 @@
<thead>
<tr>
<th scope="col">{$lang->word}</th>
<th scope="col">오류코드</th>
<th scope="col">{$lang->description}</th>
<th scope="col">{$lang->cmd_spamfilter_except_member}</th>
<!-- th scope="col">{$lang->cmd_spamfilter_except_member}</th -->
<th scope="col">{$lang->cmd_spamfilter_filter_html}</th>
<th scope="col"><a href="{getUrl('sort_index', 'latest_hit')}">{$lang->latest_hit} <!--@if($sort_index === 'latest_hit')--><!--@endif--></a></th>
<th scope="col"><a href="{getUrl('sort_index', 'hit')}">{$lang->hit} <!--@if($sort_index === 'hit' || !$sort_index)--><!--@endif--></a></th>
@ -24,8 +25,9 @@
<tbody>
<tr loop="$word_list => $word_info">
<td>{$word_info->word} <!--@if(preg_match('#^/.+/$#', $word_info->word))--><span class="is_regexp">{$lang->cmd_spamfilter_is_regexp}</span><!--@end--></td>
<td>{substr(sha1($word_info->word), 0, 7)}</td>
<td>{$word_info->description}</td>
<td><a class="denied_word_toggle_except_member" href="#" data-word="{$word_info->word}">{$word_info->except_member}</a></td>
<!-- td><a class="denied_word_toggle_except_member" href="#" data-word="{$word_info->word}">{$word_info->except_member}</a></td -->
<td><a class="denied_word_toggle_filter_html" href="#" data-word="{$word_info->word}">{$word_info->filter_html}</a></td>
<td><!--@if($word_info->latest_hit)-->{zdate($word_info->latest_hit,'Y-m-d H:i')}<!--@else-->-<!--@end--></td>
<td>{$word_info->hit}</td>

View file

@ -18,5 +18,6 @@ v.cast('ADD_MESSAGE',['invalid_alpha_number','%s의 형식이 잘못되었습니
v.cast('ADD_MESSAGE',['invalid_mid','%s의 형식이 잘못되었습니다. 첫 글자는 영문으로 시작해야 하며 \'영문+숫자+_\'로만 입력해야 합니다.']);
v.cast('ADD_MESSAGE',['invalid_number','%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.']);
v.cast('ADD_MESSAGE',['invalid_float','%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.']);
v.cast('ADD_MESSAGE',['invalid_file','%s의 값은 올바르게 업로드된 파일이 아닙니다.']);
v.cast('ADD_MESSAGE',['invalid_extension','%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.']);
})(jQuery);

View file

@ -15,6 +15,16 @@ class SecurityTest extends \Codeception\Test\Unit
// Filename (more thorough tests in FilenameFilterTest)
$this->assertEquals('foo(bar).xls', Rhymix\Framework\Security::sanitize('foo<bar>.xls', 'filename'));
// SVG #1
$source = '<svg><rect><a href="javascript:alert(0)">Test</a></rect></svg>';
$target = '<?xml version="1.0" encoding="UTF-8"?>' . "\n<svg>\n <rect>\n <a>Test</a>\n </rect>\n</svg>\n";
$this->assertEquals($target, Rhymix\Framework\Security::sanitize($source, 'svg'));
// SVG #2
$source = '<svg><rect></rect><script></script></svg>';
$target = '<?xml version="1.0" encoding="UTF-8"?>' . "\n<svg>\n <rect></rect>\n</svg>\n";
$this->assertEquals($target, Rhymix\Framework\Security::sanitize($source, 'svg'));
}
public function testEncryption()

View file

@ -676,6 +676,16 @@ class TemplateParserV2Test extends \Codeception\Test\Unit
$source = '<p class="url(foo.svg)" style="url(../foo.jpg)"> url(img/foo.jpg); } </p>';
$target = '<p class="url(foo.svg)" style="url(' . $this->baseurl . 'tests/_data/foo.jpg)"> url(img/foo.jpg); } </p>';
$this->assertEquals($target, $this->_parse($source));
// No conversion if it's a template variable
$source = '<img src="{ get_image_path(\'foo/bar.jpg\') }" />';
$target = '<img src="{ get_image_path(\'foo/bar.jpg\') }" />';
$this->assertEquals($target, $this->_parse($source));
// No conversion if it's a JS template variable
$source = '@verbatim let src = `<source src="${foo.url}" />` @endverbatim';
$target = ' let src = `<source src="${foo.url}" />` ';
$this->assertEquals($target, $this->_parse($source));
}
public function testBlockConditions()

View file

@ -5,7 +5,7 @@
<ul class="nc_memu guest">
<li class="nc_profile fLeft">
<block cond="$useProfileImage">
<img cond="!$profileImage" src="{Context::getRequestUri()}modules/ncenterlite/skins/default/img/p.png" alt="my profile" class="nc_profile_img" />
<img cond="empty($profileImage)" src="{Context::getRequestUri()}modules/ncenterlite/skins/default/img/p.png" alt="my profile" class="nc_profile_img" />
</block>
<strong>손님</strong>
</li>