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 = '2.2.4';
public const JQUERY_V2_MIGRATE = '1.4.1'; public const JQUERY_V2_MIGRATE = '1.4.1';
public const JQUERY_V3 = '3.6.3'; public const JQUERY_V3 = '3.7.1';
public const JQUERY_V3_MIGRATE = '3.4.0'; public const JQUERY_V3_MIGRATE = '3.6.0';
/** /**
* Default viewport setting * Default viewport setting
@ -746,7 +746,8 @@ class HTMLDisplayHandler
*/ */
private function _loadCommonJSCSS() 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_version = self::JQUERY_V3;
$jquery_migrate_version = self::JQUERY_V3_MIGRATE; $jquery_migrate_version = self::JQUERY_V3_MIGRATE;

View file

@ -3,7 +3,7 @@
/** /**
* RX_VERSION is the version number of the Rhymix CMS. * 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. * 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', 'minify_scripts' => 'common',
'concat_scripts' => 'none', 'concat_scripts' => 'none',
'delay_compile' => 0, 'delay_compile' => 0,
'jquery_version' => 2, 'jquery_version' => 3,
), ),
'admin' => array( 'admin' => array(
'allow' => array(), 'allow' => array(),

View file

@ -38,6 +38,12 @@ class Security
if (!utf8_check($input)) return false; if (!utf8_check($input)) return false;
return Filters\FilenameFilter::clean($input); 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. // Unknown filters.
default: default:
throw new Exception('Unknown filter type for sanitize: ' . $type); throw new Exception('Unknown filter type for sanitize: ' . $type);

View file

@ -380,7 +380,7 @@ class Session
self::$_autologin_key = self::_getAutologinKey(); self::$_autologin_key = self::_getAutologinKey();
if (!$member_srl && self::$_autologin_key) 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)) if ($member_srl && self::isValid($member_srl))
{ {
self::login($member_srl, false); self::login($member_srl, false);

View file

@ -528,7 +528,7 @@ class Template
*/ */
public function isRelativePath(string $path): bool 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 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); $domain = parse_url($url, \PHP_URL_HOST);
if (!$domain)
{
return $url;
}
$position = strpos($url, $domain); $position = strpos($url, $domain);
if ($position === false) if ($position === false)
{ {
@ -243,9 +247,13 @@ class URL
*/ */
public static function decodeIdna(string $url): string 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); $domain = parse_url($url, \PHP_URL_HOST);
if (!$domain)
{
return $url;
}
$position = strpos($url, $domain); $position = strpos($url, $domain);
if ($position === false) if ($position === false)
{ {

View file

@ -44,7 +44,7 @@ class FileContentFilter
$skip_xml = preg_match('/^(hwpx)$/', $ext); $skip_xml = preg_match('/^(hwpx)$/', $ext);
// Check SVG files. // 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); fclose($fp);
return false; return false;
@ -89,11 +89,12 @@ class FileContentFilter
* @param resource $fp * @param resource $fp
* @param int $from * @param int $from
* @param int $to * @param int $to
* @param string $ext
* @return bool * @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; return false;
} }

View file

@ -184,6 +184,8 @@ class ConfigParser
if (isset($db_info->use_ssl) && in_array($db_info->use_ssl, ['always', 'optional'])) if (isset($db_info->use_ssl) && in_array($db_info->use_ssl, ['always', 'optional']))
{ {
$config['url']['ssl'] = 'always'; $config['url']['ssl'] = 'always';
$config['session']['use_ssl'] = true;
$config['session']['use_ssl_cookies'] = true;
} }
else 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_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_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_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->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->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'; $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_mid'] = '%s의 형식이 잘못되었습니다. 첫 글자는 영문으로 시작해야 하며 \'영문+숫자+_\'로만 입력해야 합니다.';
$lang->filter['invalid_number'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.'; $lang->filter['invalid_number'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.';
$lang->filter['invalid_float'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.'; $lang->filter['invalid_float'] = '%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.';
$lang->filter['invalid_file'] = '%s의 값은 올바르게 업로드된 파일이 아닙니다.';
$lang->filter['invalid_extension'] = '%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.'; $lang->filter['invalid_extension'] = '%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.';
$lang->security_invalid_session = '바르지 않은 접근입니다. 인증을 위해 다시 로그인해야 합니다.'; $lang->security_invalid_session = '바르지 않은 접근입니다. 인증을 위해 다시 로그인해야 합니다.';
$lang->security_warning_embed = '보안 문제로 관리자 아이디로는 embed를 볼 수 없습니다. 확인하려면 다른 아이디로 접속하세요'; $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> <a href="#" title="{$lang->cmd_search}"><i class="xi-magnifier"></i><span class="blind">{$lang->cmd_search}</span></a>
</li> </li>
<!-- admin --> <!-- 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> <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> </li>
<!-- login --> <!-- 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_en.css' => 'deleted:xe',
'modules/admin/tpl/css/admin_jp.css' => 'deleted:xe', 'modules/admin/tpl/css/admin_jp.css' => 'deleted:xe',
'modules/admin/tpl/css/admin_ko.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/ruleset/' => 'deleted:xe',
'modules/autoinstall/tpl/filter/uninstall_package.xml' => 'deleted:xe', 'modules/autoinstall/tpl/filter/uninstall_package.xml' => 'deleted:xe',
'modules/board/board.wap.php' => '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/install/tpl/js/install_admin.js' => 'deleted:xe',
'modules/integration_search/skins/default/trackback.html' => 'deleted', 'modules/integration_search/skins/default/trackback.html' => 'deleted',
'modules/member/skins/default/filter/find_member_account_by_question.xml' => 'deleted:xe', '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/schemas/site_admin.xml' => 'deleted',
'modules/module/tpl/css/module_admin.less' => 'deleted', 'modules/module/tpl/css/module_admin.less' => 'deleted',
'modules/page/page.wap.php' => 'deleted:xe', 'modules/page/page.wap.php' => 'deleted:xe',

View file

@ -20,17 +20,16 @@ class Notification extends Base
public function dispAdminConfigNotification() public function dispAdminConfigNotification()
{ {
// Load advanced mailer module (for lang). // Load advanced mailer module (for lang).
$oAdvancedMailerAdminView = \Advanced_mailerAdminView::getInstance(); $oAdvancedMailerController = \Advanced_mailerController::getInstance();
// Load advanced mailer config. // Load advanced mailer config.
$advanced_mailer_config = $oAdvancedMailerAdminView->getConfig(); $advanced_mailer_config = $oAdvancedMailerController->getConfig();
Context::set('advanced_mailer_config', $advanced_mailer_config); Context::set('advanced_mailer_config', $advanced_mailer_config);
// Load member config. // Load member config.
$member_config = ModuleModel::getModuleConfig('member'); $default_identity = $oAdvancedMailerController->getDefaultEmailIdentity();
Context::set('member_config', $member_config); Context::set('webmaster_name', $default_identity[1]);
Context::set('webmaster_name', !empty($member_config->webmaster_name) ? $member_config->webmaster_name : 'webmaster'); Context::set('webmaster_email', $default_identity[0]);
Context::set('webmaster_email', $member_config->webmaster_email ?? '');
// Load module config. // Load module config.
$module_config = ModuleModel::getModuleConfig('module'); $module_config = ModuleModel::getModuleConfig('module');
@ -89,7 +88,7 @@ class Notification extends Base
$vars = Context::getRequestVars(); $vars = Context::getRequestVars();
// Load advanced mailer module (for lang). // Load advanced mailer module (for lang).
$oAdvancedMailerAdminView = \Advanced_mailerAdminView::getInstance(); $oAdvancedMailerController = \Advanced_mailerController::getInstance();
// Validate the mail sender's information. // Validate the mail sender's information.
if (!$vars->mail_default_name) 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->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->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->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->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->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'; $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->cmd_concat_css_js = 'CSS와 JS를 모두 합침';
$lang->about_concat_scripts = 'CSS, JS 파일들을 하나로 합쳐서 전송합니다. 외부에서 로딩하는 스크립트는 합쳐지지 않습니다.'; $lang->about_concat_scripts = 'CSS, JS 파일들을 하나로 합쳐서 전송합니다. 외부에서 로딩하는 스크립트는 합쳐지지 않습니다.';
$lang->jquery_version = 'jQuery 버전'; $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->use_gzip = 'gzip 압축';
$lang->about_use_gzip = '웹서버가 gzip을 지원하지 않더라도 페이지를 강제로 압축하는 기능입니다. 대부분의 서버에는 필요하지 않습니다.'; $lang->about_use_gzip = '웹서버가 gzip을 지원하지 않더라도 페이지를 강제로 압축하는 기능입니다. 대부분의 서버에는 필요하지 않습니다.';
$lang->delay_session = '세션 시작 지연'; $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(){ $.fn.checkToggle = function(){
function check(){ function check(){
setTimeout(function(){ setTimeout(function(){
$(':checked').parent('label').addClass('checked'); $(':radio, :checkbox').each(function() {
$(':not(":checked")').parent('label').removeClass('checked'); if ($(this).is(':checked')) {
},0); $(this).parent('label').addClass('checked');
} else {
$(this).parent('label').removeClass('checked');
}
});
}, 0);
} }
this.change(check); this.change(check);
check(); check();

View file

@ -58,7 +58,21 @@ class BoardAdminController extends Board {
if($args->use_anonymous != 'Y') $args->use_anonymous = 'N'; if($args->use_anonymous != 'Y') $args->use_anonymous = 'N';
if($args->anonymous_except_admin != 'Y') $args->anonymous_except_admin = 'N'; if($args->anonymous_except_admin != 'Y') $args->anonymous_except_admin = 'N';
if($args->consultation != 'Y') $args->consultation = '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($this->user->isAdmin())
{ {
if($args->protect_admin_content_update != 'Y') $args->protect_admin_content_update = 'N'; 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 // install order (sorting) options
foreach($this->order_target as $key) $order_target[$key] = lang($key); 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'); $order_target['update_order'] = lang('last_update');
Context::set('order_target', $order_target); Context::set('order_target', $order_target);
} }

View file

@ -171,9 +171,10 @@ class BoardController extends Board
// Protect document by comment // Protect document by comment
if($this->module_info->protect_content == 'Y' || $this->module_info->protect_update_content == 'Y') 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 // check protect content
if($this->module_info->protect_content == 'Y' || $this->module_info->protect_delete_content == 'Y') 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); $comment = CommentModel::getComment($obj->comment_srl);
if($this->module_info->protect_update_comment === 'Y' && $this->grant->manager == false) 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); $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($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'); $format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate); $message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($massage); throw new Rhymix\Framework\Exception($message);
} }
} }
// check the grant // check the grant
@ -656,10 +659,11 @@ class BoardController extends Board
$childs = null; $childs = null;
if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false) 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); $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($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'); $format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate); $message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($massage); throw new Rhymix\Framework\Exception($message);
} }
} }
// generate comment controller object // generate comment controller object

View file

@ -547,7 +547,13 @@ class BoardView extends Board
$args->page = intval(Context::get('page')) ?: null; $args->page = intval(Context::get('page')) ?: null;
$args->list_count = $this->list_count; $args->list_count = $this->list_count;
$args->page_count = $this->page_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) 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)); $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'))) if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
{ {
$format = lang('msg_protect_regdate_document'); $format = lang('msg_protect_regdate_document');
$massage = sprintf($format, $this->module_info->protect_document_regdate); $message = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage); throw new Rhymix\Framework\Exception($message);
} }
} }
if ($this->module_info->protect_content === 'Y' || $this->module_info->protect_update_content === 'Y') 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); $point_config = ModuleModel::getModulePartConfig('point',$this->module_srl);
if ($point_config) 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 else
{ {
@ -1096,17 +1103,18 @@ class BoardView extends Board
{ {
if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day'))) if($oDocument->get('regdate') < date('YmdHis', strtotime('-'.$this->module_info->protect_document_regdate.' day')))
{ {
$format = lang('msg_protect_regdate_document'); $format = lang('msg_protect_regdate_document');
$massage = sprintf($format, $this->module_info->protect_document_regdate); $message = sprintf($format, $this->module_info->protect_document_regdate);
throw new Rhymix\Framework\Exception($massage); throw new Rhymix\Framework\Exception($message);
} }
} }
if($this->module_info->protect_content == "Y" || $this->module_info->protect_delete_content == 'Y') 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($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'); $format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate); $message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($massage); throw new Rhymix\Framework\Exception($message);
} }
} }
if($this->module_info->protect_update_comment === 'Y' && $this->grant->manager == false) 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); $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($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'); $format = lang('msg_protect_regdate_comment');
$massage = sprintf($format, $this->module_info->protect_document_regdate); $message = sprintf($format, $this->module_info->protect_comment_regdate);
throw new Rhymix\Framework\Exception($massage); throw new Rhymix\Framework\Exception($message);
} }
} }
if($this->module_info->protect_delete_comment === 'Y' && $this->grant->manager == false) 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); $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_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_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_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->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_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.'; $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->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->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->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_comment = 'Protect Comment';
$lang->protect_admin_content = 'Protect Admin Content'; $lang->protect_admin_content = 'Protect Admin Content';
$lang->protect_regdate = 'Update/Delete Time Limit'; $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->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_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_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_update = 'Prevent updating a post if it has %d or more comments.';
$lang->about_protect_content = 'Prevent updating a post if there are comments on it.'; $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->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 %d or more comments on it.';
$lang->msg_protect_update_content = 'You cannot update a post with 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_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_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_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_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.'; $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_admin_mail = '새 글이나 댓글이 등록되면 지정된 메일 주소로 알림을 받습니다. 여러 메일 주소를 지정하려면 쉼표(,)로 구분하세요.';
$lang->about_list_config = '게시판의 목록형식 사용시 원하는 항목들로 배치를 할 수 있습니다. 단 스킨에서 지원하지 않는 경우 불가능합니다. 대상항목/ 표시항목의 항목을 더블클릭하면 추가/ 제거가 됩니다.'; $lang->about_list_config = '게시판의 목록형식 사용시 원하는 항목들로 배치를 할 수 있습니다. 단 스킨에서 지원하지 않는 경우 불가능합니다. 대상항목/ 표시항목의 항목을 더블클릭하면 추가/ 제거가 됩니다.';
$lang->about_use_status = '글 작성 시 선택할 수 있는 상태를 지정해주세요.'; $lang->about_use_status = '글 작성 시 선택할 수 있는 상태를 지정해주세요.';
$lang->about_protect_comment = '댓글의 댓글이 있을경우 해당댓글을 삭제 및 수정을 할 수 없도록 합니다.';
$lang->about_update_log = '게시글을 수정할 경우 수정한 내역을 저장하도록 합니다.'; $lang->about_update_log = '게시글을 수정할 경우 수정한 내역을 저장하도록 합니다.';
$lang->skip_bottom_list_for_olddoc = '오래된 게시물 열람시 하단 목록을 정확하게 계산하지 않음'; $lang->skip_bottom_list_for_olddoc = '오래된 게시물 열람시 하단 목록을 정확하게 계산하지 않음';
$lang->skip_bottom_list_for_robot = '로봇 방문시 하단 목록을 정확하게 계산하지 않음'; $lang->skip_bottom_list_for_robot = '로봇 방문시 하단 목록을 정확하게 계산하지 않음';
@ -73,15 +72,19 @@ $lang->about_inline_data_url_limit = 'data: URL을 사용하여 첨부 제한을
$lang->update_order_on_comment = '댓글 작성시 글 수정 시각 갱신'; $lang->update_order_on_comment = '댓글 작성시 글 수정 시각 갱신';
$lang->about_update_order_on_comment = '댓글이 작성되면 해당 글의 수정 시각을 갱신합니다. 포럼형 게시판, 최근 댓글 표시 기능 등에 필요합니다.'; $lang->about_update_order_on_comment = '댓글이 작성되면 해당 글의 수정 시각을 갱신합니다. 포럼형 게시판, 최근 댓글 표시 기능 등에 필요합니다.';
$lang->about_filter_specialchars = '가독성에 악영향을 주는 과도한 유니코드 악센트 기호의 조합, RLO 문자 등의 사용을 금지합니다.'; $lang->about_filter_specialchars = '가독성에 악영향을 주는 과도한 유니코드 악센트 기호의 조합, RLO 문자 등의 사용을 금지합니다.';
$lang->about_protect_regdate = '글이나 댓글을 작성한 후 일정 기간이 지나면 수정 또는 삭제할 수 없도록 합니다. (단위 : day)'; $lang->about_protect_content_update = '댓글이 %d개 이상 달린 글은 수정할 수 없도록 합니다.';
$lang->about_protect_content = '댓글이 달린 글은 수정 또는 삭제할 수 없도록 합니다.'; $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->about_protect_admin_content = '최고관리자가 작성한 글이나 댓글은 게시판 관리 권한이 있는 회원이라도 수정 또는 삭제할 수 없도록 합니다.';
$lang->msg_protect_delete_content = '댓글이 달린 글은 삭제할 수 없습니다.'; $lang->msg_protect_update_content = '댓글이 %d개 이상 달린 글은 수정할 수 없습니다.';
$lang->msg_protect_update_content = '댓글이 달린 글은 수정할 수 없습니다.'; $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_document_no_modify = '최고관리자의 게시물을 수정할 권한이 없습니다.';
$lang->msg_admin_comment_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_document = '%d일 이상 지난 글은 수정 또는 삭제할 수 없습니다.';
$lang->msg_protect_regdate_comment = '%d일 이상 지난 댓글은 수정 또는 삭제할 수 없습니다.'; $lang->msg_protect_regdate_comment = '%d일 이상 지난 댓글은 수정 또는 삭제할 수 없습니다.';
$lang->msg_dont_have_update_log = '업데이트 로그가 기록되어 있지 않은 게시글입니다.'; $lang->msg_dont_have_update_log = '업데이트 로그가 기록되어 있지 않은 게시글입니다.';

View file

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

View file

@ -362,17 +362,52 @@
<div class="x_control-group"> <div class="x_control-group">
<label class="x_control-label">{$lang->protect_content}</label> <label class="x_control-label">{$lang->protect_content}</label>
<div class="x_controls"> <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 for="protect_update_content">
<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> <input type="checkbox" name="protect_update_content" id="protect_update_content" value="Y" checked="checked"|cond="$module_info->protect_update_content == 'Y'" />
<p>{$lang->about_protect_content}</p> {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> </div>
<div class="x_control-group"> <div class="x_control-group">
<label class="x_control-label">{$lang->protect_comment}</label> <label class="x_control-label">{$lang->protect_comment}</label>
<div class="x_controls"> <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 for="protect_update_comment">
<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> <input type="checkbox" name="protect_update_comment" id="protect_update_comment" value="Y" checked="checked"|cond="$module_info->protect_update_comment == 'Y'" />
<p>{$lang->about_protect_comment}</p> {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>
</div> </div>
<!--@if($this->user->isAdmin())--> <!--@if($this->user->isAdmin())-->
@ -385,14 +420,6 @@
</div> </div>
</div> </div>
<!--@end--> <!--@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"> <div class="x_control-group">
<label class="x_control-label" for="comment_delete_message">{$lang->comment_delete_message}</label> <label class="x_control-label" for="comment_delete_message">{$lang->comment_delete_message}</label>
<div class="x_controls"> <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; $point = 1;
$allow_same_ip = ($comment_config->allow_vote_from_same_ip ?? 'N') === 'Y'; $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'); $logged_info = Context::get('logged_info');
if (!$logged_info->member_srl) if (!$logged_info || !$logged_info->member_srl)
{ {
return $this->grant_cache = false; return $this->grant_cache = false;
} }
if ($logged_info->is_admin == 'Y') if ($logged_info && $logged_info->is_admin == 'Y')
{ {
return $this->grant_cache = true; 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; 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. // return if the currently logged-in user is an author of the comment.
$logged_info = Context::get('logged_info'); $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; return;
} }
@ -306,7 +306,7 @@ class CommentItem extends BaseObject
$title .= cut_str(strip_tags($content), 30, '...'); $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'))); $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'); $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 // send a message
$oCommunicationController = getController('communication'); $oCommunicationController = getController('communication');
@ -376,17 +376,24 @@ class CommentItem extends BaseObject
function getMyVote() function getMyVote()
{ {
if(!$this->comment_srl) return false; if (!$this->comment_srl)
if(isset($_SESSION['voted_comment'][$this->comment_srl])) {
return false;
}
if (isset($_SESSION['voted_comment'][$this->comment_srl]))
{ {
return $_SESSION['voted_comment'][$this->comment_srl]; return $_SESSION['voted_comment'][$this->comment_srl];
} }
$logged_info = Context::get('logged_info'); $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(); $args = new stdClass();
if($logged_info->member_srl) if ($logged_info && $logged_info->member_srl)
{ {
$args->member_srl = $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'); $logged_info = Context::get('logged_info');
if (!$logged_info->member_srl) if (!$logged_info || !$logged_info->member_srl)
{ {
return false; return false;
} }
@ -424,7 +431,7 @@ class CommentItem extends BaseObject
} }
$args = new stdClass(); $args = new stdClass();
if ($logged_info->member_srl) if ($logged_info && $logged_info->member_srl)
{ {
$args->member_srl = $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()); $url = getUrl('', 'module', 'admin', 'act', 'dispCommentAdminList', 'search_target', 'ipaddress', 'search_keyword', $oComment->getIpAddress());
$oCommentController->addCommentPopupMenu($url, 'cmd_search_by_ipaddress', '', 'TraceByIpaddress'); $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'); $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; $point = 1;
$allow_same_ip = ($document_config->allow_vote_from_same_ip ?? 'N') === 'Y'; $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. // 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'); $ev_output = $extra_item->uploadFile($value, $obj->document_srl, 'doc');
if (!$ev_output->toBool()) if (!$ev_output->toBool())
@ -1300,16 +1306,20 @@ class DocumentController extends Document
if ($extra_item->type === 'file') if ($extra_item->type === 'file')
{ {
// New upload // New upload
if (is_array($value) && isset($value['name'])) if (is_array($value) && isset($value['tmp_name']))
{ {
// Delete old file // Delete old file
if (isset($old_extra_vars[$idx]->value)) if (isset($old_extra_vars[$idx]->value))
{ {
$fc_output = FileController::getInstance()->deleteFile($old_extra_vars[$idx]->value); $old_file = FileModel::getFile($old_extra_vars[$idx]->value);
if (!$fc_output->toBool()) if ($old_file && $old_file->upload_target_srl == $obj->document_srl)
{ {
$oDB->rollback(); $fc_output = FileController::getInstance()->deleteFile($old_file->file_srl);
return $fc_output; if (!$fc_output->toBool())
{
$oDB->rollback();
return $fc_output;
}
} }
} }
// Insert new file // Insert new file
@ -1334,21 +1344,22 @@ class DocumentController extends Document
return $ev_output; return $ev_output;
} }
// Delete old file // Delete old file
$fc_output = FileController::getInstance()->deleteFile($old_extra_vars[$idx]->value); $old_file = FileModel::getFile($old_extra_vars[$idx]->value);
if (!$fc_output->toBool()) if ($old_file && $old_file->upload_target_srl == $obj->document_srl)
{ {
$oDB->rollback(); $fc_output = FileController::getInstance()->deleteFile($old_file->file_srl);
return $fc_output; if (!$fc_output->toBool())
{
$oDB->rollback();
return $fc_output;
}
} }
} }
} }
// Leave current file unchanged // 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; return $this->grant_cache = false;
} }
if ($logged_info->is_admin == 'Y') if ($logged_info && $logged_info->is_admin == 'Y')
{ {
return $this->grant_cache = true; 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; return $this->grant_cache = true;
} }
@ -411,7 +411,7 @@ class DocumentItem extends BaseObject
// Return if the currently logged-in user is an author // Return if the currently logged-in user is an author
$logged_info = Context::get('logged_info'); $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; 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)); $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 // 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); 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'); $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')); $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; return false;
} }
} }
$args = new stdClass; $args = new stdClass;
if($logged_info->member_srl) if ($logged_info && $logged_info->member_srl)
{ {
$args->member_srl = $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'); $logged_info = Context::get('logged_info');
if(!$logged_info->member_srl) if(!$logged_info || !$logged_info->member_srl)
{ {
return false; return false;
} }
@ -565,7 +565,7 @@ class DocumentItem extends BaseObject
} }
$args = new stdClass(); $args = new stdClass();
if($logged_info->member_srl) if($logged_info && $logged_info->member_srl)
{ {
$args->member_srl = $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. // Cache the vote log for all comments.
$logged_info = Context::get('logged_info'); $logged_info = Context::get('logged_info');
if ($logged_info->member_srl) if ($logged_info && $logged_info->member_srl)
{ {
$comment_srls = array(); $comment_srls = array();
foreach ($comment_list as $comment_srl => $comment) foreach ($comment_list as $comment_srl => $comment)
@ -1650,6 +1650,10 @@ class DocumentItem extends BaseObject
return ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl'))->browser_title; return ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl'))->browser_title;
} }
/**
* Get the title of the module to which the document belongs.
* @return string
*/
function getBrowserTitle() function getBrowserTitle()
{ {
return $this->getModuleName(); return $this->getModuleName();

View file

@ -111,6 +111,7 @@ class DocumentModel extends Document
foreach($GLOBALS['XE_EXTRA_KEYS'][$module_srl] as $idx => $key) foreach($GLOBALS['XE_EXTRA_KEYS'][$module_srl] as $idx => $key)
{ {
$document_extra_vars[$idx] = clone($key); $document_extra_vars[$idx] = clone($key);
$document_extra_vars[$idx]->parent_srl = $document_srl;
// set variable value in user language // set variable value in user language
if(isset($document_extra_values[$idx][$user_lang_code])) 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()); $url = getUrl('','module','admin','act','dispDocumentAdminList','search_target','ipaddress','search_keyword',$oDocument->getIpAddress());
$oDocumentController->addDocumentPopupMenu($url,'cmd_search_by_ipaddress',$icon_path,'TraceByIpaddress'); $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'); $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); $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 // get directly module_srl by mid
if(isset($searchOpt->mid) && $searchOpt->mid) if(isset($searchOpt->mid) && $searchOpt->mid)
@ -1562,13 +1567,13 @@ class DocumentModel extends Document
if($searchOpt->isExtraVars) if($searchOpt->isExtraVars)
{ {
$args->sort_eid = $args->sort_index; $args->sort_eid = $args->sort_index;
$args->sort_lang = Context::getLangType();
if ($searchOpt->isExtraVarsSortAsNumber ?? false) if ($searchOpt->isExtraVarsSortAsNumber ?? false)
{ {
$args->sort_index = 'extra_sort.sort_value'; $args->sort_index = 'extra_sort.sort_value';
} }
else else
{ {
$args->sort_lang = Context::getLangType();
$args->sort_index = 'extra_sort.value'; $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->declared_cancel_message_title = 'Cancel the reported a post.';
$lang->declaring_user = 'Reporter'; $lang->declaring_user = 'Reporter';
$lang->improper_document_declare_reason = 'Reason'; $lang->improper_document_declare_reason = 'Reason';
$lang->improper_document_reasons['advertisement'] = 'Advertisements that do not fit the topics or themes.'; $lang->improper_document_reasons['do_not_fight'] = '1. Do not fight';
$lang->improper_document_reasons['theme'] = 'Posts that do not fit the topics or themes.'; $lang->improper_document_reasons['sensitive_content'] = '2. Sensitive content';
$lang->improper_document_reasons['bad_word'] = 'Too much bad words.'; $lang->improper_document_reasons['spoiler'] = '3. Spoiler';
$lang->improper_document_reasons['violence'] = 'Violence.'; $lang->improper_document_reasons['tas_export'] = '4. TAS export';
$lang->improper_document_reasons['racism'] = 'Racism.'; $lang->improper_document_reasons['tas_swear'] = '5. TAS swear';
$lang->improper_document_reasons['pornography'] = 'Pornography.'; $lang->improper_document_reasons['ad'] = '6. Advertisement';
$lang->improper_document_reasons['privacy'] = 'Privacy issue.';
$lang->improper_document_reasons['others'] = 'Others (Write your own)'; $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->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'; $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->declared_cancel_message_title = '신고가 취소되었습니다.';
$lang->declaring_user = '신고자'; $lang->declaring_user = '신고자';
$lang->improper_document_declare_reason = '신고 이유'; $lang->improper_document_declare_reason = '신고 이유';
$lang->improper_document_reasons['advertisement'] = '주제나 흐름에 맞지 않는 광고 글입니다.'; $lang->improper_document_reasons['do_not_fight'] = '1. 싸우지 마세요 위반';
$lang->improper_document_reasons['theme'] = '주제에 맞지 않는 글입니다.'; $lang->improper_document_reasons['sensitive_content'] = '2. 후방글에는 반드시 후방 주의를 달아주세요 위반';
$lang->improper_document_reasons['bad_word'] = '과도한 욕설을 담고 있습니다.'; $lang->improper_document_reasons['spoiler'] = '3. 스포글에도 반드시 스포 주의 달아주세요 위반';
$lang->improper_document_reasons['violence'] = '폭력적인 내용을 담고 있습니다.'; $lang->improper_document_reasons['tas_export'] = '4. 타스 내수용 수출';
$lang->improper_document_reasons['racism'] = '인종차별적인 내용을 담고 있습니다.'; $lang->improper_document_reasons['tas_swear'] = '5. 타스 비방/욕설';
$lang->improper_document_reasons['pornography'] = '음란물을 포함하고 있습니다.'; $lang->improper_document_reasons['ad'] = '6. 광고/스팸글';
$lang->improper_document_reasons['privacy'] = '민감한 개인정보가 노출 되어있습니다.'; $lang->improper_document_reasons['others'] = '기타(직접 작성)';
$lang->improper_document_reasons['others'] = '기타(직접작성)';
$lang->about_improper_document_declare = '게시글을 신고하신 이유를 간단히 적어서 제출해주시면 관리자 검토 후 조치하겠습니다.'; $lang->about_improper_document_declare = '게시글을 신고하신 이유를 간단히 적어서 제출해주시면 관리자 검토 후 조치하겠습니다.';
$lang->allow_vote_from_same_ip = '동일 IP 추천 허용'; $lang->allow_vote_from_same_ip = '동일 IP 추천 허용';
$lang->allow_vote_non_member = '비회원 추천 허용'; $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->declared_cancel_message_title = 'Báo cáo đã bị hủy.';
$lang->declaring_user = 'Người báo'; $lang->declaring_user = 'Người báo';
$lang->improper_document_declare_reason = 'Lý do 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['do_not_fight'] = '1. Không gây gổ';
$lang->improper_document_reasons['theme'] = 'Bài viết không hợp với chủ đề.'; $lang->improper_document_reasons['sensitive_content'] = '2. Nội dung nhạy cảm';
$lang->improper_document_reasons['bad_word'] = 'Có chứa những lời chửi thề.'; $lang->improper_document_reasons['spoiler'] = '3. Tiết lộ nội dung';
$lang->improper_document_reasons['violence'] = 'Có nội dung bạo lực.'; $lang->improper_document_reasons['tas_export'] = '4. Xuất khẩu TAS';
$lang->improper_document_reasons['racism'] = 'Có nội dung phân biệt chủng tộc.'; $lang->improper_document_reasons['tas_swear'] = '5. Lời lẽ thô tục TAS';
$lang->improper_document_reasons['pornography'] = 'Có nội dung khiêu dâm.'; $lang->improper_document_reasons['ad'] = '6. Quảng cáo/Spam';
$lang->improper_document_reasons['privacy'] = 'Thông tin cá nhân nhạy cảm được tiết lộ.';
$lang->improper_document_reasons['others'] = 'Khác(Tự viết)'; $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ý.'; $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="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" 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="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="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" /> <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="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="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_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="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" 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="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="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" /> <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="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="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_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="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" 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="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="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" /> <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="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="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_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="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.is_secret" var="s_is_secret" pipe="or" />
<condition operation="equal" column="d.member_srl" var="s_member_srl" 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.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="d.voted_count" var="s_voted_count" pipe="or" /> <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="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.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="d.trackback_count" var="s_trackback_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="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" 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="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="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" /> <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="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="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_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="homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="tags" var="s_tags" 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="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="readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="voted_count" var="s_voted_count" pipe="or" /> <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="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="comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="trackback_count" var="s_trackback_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.homepage" var="s_homepage" pipe="or" />
<condition operation="like" column="documents.tags" var="s_tags" 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="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.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" /> <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="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.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="documents.trackback_count" var="s_trackback_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="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.is_secret" var="s_is_secret" pipe="or" />
<condition operation="equal" column="d.member_srl" var="s_member_srl" 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.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="d.voted_count" var="s_voted_count" pipe="or" /> <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="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.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="d.trackback_count" var="s_trackback_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="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.is_notice" var="s_is_notice" pipe="or" />
<condition operation="equal" column="documents.member_srl" var="s_member_srl" 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.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" /> <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="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.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="documents.trackback_count" var="s_trackback_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="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.is_secret" var="s_is_secret" pipe="or" />
<condition operation="equal" column="documents.member_srl" var="s_member_srl" 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.readed_count" var="s_readed_count" pipe="and" />
<condition operation="more" column="documents.voted_count" var="s_voted_count" pipe="or" /> <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="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.comment_count" var="s_comment_count" pipe="or" />
<condition operation="more" column="documents.trackback_count" var="s_trackback_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> </div>
</form> </form>
<form action="./" class="x_pagination"> <form action="./" class="x_pagination" no-error-return-url="true">
<input type="hidden" name="error_return_url" value="" />
<input type="hidden" name="module" value="{$module}" /> <input type="hidden" name="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" /> <input type="hidden" name="act" value="{$act}" />
<input cond="$search_keyword" type="hidden" name="search_keyword" value="{$search_keyword}" /> <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> <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> </ul>
</form> </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="module" value="{$module}" />
<input type="hidden" name="act" value="{$act}" /> <input type="hidden" name="act" value="{$act}" />
<input type="hidden" name="error_return_url" value="" />
<select name="module_srl" style="margin-right:4px"> <select name="module_srl" style="margin-right:4px">
<option value="">{lang('all')}</option> <option value="">{lang('all')}</option>
<!--@foreach($module_list as $item)--> <!--@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="module" value="document" />
<input type="hidden" name="act" value="procDocumentManageCheckedDocument" /> <input type="hidden" name="act" value="procDocumentManageCheckedDocument" />
<input type="hidden" name="type" value="" /> <input type="hidden" name="type" value="" />
<input type="hidden" name="module_srl" value="" /> <input type="hidden" name="module_srl" value="{$module_srl}" />
<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="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" /> <input type="hidden" name="xe_validator_id" value="modules/document/tpl/document_list/1" />
<div class="x_modal-header"> <div class="x_modal-header">
<h1>{$lang->document_manager}: <span class="_sub"></span></h1> <h1>{$lang->document_manager}: <span class="_sub"></span></h1>

View file

@ -387,6 +387,7 @@ class EditorModel extends Editor
} }
else else
{ {
$logged_info = new Rhymix\Framework\Helpers\SessionHelper();
$group_list = array(); $group_list = array();
} }
@ -507,7 +508,7 @@ class EditorModel extends Editor
$logged_info = Context::get('logged_info'); $logged_info = Context::get('logged_info');
$auto_save_args->member_srl = $logged_info->member_srl; $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]; $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}); unset($component_list->{$key});
continue; continue;
} }
if($logged_info->is_admin == "Y") continue; if($logged_info && $logged_info->is_admin == "Y") continue;
if($val->target_group) if(isset($val->target_group) && $val->target_group)
{ {
if(!Context::get('is_logged')) if(!Context::get('is_logged'))
{ {
@ -664,7 +665,7 @@ class EditorModel extends Editor
if(!$is_granted) $val->enabled = "N"; 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'); $mid = Context::get('mid');
if(!in_array($mid, $val->mid_list)) $val->enabled = "N"; 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" <div cond="$allow_fileupload" id="xefu-container-{$editor_sequence}" class="xefu-container xe-clearfix"
data-editor-sequence="{$editor_sequence}" data-editor-sequence="{$editor_sequence}"
data-editor-status="{json_encode(FileModel::getInstance()->getFileList($editor_sequence), JSON_UNESCAPED_UNICODE)}" 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-max-chunk-size="{$file_config->allowed_chunk_size ?: 0}"
data-autoinsert-types="{json_encode($editor_autoinsert_types)}" data-autoinsert-types="{json_encode($editor_autoinsert_types)}"
data-autoinsert-position="{$editor_autoinsert_position ?: 'paragraph'}"> data-autoinsert-position="{$editor_autoinsert_position ?: 'paragraph'}">

View file

@ -25,6 +25,7 @@ class Value
public $input_id = ''; public $input_id = '';
public $input_name = ''; public $input_name = '';
public $parent_type = 'document'; public $parent_type = 'document';
public $parent_srl = null;
public $type = 'text'; public $type = 'text';
public $value = null; public $value = null;
public $name = ''; public $name = '';
@ -159,7 +160,7 @@ class Value
*/ */
public function getValueHTML(): string 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]; $values = [$value];
} }
// Check if a required value is empty. // Check that a required value is not empty.
if ($this->is_required === 'Y') if ($this->is_required === 'Y')
{ {
if ($this->type === 'file' && !$value && $old_value) 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->is_strict === 'Y' && $value)
{ {
if ($this->canHaveOptions()) 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; return new BaseObject;
} }
@ -442,9 +452,11 @@ class Value
* *
* @param string $type * @param string $type
* @param string|array $value * @param string|array $value
* @param string $parent_type
* @param ?int $parent_srl
* @return string * @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. // Return if the value is empty.
$value = self::_getTypeValue($type, $value); $value = self::_getTypeValue($type, $value);
@ -511,10 +523,14 @@ class Value
if ($value) if ($value)
{ {
$file = FileModel::getFile($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)); 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 else
{ {
return ''; return '';

View file

@ -551,7 +551,7 @@ class FileController extends File
{ {
$download_type = 'inline'; $download_type = 'inline';
} }
if (Context::get('force_download') === 'Y') if ($mime_type === 'image/svg+xml' || Context::get('force_download') === 'Y')
{ {
$download_type = 'attachment'; $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 // Adjust
if(!$manual_insert) if(!$manual_insert)
{ {

View file

@ -204,6 +204,13 @@ class installController extends install
// Set the default umask. // Set the default umask.
$config['file']['umask'] = Rhymix\Framework\Storage::recommendUmask(); $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. // Load the new configuration.
Rhymix\Framework\Config::setAll($config); Rhymix\Framework\Config::setAll($config);
Context::loadDBInfo($config); Context::loadDBInfo($config);

View file

@ -28,6 +28,11 @@ class installView extends install
// Specify the template path. // Specify the template path.
$this->setTemplatePath($this->module_path.'tpl'); $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. // Check the environment.
$oInstallController = getController('install'); $oInstallController = getController('install');
self::$checkEnv = $oInstallController->checkInstallEnv(); self::$checkEnv = $oInstallController->checkInstallEnv();

View file

@ -1,7 +1,7 @@
<?php <?php
$lang->krzip = 'Korean Postal Code'; $lang->krzip = 'Korean Postal Code';
$lang->cmd_krzip_api_type = 'Select API Provider'; $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_epostapi = 'Korea Post API';
$lang->cmd_krzip_postcodify = 'Postcodify'; $lang->cmd_krzip_postcodify = 'Postcodify';
$lang->cmd_krzip_regkey = 'Registration Key'; $lang->cmd_krzip_regkey = 'Registration Key';

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -17,10 +17,11 @@
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr loop="$layout_list => $key, $layout"> <!--@foreach($layout_list as $layout)-->
<block cond="$layout->title"> <tr>
<!--@if($layout->title)-->
<td class="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>{$layout->description}</p>
<p cond="$layout->need_update == 'Y'" class="update"> <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> {$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> </block>
</td> </td>
<td class="rx_detail_marks">{$layout->path}</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> <td class="nowr rx_detail_marks">
</block> <a cond="$layout->remove_url" class="x_btn x_btn-link" href="{$layout->remove_url}&amp;return_url={urlencode(getRequestUriByServerEnviroment())}">{$lang->cmd_delete}</a>
<block cond="!$layout->title"> </td>
<!--@else-->
<td class="title"> <td class="title">
<p><a href="{getUrl('act', 'dispLayoutAdminInstanceList', 'type', $type, 'layout', $layout->layout)}">{$layout->layout}</a></p> <p><a href="{getUrl('act', 'dispLayoutAdminInstanceList', 'type', $type, 'layout', $layout->layout)}">{$layout->layout}</a></p>
<p cond="$layout->need_update == 'Y'" class="update"> <p cond="$layout->need_update == 'Y'" class="update">
@ -52,7 +54,31 @@
<td>-</td> <td>-</td>
<td>-</td> <td>-</td>
<td class="rx_detail_marks">{$layout->path}</td> <td class="rx_detail_marks">{$layout->path}</td>
</block> <td class="rx_detail_marks"></td>
<!--@endif-->
</tr> </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> </tbody>
</table> </table>

View file

@ -1,6 +1,6 @@
<ul class="x_nav x_nav-tabs"> <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', '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', 'M')}">Mobile ({$mobileLayoutCount})</a></li>
</ul> </ul>
<div> <div>
<a class="active"|cond="$act == 'dispLayoutAdminAllInstanceList'" href="{getUrl('act', 'dispLayoutAdminAllInstanceList', 'layout_srl', '')}">{$lang->instance_layout}</a> <i>|</i> <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="procMemberAdminUpdateGroupOrder" type="controller" />
<action name="procMemberAdminUpdateMembersGroup" type="controller" ruleset="manageMemberGroup" /> <action name="procMemberAdminUpdateMembersGroup" type="controller" ruleset="manageMemberGroup" />
<action name="procMemberAdminDeleteMembers" type="controller" /> <action name="procMemberAdminDeleteMembers" type="controller" />
<action name="procMemberAdminLoginAs" type="controller" />
</actions> </actions>
<eventHandlers> <eventHandlers>
<eventHandler after="document.getDocumentMenu" class="controller" method="triggerGetDocumentMenu" /> <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['last_login_ipaddress'] = 'Last Login IP address';
$lang->search_target_list['birthday'] = 'Birthday'; $lang->search_target_list['birthday'] = 'Birthday';
$lang->search_target_list['extra_vars'] = 'User Defined'; $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_modify_new_auth_email_address = 'New email address';
$lang->cmd_set_design_info = 'Desgin'; $lang->cmd_set_design_info = 'Desgin';
$lang->cmd_login = 'Login'; $lang->cmd_login = 'Login';
@ -406,3 +407,6 @@ $lang->member_unauthenticated = 'Unauthenticated';
$lang->member_number = 'Member identification number'; $lang->member_number = 'Member identification number';
$lang->msg_change_after_click = 'Change after clicking link below'; $lang->msg_change_after_click = 'Change after clicking link below';
$lang->msg_password_changed = 'Your password has been changed.'; $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['last_login_ipaddress'] = '최근 로그인 IP 주소';
$lang->search_target_list['birthday'] = '생일'; $lang->search_target_list['birthday'] = '생일';
$lang->search_target_list['extra_vars'] = '사용자 정의'; $lang->search_target_list['extra_vars'] = '사용자 정의';
$lang->search_target_list['description'] = '관리자 메모';
$lang->cmd_modify_new_auth_email_address = '신규 메일 주소로 변경 후 인증 메일 발송'; $lang->cmd_modify_new_auth_email_address = '신규 메일 주소로 변경 후 인증 메일 발송';
$lang->cmd_set_design_info = '디자인'; $lang->cmd_set_design_info = '디자인';
$lang->cmd_login = '로그인'; $lang->cmd_login = '로그인';
@ -410,3 +411,6 @@ $lang->member_unauthenticated = '미인증';
$lang->member_number = '회원 번호'; $lang->member_number = '회원 번호';
$lang->msg_change_after_click = '아래 링크 클릭 후 변경 가능'; $lang->msg_change_after_click = '아래 링크 클릭 후 변경 가능';
$lang->msg_password_changed = '비밀번호가 변경되었습니다.'; $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(); 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 */ /* End of file member.admin.controller.php */
/* Location: ./modules/member/member.admin.controller.php */ /* Location: ./modules/member/member.admin.controller.php */

View file

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

View file

@ -1837,6 +1837,7 @@ class MemberController extends Member
} }
Context::set('auth_args', $args); Context::set('auth_args', $args);
// Prepare member information to be included in the email #2594 #2663
$memberInfo = array(); $memberInfo = array();
if (in_array('user_id', $member_config->identifiers)) if (in_array('user_id', $member_config->identifiers))
{ {
@ -1846,6 +1847,21 @@ class MemberController extends Member
{ {
$memberInfo[$lang->email_address] = $member_info->email_address; $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); Context::set('memberInfo', $memberInfo);
if(!$member_config->skin) $member_config->skin = "default"; if(!$member_config->skin) $member_config->skin = "default";
@ -2383,7 +2399,7 @@ class MemberController extends Member
* @param string $autologin_key * @param string $autologin_key
* @return int|false * @return int|false
*/ */
function doAutologin($autologin_key = null) public static function doAutoLogin($autologin_key = null)
{ {
// Validate the key. // Validate the key.
if (strlen($autologin_key) == 48) if (strlen($autologin_key) == 48)
@ -2426,6 +2442,28 @@ class MemberController extends Member
return false; 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 current security key matches, generate a new key.
// If the previous key matches, don't update until the client has the current 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. // 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. // Update the last login time.
executeQuery('member.updateLastLogin', (object)['member_srl' => $output->data->member_srl]); self::updateLastLogin($output->data->member_srl);
self::clearMemberCache($output->data->member_srl);
// Call a trigger after validate security key (after) // Call a trigger after validate security key.
$trigger_obj = new stdClass(); ModuleHandler::triggerCall('member.doAutoLogin', 'after', $member_info);
$trigger_obj->member_srl = $output->data->member_srl;
ModuleHandler::triggerCall('member.doAutoLogin', 'after', $trigger_obj);
// Return the member_srl. // Return the member_srl.
return intval($output->data->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. // Check if there is recoding table.
$oDB = DB::getInstance(); $oDB = DB::getInstance();
if($oDB->isTableExists('member_count_history') && $config->enable_login_fail_report != 'N') if($oDB->isTableExists('member_count_history') && $config->enable_login_fail_report != 'N')
@ -2698,6 +2728,7 @@ class MemberController extends Member
// Log in! // Log in!
Rhymix\Framework\Session::login($member_info->member_srl); Rhymix\Framework\Session::login($member_info->member_srl);
self::updateLastLogin($member_info->member_srl);
$this->setSessionInfo(); $this->setSessionInfo();
// Log out all other sessions if so configured. // Log out all other sessions if so configured.
@ -2712,10 +2743,23 @@ class MemberController extends Member
return $output; 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 * 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 // If your information came through the current session information to extract information from the users
$member_info = Rhymix\Framework\Session::getMemberInfo(true); $member_info = Rhymix\Framework\Session::getMemberInfo(true);
@ -3105,7 +3149,7 @@ class MemberController extends Member
* *
* @param bool $deprecated_allow_update_other * @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) // Call a trigger (before)
$output = ModuleHandler::triggerCall('member.updateMember', 'before', $args); $output = ModuleHandler::triggerCall('member.updateMember', 'before', $args);
@ -3131,7 +3175,7 @@ class MemberController extends Member
{ {
unset($args->is_admin); unset($args->is_admin);
unset($args->limit_date); unset($args->limit_date);
unset($args->description); if(!$manual_updated) unset($args->description);
if (!$deprecated_allow_update_other) if (!$deprecated_allow_update_other)
{ {
unset($args->denied); unset($args->denied);
@ -3345,7 +3389,7 @@ class MemberController extends Member
if(!$args->user_name) $args->user_name = $orgMemberInfo->user_name; if(!$args->user_name) $args->user_name = $orgMemberInfo->user_name;
if(!$args->user_id) $args->user_id = $orgMemberInfo->user_id; if(!$args->user_id) $args->user_id = $orgMemberInfo->user_id;
if(!$args->nick_name) $args->nick_name = $orgMemberInfo->nick_name; 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; $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="phone_number" var="s_phone_number" pipe="or" />
<condition operation="like" column="birthday" var="s_birthday" 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="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="regdate" var="s_regdate" pipe="or" />
<condition operation="like_prefix" column="ipaddress" var="s_ipaddress" 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" /> <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.phone_number" var="s_phone_number" pipe="or" />
<condition operation="like" column="member.birthday" var="s_birthday" 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.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.regdate" var="s_regdate" pipe="or" />
<condition operation="like_prefix" column="member.ipaddress" var="s_ipaddress" 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" /> <condition operation="like_prefix" column="member.last_login" var="s_last_login" pipe="or" />

View file

@ -2,7 +2,13 @@
<hr noshade="noshade" /> <hr noshade="noshade" />
<ul> <ul>
<li>{$lang->site} : <a href="{getUrl()}" target="_blank">{getUrl()}</a></li> <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> <li>{$lang->password} : <span style="color:red">{$auth_args->new_password}</span></li>
</ul> </ul>
<hr noshade="noshade" /> <hr noshade="noshade" />

View file

@ -97,7 +97,12 @@
{zdate($member_info['last_login'], 'Y-m-d')} {zdate($member_info['last_login'], 'Y-m-d')}
</td> </td>
<td class="rx_detail_marks">{$member_info['group_list']}&nbsp;</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 = ''} {@$used_values = ''}
<!--@foreach($usedIdentifiers as $name=>$title)--> <!--@foreach($usedIdentifiers as $name=>$title)-->
{@$used_values .= "\t".$member_info[$name]} {@$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> </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); $resultModuleList = $oMenuAdminModel->getModuleListInSitemap($site_srl);
Context::set('module_list', $resultModuleList); Context::set('module_list', $resultModuleList);
// Get installed layout list
$oLayoutModel = getModel('layout'); $oLayoutModel = getModel('layout');
$layoutList = $oLayoutModel->getLayoutList(); $layoutList = $oLayoutModel->getLayoutList();
Context::set('layout_list', $layoutList); Context::set('layout_list', $layoutList);
// choice theme file // Get current layout information
$theme_file = RX_BASEDIR.'files/theme/theme_info.php'; $default_mid = ModuleModel::getDefaultMid();
if(is_readable($theme_file)) Context::set('current_layout', $default_mid->layout_srl);
{
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 default group list // get default group list
$oMemberModel = getModel('member'); $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, 'skin' : skin,
'type': type, 'type': type,
}; };
var response_tags = [ 'error', 'message', 'tpl' ];
function on_complete(ret) { Rhymix.ajax('message.getMessageAdminColorset', params).then(function(ret) {
var $container = jQuery('#colorset'); var $container = type == 'M' ? $('#mcolorset') : $('#colorset');
if(type == 'M'){
$container = jQuery('#mcolorset');
}
var old_h = $container.is(':visible') ? $container.outerHeight() : 0; var old_h = $container.is(':visible') ? $container.outerHeight() : 0;
if(ret.tpl == ''){ if (ret.tpl == '') {
$container.hide(); $container.hide();
}else{ } else {
$container.show(); $container.show();
var $colorset = jQuery('#message_colorset'); var $colorset = (type == 'M') ? $('#message_mcolorset') : $('#message_colorset');
if(type == 'M'){
$colorset = jQuery('#message_mcolorset');
}
$colorset.html(ret.tpl); $colorset.html(ret.tpl);
} }
var new_h = $container.is(':visible') ? $container.outerHeight() : 0; var new_h = $container.is(':visible') ? $container.outerHeight() : 0;
try { try {
fixAdminLayoutFooter(new_h - old_h) fixAdminLayoutFooter(new_h - old_h)
} catch (e) {}; } catch (e) {};
} });
exec_xml('message', 'getMessageAdminColorset', params, on_complete, response_tags);
} }
jQuery(function($){ $(function() {
doGetSkinColorset($('#skin').val()); doGetSkinColorset($('#skin').val());
doGetSkinColorset($('#mskin').val(), 'M'); doGetSkinColorset($('#mskin').val(), 'M');
}); });

View file

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

View file

@ -14,7 +14,7 @@ $lang->ncenterlite_type_scrap = '스크랩 알림';
$lang->ncenterlite_type_message = '쪽지 알림'; $lang->ncenterlite_type_message = '쪽지 알림';
$lang->ncenterlite_type_test = '테스트 알림'; $lang->ncenterlite_type_test = '테스트 알림';
$lang->ncenterlite_type_admin_content = '관리자 알림'; $lang->ncenterlite_type_admin_content = '관리자 알림';
$lang->ncenterlite_type_custom = '기타 알림'; $lang->ncenterlite_type_custom = '글 작성 알림';
$lang->ncenterlite_comment_noti = $lang->ncenterlite_type_comment; $lang->ncenterlite_comment_noti = $lang->ncenterlite_type_comment;
$lang->ncenterlite_comment_comment_noti = $lang->ncenterlite_type_comment_comment; $lang->ncenterlite_comment_comment_noti = $lang->ncenterlite_type_comment_comment;
$lang->ncenterlite_mention_noti = $lang->ncenterlite_type_mention; $lang->ncenterlite_mention_noti = $lang->ncenterlite_type_mention;
@ -45,7 +45,7 @@ $lang->ncenterlite_message_noti_about = '새 쪽지가 도착하면 알림을
$lang->ncenterlite_vote_noti_about = '내 글이나 댓글이 추천을 받으면 알림을 받습니다.'; $lang->ncenterlite_vote_noti_about = '내 글이나 댓글이 추천을 받으면 알림을 받습니다.';
$lang->ncenterlite_scrap_noti_about = '누군가 내 글을 스크랩하면 알림을 받습니다.'; $lang->ncenterlite_scrap_noti_about = '누군가 내 글을 스크랩하면 알림을 받습니다.';
$lang->ncenterlite_admin_content_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 = '개별 문서/댓글 알림 차단';
$lang->ncneterlite_block_individual_about = '개별적으로 문서/댓글을 차단할 수 있습니다.'; $lang->ncneterlite_block_individual_about = '개별적으로 문서/댓글을 차단할 수 있습니다.';
$lang->ncenterlite_activate = '사용'; $lang->ncenterlite_activate = '사용';

View file

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

View file

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

View file

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

View file

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

View file

@ -6,5 +6,6 @@
<column name="vote_notify" type="varchar" size="40" notnull="notnull" /> <column name="vote_notify" type="varchar" size="40" notnull="notnull" />
<column name="scrap_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="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" /> <column name="regdate" type="date" index="idx_regdate" />
</table> </table>

View file

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

View file

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

View file

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

View file

@ -141,7 +141,7 @@ class SpamfilterModel extends Spamfilter
if (strpos($custom_message, '%s') !== false) 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); return new BaseObject(-1, $custom_message);
@ -222,11 +222,11 @@ class SpamfilterModel extends Spamfilter
{ {
return false; return false;
} }
if ($user->is_admin === 'Y') if ($user && $user->is_admin === 'Y')
{ {
return false; return false;
} }
if ($config->captcha->target_users !== 'everyone' && $user->member_srl) if ($config->captcha->target_users !== 'everyone' && $user && $user->member_srl)
{ {
return false; return false;
} }

View file

@ -12,8 +12,9 @@
<thead> <thead>
<tr> <tr>
<th scope="col">{$lang->word}</th> <th scope="col">{$lang->word}</th>
<th scope="col">오류코드</th>
<th scope="col">{$lang->description}</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">{$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', '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> <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> <tbody>
<tr loop="$word_list => $word_info"> <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>{$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>{$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><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><!--@if($word_info->latest_hit)-->{zdate($word_info->latest_hit,'Y-m-d H:i')}<!--@else-->-<!--@end--></td>
<td>{$word_info->hit}</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_mid','%s의 형식이 잘못되었습니다. 첫 글자는 영문으로 시작해야 하며 \'영문+숫자+_\'로만 입력해야 합니다.']);
v.cast('ADD_MESSAGE',['invalid_number','%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.']); v.cast('ADD_MESSAGE',['invalid_number','%s의 형식이 잘못되었습니다. 숫자로만 입력해야 합니다.']);
v.cast('ADD_MESSAGE',['invalid_float','%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 등 쉼표로 구분하여 입력해야 합니다.']); v.cast('ADD_MESSAGE',['invalid_extension','%s의 형식이 잘못되었습니다. gif, jpg, png 등 쉼표로 구분하여 입력해야 합니다.']);
})(jQuery); })(jQuery);

View file

@ -15,6 +15,16 @@ class SecurityTest extends \Codeception\Test\Unit
// Filename (more thorough tests in FilenameFilterTest) // Filename (more thorough tests in FilenameFilterTest)
$this->assertEquals('foo(bar).xls', Rhymix\Framework\Security::sanitize('foo<bar>.xls', 'filename')); $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() 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>'; $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>'; $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)); $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() public function testBlockConditions()

View file

@ -5,7 +5,7 @@
<ul class="nc_memu guest"> <ul class="nc_memu guest">
<li class="nc_profile fLeft"> <li class="nc_profile fLeft">
<block cond="$useProfileImage"> <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> </block>
<strong>손님</strong> <strong>손님</strong>
</li> </li>