Merge branch 'rhymix:master' into master

This commit is contained in:
Lastorder 2025-03-03 10:47:47 +09:00 committed by GitHub
commit e5b729f8e9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
152 changed files with 2348 additions and 792 deletions

View file

@ -11,3 +11,6 @@ $lang->about_installed_addon = 'Check PC and Mobile to switch on the addon.';
$lang->fixed = 'Fixed';
$lang->about_fixed = 'Check this, and the site administrator cannot change this setting.';
$lang->msg_not_exist_option = 'Configuration for this addon does not exist.';
$lang->run_method = 'Select opt-in or opt-out';
$lang->run_selected_module = 'Run this addon on the selected modules';
$lang->no_run_selected_module = 'Do NOT run this addon on the selected modules';

View file

@ -113,7 +113,7 @@ $lang->cmd_new_domain = 'Add New Domain';
$lang->cmd_edit_domain = 'Edit Domain';
$lang->cmd_is_default_domain = 'Default Domain';
$lang->cmd_multidomain_configuration = 'Multidomain Configuration';
$lang->cmd_unregistered_domain_action = 'Unregistered Domains';
$lang->cmd_unregistered_domain_action = 'Unconfigured Domains';
$lang->cmd_unregistered_domain_redirect_301 = '301 Redirect to Default Domain (Recommended)';
$lang->cmd_unregistered_domain_redirect_302 = '302 Redirect to Default Domain';
$lang->cmd_unregistered_domain_display = 'Display Main Screen as Usual';
@ -329,7 +329,7 @@ $lang->use_rewrite = 'Use Short URLs';
$lang->use_rewrite_0 = 'None';
$lang->use_rewrite_1 = 'XE-compatible URLs only';
$lang->use_rewrite_2 = 'All supported URLs';
$lang->about_use_rewrite = 'Your web server must support mod_rewrite in order for short URLs to work. Apache usually detects the .htaccess file automatically.<br />nginx users should configure rewrite rules according to <a href="https://github.com/rhymix/rhymix-docs/blob/master/ko/introduction/nginx.md> target="_blank">the manual</a>. Outdated versions of nginx rewrite rules only support XE-compatible short URLs.';
$lang->about_use_rewrite = 'Your web server must support mod_rewrite in order for short URLs to work. Apache usually detects the .htaccess file automatically.<br />nginx users should configure rewrite rules according to <a href="https://github.com/rhymix/rhymix-docs/blob/master/ko/introduction/nginx.md" target="_blank">the manual</a>. Outdated versions of nginx rewrite rules only support XE-compatible short URLs.';
$lang->timezone = 'Time Zone';
$lang->use_mobile_view = 'Enable Mobile View';
$lang->about_use_mobile_view = 'Show mobile page when visitors access with mobile devices.';
@ -371,7 +371,7 @@ $lang->site_default_color_scheme_options = array(
'dark' => 'Dark mode only',
);
$lang->use_sso = 'Use <abbr title="Single Sign On">SSO</abbr>?';
$lang->about_use_sso = 'Logging into one domain will automatically log the user into all domains.';
$lang->about_use_sso = 'Logging into one domain will automatically log the user into all domains.<br>Do not rely on this feature, as it will be removed in the future.';
$lang->about_arrange_session = 'Do you want to clean up old session data?';
$lang->cmd_clear_session = 'Session cleanup';
$lang->save = 'Save';

View file

@ -112,7 +112,7 @@ $lang->cmd_new_domain = '새 도메인 추가';
$lang->cmd_edit_domain = '도메인 정보 수정';
$lang->cmd_is_default_domain = '기본 도메인';
$lang->cmd_multidomain_configuration = '멀티도메인 기능 설정';
$lang->cmd_unregistered_domain_action = '등록되지 않은 도메인 처리';
$lang->cmd_unregistered_domain_action = '설정하지 않은 도메인 처리';
$lang->cmd_unregistered_domain_redirect_301 = '기본 도메인으로 301 Redirect (권장)';
$lang->cmd_unregistered_domain_redirect_302 = '기본 도메인으로 302 Redirect';
$lang->cmd_unregistered_domain_display = '메인 화면 표시';
@ -367,7 +367,7 @@ $lang->site_default_color_scheme_options = array(
'dark' => '어두운 색상 고정',
);
$lang->use_sso = '<abbr title="Single Sign On">SSO</abbr> 사용';
$lang->about_use_sso = '한 번만 로그인하면 모든 도메인에 로그인되도록 합니다.';
$lang->about_use_sso = '한 번만 로그인하면 모든 도메인에 로그인되도록 합니다.<br>이 기능은 폐기 예정이니 의존하지 마시기 바랍니다.';
$lang->about_arrange_session = '세션을 정리하시겠습니까?';
$lang->cmd_clear_session = '세션 정리';
$lang->save = '저장';

View file

@ -338,6 +338,9 @@ body>.x,
padding: 10px 15px;
border-bottom: 1px solid #aaa;
background-color: #78909C;
display: flex;
justify-content: space-between;
align-items: center;
}
.x .x_modal-header>h1,
.x .x_modal-header>h2,
@ -347,6 +350,13 @@ body>.x,
margin: 0;
color: #fff;
}
.x .x_modal-header>.close_window {
font-size: 20px;
font-weight: bold;
text-decoration: none;
color: #fff;
opacity: 0.5;
}
.x .x_modal-body {
overflow-y: visible;
max-height: none;

View file

@ -370,7 +370,7 @@ class autoinstallModel extends autoinstall
function getRemoveUrlByPackageSrl($packageSrl)
{
$ftp_info = Context::getFTPInfo();
if(!$ftp_info->ftp_root_path)
if(empty($ftp_info->ftp_root_path))
{
return;
}

View file

@ -6,7 +6,7 @@ $lang->order_newest = 'Newest';
$lang->order_popular = 'Popular';
$lang->order_download = 'Download';
$lang->success_installed = 'Successfully Installed';
$lang->description_ftp_note = 'If the %s is not set, the installation or update will not work. Pleas configure the FTP information.';
$lang->description_ftp_note = 'If the %s is not set, the installation or update will not work. Please configure the FTP information.';
$lang->ftp_setup = 'FTP configuration';
$lang->description_update = 'Click %s before using EasyInstall.';
$lang->status_update = 'update button';
@ -42,6 +42,8 @@ $lang->msg_sftp_not_supported = 'SFTP is not supported.';
$lang->msg_no_permission_to_install = 'Your web server does not have permission to update the installation path. Please check server permissions.';
$lang->msg_direct_install_not_supported = 'Cannot proceed due to write permission missing to the directories listed in the list below.';
$lang->msg_does_not_support_delete = 'Cannot delete this package (no moduleUninstall() in the module class).';
$lang->msg_update_core_title = 'Rhymix Core is updateing.';
$lang->msg_update_core = 'Prior to updating Rhymix Core, please check the compatibility of the installed packages (e.g., modules, widgets, layouts, skins, etc.).';
$lang->installed = 'Installed';
$lang->typename['core'] = 'Core';
$lang->typename['m.layout'] = 'Mobile layout';

View file

@ -9,44 +9,58 @@
class Board extends ModuleObject
{
var $search_option = array('title_content','title','content','comment','user_name','nick_name','user_id','tag'); ///< 검색 옵션
var $order_target = array('list_order', 'update_order', 'regdate', 'voted_count', 'blamed_count', 'readed_count', 'comment_count', 'title', 'nick_name', 'user_name', 'user_id'); // 정렬 옵션
var $skin = "default"; ///< skin name
var $list_count = 20; ///< the number of documents displayed in a page
var $page_count = 10; ///< page number
var $category_list = NULL; ///< category list
/**
* constructor
*
* @return void
* Default search columns
*/
function __construct()
{
parent::__construct();
}
public $search_option = [
'title_content',
'title',
'content',
'comment',
'user_name',
'nick_name',
'user_id',
'tag',
];
/**
* @brief install the module
**/
* Default sort columns
*/
public $order_target = [
'list_order',
'update_order',
'regdate',
'voted_count',
'blamed_count',
'readed_count',
'comment_count',
'title',
'nick_name',
'user_name',
'user_id',
];
/**
* Default values
*/
public $skin = 'default';
public $list_count = 20;
public $page_count = 10;
public $category_list;
/**
* Callback functions for autoinstall
*/
function moduleInstall()
{
}
/**
* @brief chgeck module method
**/
function checkUpdate()
{
}
/**
* @brief update module
**/
function moduleUpdate()
{
@ -54,17 +68,6 @@ class Board extends ModuleObject
function moduleUninstall()
{
$output = executeQueryArray("board.getAllBoard");
if(!$output->data) return new BaseObject();
@set_time_limit(0);
$oModuleController = getController('module');
foreach($output->data as $board)
{
$oModuleController->deleteModule($board->module_srl);
}
return new BaseObject();
}
}

View file

@ -5,21 +5,14 @@
* @class boardController
* @author NAVER (developers@xpressengine.com)
* @brief board module Controller class
**/
*/
class BoardController extends Board
{
/**
* @brief initialization
**/
function init()
{
}
/**
* @brief insert document
**/
function procBoardInsertDocument()
*/
public function procBoardInsertDocument()
{
// check grant
if(!$this->grant->write_document)
@ -152,7 +145,6 @@ class BoardController extends Board
$manual = true;
$anonymous_name = $this->module_info->anonymous_name ?: 'anonymous';
$anonymous_name = $this->createAnonymousName($anonymous_name, $logged_info->member_srl, $obj->document_srl);
$this->module_info->admin_mail = '';
$obj->notify_message = 'N';
$obj->email_address = $obj->homepage = $obj->user_id = '';
@ -295,7 +287,7 @@ class BoardController extends Board
$this->setMessage($msg_code);
}
function procBoardRevertDocument()
public function procBoardRevertDocument()
{
$update_id = Context::get('update_id');
$logged_info = Context::get('logged_info');
@ -338,8 +330,8 @@ class BoardController extends Board
/**
* @brief delete the document
**/
function procBoardDeleteDocument()
*/
public function procBoardDeleteDocument()
{
// get the document_srl
$document_srl = Context::get('document_srl');
@ -416,8 +408,8 @@ class BoardController extends Board
/**
* @brief vote
**/
function procBoardVoteDocument()
*/
public function procBoardVoteDocument()
{
// Check document_srl
$document_srl = intval(Context::get('document_srl'));
@ -434,8 +426,8 @@ class BoardController extends Board
/**
* @brief insert comments
**/
function procBoardInsertComment()
*/
public function procBoardInsertComment()
{
// check grant
if(!$this->grant->write_comment)
@ -513,7 +505,6 @@ class BoardController extends Board
// For anonymous use, remove writer's information and notifying information
if($this->module_info->use_anonymous == 'Y' && (!$this->grant->manager || ($this->module_info->anonymous_except_admin ?? 'N') !== 'Y'))
{
$this->module_info->admin_mail = '';
$obj->notify_message = 'N';
$obj->member_srl = -1*$logged_info->member_srl;
$obj->email_address = $obj->homepage = $obj->user_id = '';
@ -625,8 +616,8 @@ class BoardController extends Board
/**
* @brief delete the comment
**/
function procBoardDeleteComment()
*/
public function procBoardDeleteComment()
{
// get the comment_srl
$comment_srl = Context::get('comment_srl');
@ -741,8 +732,8 @@ class BoardController extends Board
/**
* @brief delete the tracjback
**/
function procBoardDeleteTrackback()
*/
public function procBoardDeleteTrackback()
{
$trackback_srl = Context::get('trackback_srl');
@ -765,8 +756,8 @@ class BoardController extends Board
/**
* @brief check the password for document and comment
**/
function procBoardVerificationPassword()
*/
public function procBoardVerificationPassword()
{
// get the id number of the document and the comment
$password = Context::get('password');
@ -790,7 +781,9 @@ class BoardController extends Board
}
$oComment->setGrantForSession();
} else {
}
else
{
// get the document information
$oDocument = DocumentModel::getDocument($document_srl);
if(!$oDocument->isExists())
@ -810,8 +803,8 @@ class BoardController extends Board
/**
* @brief the trigger for displaying 'view document' link when click the user ID
**/
function triggerMemberMenu($obj)
*/
public function triggerMemberMenu($obj)
{
if(!$mid = Context::get('cur_mid'))
{

View file

@ -3,7 +3,7 @@
class BoardMobile extends BoardView
{
function getBoardCommentPage()
public function getBoardCommentPage()
{
$this->dispBoardCommentPage();
$oTemplate = TemplateHandler::getInstance();

View file

@ -5,22 +5,16 @@
* @class boardModel
* @author NAVER (developers@xpressengine.com)
* @brief board module Model class
**/
*/
class BoardModel extends Board
{
/**
* @brief initialization
**/
function init()
{
}
/**
* @brief get the list configuration
**/
*/
public static function getListConfig($module_srl)
{
// get the list config value, if it is not exitsted then setup the default value
$module_srl = (int)$module_srl;
$list_config = ModuleModel::getModulePartConfig('board', $module_srl);
if(!is_array($list_config) || count($list_config) <= 0)
{
@ -53,7 +47,7 @@ class BoardModel extends Board
/**
* @brief return the default list configration value
**/
*/
public static function getDefaultListConfig($module_srl)
{
$extra_vars = [];
@ -84,7 +78,7 @@ class BoardModel extends Board
/**
* @brief return module name in sitemap
**/
*/
public function triggerModuleListInSitemap(&$obj)
{
array_push($obj, 'board');

View file

@ -5,24 +5,26 @@
* @class boardView
* @author NAVER (developers@xpressengine.com)
* @brief board module View class
**/
*/
class BoardView extends Board
{
var $listConfig;
var $columnList;
/**
* Default values
*/
public $listConfig = [];
public $columnList = [];
/**
* @brief initialization
* board module can be used in either normal mode or admin mode.\n
**/
function init()
*/
public function init()
{
$oSecurity = new Security();
$oSecurity->encodeHTML('document_srl', 'comment_srl', 'vid', 'mid', 'page', 'category', 'search_target', 'search_keyword', 'sort_index', 'order_type', 'trackback_srl');
/**
* setup the module general information
**/
*/
$m = Context::get('m');
$this->list_count = $m ? ($this->module_info->mobile_list_count ?? 20) : ($this->module_info->list_count ?? 20);
$this->search_list_count = $m ? ($this->module_info->mobile_search_list_count ?? 20) : ($this->module_info->search_list_count ?? 20);
@ -68,7 +70,7 @@ class BoardView extends Board
/**
* check the consultation function, if the user is admin then swich off consultation function
* if the user is not logged, then disppear write document/write comment./ view document
**/
*/
if($this->module_info->consultation == 'Y' && !$this->grant->manager && !$this->grant->consultation_read)
{
$this->consultation = TRUE;
@ -87,13 +89,13 @@ class BoardView extends Board
/**
* use context::set to setup extra variables
**/
*/
$extra_keys = DocumentModel::getExtraKeys($this->module_info->module_srl);
Context::set('extra_keys', $extra_keys);
/**
* add extra variables to order(sorting) target
**/
*/
if (is_array($extra_keys))
{
foreach($extra_keys as $val)
@ -103,7 +105,7 @@ class BoardView extends Board
}
/**
* load javascript, JS filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'input_password.xml');
Context::loadFile([$this->module_path.'tpl/js/board.js', 'head']);
if (config('url.rewrite') > 1)
@ -127,12 +129,12 @@ class BoardView extends Board
/**
* @brief display board contents
**/
function dispBoardContent()
*/
public function dispBoardContent()
{
/**
* check the access grant (all the grant has been set by the module object)
**/
*/
if(!$this->grant->access || !$this->grant->list)
{
$this->dispBoardMessage($this->user->isMember() ? 'msg_not_permitted' : 'msg_not_logged');
@ -140,13 +142,13 @@ class BoardView extends Board
/**
* display the category list, and then setup the category list on context
**/
*/
$this->dispBoardCategoryList();
/**
* display the search options on the screen
* add extra vaiables to the search options
**/
*/
// use search options on the template (the search options key has been declared, based on the language selected)
foreach($this->search_option as $opt) $search_option[$opt] = lang($opt);
$extra_keys = Context::get('extra_keys');
@ -208,7 +210,7 @@ class BoardView extends Board
/**
* add javascript filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'search.xml');
$oSecurity = new Security();
@ -220,10 +222,11 @@ class BoardView extends Board
/**
* @brief display the category list
**/
function dispBoardCategoryList(){
*/
public function dispBoardCategoryList()
{
// check if the use_category option is enabled
if($this->module_info->use_category=='Y')
if ($this->module_info->use_category === 'Y' || !empty($this->include_modules))
{
// check the grant
if(!$this->grant->list)
@ -239,14 +242,31 @@ class BoardView extends Board
}
else
{
$category_list = DocumentModel::getCategoryList($this->module_srl);
if ($this->module_info->use_category === 'Y')
{
$category_list = DocumentModel::getCategoryList($this->module_srl);
}
else
{
$category_list = [];
}
foreach ($this->include_modules as $module_srl)
{
if ($module_srl != $this->module_srl)
{
$category_list += DocumentModel::getCategoryList($module_srl);
if ((ModuleModel::getModuleExtraVars($module_srl)->hide_category ?? 'N') !== 'Y')
{
$category_list += DocumentModel::getCategoryList($module_srl);
}
}
}
if ($category_list)
{
$this->module_info->hide_category = 'N';
$this->module_info->use_category = 'Y';
}
}
Context::set('category_list', $category_list);
@ -257,15 +277,16 @@ class BoardView extends Board
/**
* @brief display the board conent view
**/
function dispBoardContentView(){
*/
public function dispBoardContentView()
{
// get the variable value
$document_srl = Context::get('document_srl');
$page = Context::get('page');
/**
* if the document exists, then get the document information
**/
*/
if($document_srl)
{
$oDocument = DocumentModel::getDocument($document_srl, false, true);
@ -318,16 +339,17 @@ class BoardView extends Board
/**
* if the document is not existed, get an empty document
**/
*/
}
else
{
$oDocument = DocumentModel::getDocument(0);
$oDocument->add('module_srl', $this->module_srl);
}
/**
*check the document view grant
**/
*/
if($oDocument->isExists())
{
if(!$this->grant->view && !$oDocument->isGranted())
@ -373,17 +395,18 @@ class BoardView extends Board
/**
* add javascript filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'insert_comment.xml');
}
/**
* @brief display the document file list (can be used by API)
**/
function dispBoardContentFileList(){
*/
public function dispBoardContentFileList()
{
/**
* check the access grant (all the grant has been set by the module object)
**/
*/
if(!$this->grant->access)
{
return $this->dispBoardMessage('msg_not_permitted');
@ -449,8 +472,9 @@ class BoardView extends Board
/**
* @brief display the document comment list (can be used by API)
**/
function dispBoardContentCommentList(){
*/
public function dispBoardContentCommentList()
{
// check document view grant
$this->dispBoardContentView();
@ -475,8 +499,9 @@ class BoardView extends Board
/**
* @brief display notice list (can be used by API)
**/
function dispBoardNoticeList(){
*/
public function dispBoardNoticeList()
{
// check the grant
if(!$this->grant->list || (Context::get('document_srl') && $this->module_info->use_bottom_list === 'N'))
{
@ -502,8 +527,9 @@ class BoardView extends Board
/**
* @brief display board content list
**/
function dispBoardContentList(){
*/
public function dispBoardContentList()
{
// check the grant
if(!$this->grant->list || (Context::get('document_srl') && $this->module_info->use_bottom_list === 'N'))
{
@ -670,7 +696,7 @@ class BoardView extends Board
}
}
function _makeListColumnList()
public function _makeListColumnList()
{
// List of all available columns
$allColumnList = array(
@ -727,8 +753,8 @@ class BoardView extends Board
/**
* @brief display tag list
**/
function dispBoardTagList()
*/
public function dispBoardTagList()
{
// check if there is not grant fot view list, then alert an warning message
if(!$this->grant->list)
@ -774,7 +800,7 @@ class BoardView extends Board
/**
* @brief display category list
*/
function dispBoardCategory()
public function dispBoardCategory()
{
$this->dispBoardCategoryList();
$this->setTemplateFile('category.html');
@ -783,7 +809,7 @@ class BoardView extends Board
/**
* @brief display comment page
*/
function dispBoardCommentPage()
public function dispBoardCommentPage()
{
$document_srl = Context::get('document_srl');
if(!$document_srl)
@ -810,8 +836,8 @@ class BoardView extends Board
/**
* @brief display document write form
**/
function dispBoardWrite()
*/
public function dispBoardWrite()
{
// check grant
if(!$this->grant->write_document)
@ -821,7 +847,7 @@ class BoardView extends Board
/**
* check if the category option is enabled not not
**/
*/
if($this->module_info->use_category=='Y')
{
// get the user group information
@ -969,7 +995,7 @@ class BoardView extends Board
/**
* add JS filters
**/
*/
if($this->grant->manager || $this->module_info->allow_no_category == 'Y')
{
Context::addJsFilter($this->module_path.'tpl/filter', 'insert_admin.xml');
@ -985,7 +1011,7 @@ class BoardView extends Board
$this->setTemplateFile('write_form');
}
function _getStatusNameList()
public function _getStatusNameList()
{
$resultList = array();
if(!empty($this->module_info->use_status))
@ -1006,8 +1032,8 @@ class BoardView extends Board
/**
* @brief display board module deletion form
**/
function dispBoardDelete()
*/
public function dispBoardDelete()
{
// check grant
if(!$this->grant->write_document)
@ -1078,7 +1104,7 @@ class BoardView extends Board
/**
* add JS filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'delete_document.xml');
$this->setTemplateFile('delete_form');
@ -1086,8 +1112,8 @@ class BoardView extends Board
/**
* @brief display comment wirte form
**/
function dispBoardWriteComment()
*/
public function dispBoardWriteComment()
{
$document_srl = Context::get('document_srl');
@ -1122,7 +1148,7 @@ class BoardView extends Board
/**
* add JS filter
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'insert_comment.xml');
$this->setTemplateFile('comment_form');
@ -1130,8 +1156,8 @@ class BoardView extends Board
/**
* @brief display comment replies page
**/
function dispBoardReplyComment()
*/
public function dispBoardReplyComment()
{
// check grant
if(!$this->grant->write_comment)
@ -1191,7 +1217,7 @@ class BoardView extends Board
/**
* add JS filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'insert_comment.xml');
$this->setTemplateFile('comment_form');
@ -1199,8 +1225,8 @@ class BoardView extends Board
/**
* @brief display the comment modification from
**/
function dispBoardModifyComment()
*/
public function dispBoardModifyComment()
{
// check grant
if(!$this->grant->write_comment)
@ -1275,7 +1301,7 @@ class BoardView extends Board
/**
* add JS fitlers
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'insert_comment.xml');
$this->setTemplateFile('comment_form');
@ -1283,8 +1309,8 @@ class BoardView extends Board
/**
* @brief display the delete comment form
**/
function dispBoardDeleteComment()
*/
public function dispBoardDeleteComment()
{
// check grant
if(!$this->grant->write_comment)
@ -1358,7 +1384,7 @@ class BoardView extends Board
/**
* add JS filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'delete_comment.xml');
$this->setTemplateFile('delete_comment_form');
@ -1366,8 +1392,8 @@ class BoardView extends Board
/**
* @brief display the delete trackback form
**/
function dispBoardDeleteTrackback()
*/
public function dispBoardDeleteTrackback()
{
$oTrackbackModel = getModel('trackback');
if(!$oTrackbackModel)
@ -1393,13 +1419,13 @@ class BoardView extends Board
/**
* add JS filters
**/
*/
Context::addJsFilter($this->module_path.'tpl/filter', 'delete_trackback.xml');
$this->setTemplateFile('delete_trackback_form');
}
function dispBoardUpdateLog()
public function dispBoardUpdateLog()
{
if($this->grant->update_view !== true)
{
@ -1427,7 +1453,7 @@ class BoardView extends Board
$this->setTemplateFile('update_list');
}
function dispBoardUpdateLogView()
public function dispBoardUpdateLogView()
{
if($this->grant->update_view !== true)
{
@ -1464,7 +1490,7 @@ class BoardView extends Board
$this->setTemplateFile('update_view');
}
function dispBoardVoteLog()
public function dispBoardVoteLog()
{
iF($this->grant->vote_log_view !== true)
{
@ -1528,7 +1554,7 @@ class BoardView extends Board
/**
* Default 404 Handler.
*/
function dispBoardNotFound()
public function dispBoardNotFound()
{
$this->dispBoardMessage('msg_not_founded', 404);
}
@ -1540,7 +1566,7 @@ class BoardView extends Board
* @param int $http_code
* @return void
*/
function dispBoardMessage($msg_code, $http_code = 403)
public function dispBoardMessage($msg_code, $http_code = 403)
{
//Context::set('message', lang($msg_code));
//$this->setTemplateFile('message');
@ -1561,11 +1587,10 @@ class BoardView extends Board
* @param int $http_code
* @return void
*/
function alertMessage($msg_code, $http_code = 403)
public function alertMessage($msg_code, $http_code = 403)
{
$script = sprintf('<script> jQuery(function(){ alert(%s); } );</script>', json_encode(lang($msg_code)));
Context::addHtmlFooter($script);
$this->setHttpStatusCode($http_code);
}
}

View file

@ -11,44 +11,45 @@ $lang->list_target_item = 'Target Item';
$lang->list_display_item = 'Display Item';
$lang->summary = 'Summary';
$lang->thumbnail = 'Thumbnail';
$lang->last_post = 'Last post';
$lang->last_post = 'Last Post';
$lang->board_management = 'Board Management';
$lang->search_result = 'Search Result';
$lang->consultation = 'Consultation';
$lang->use_consultation = 'Use as Consultation Board';
$lang->secret = 'Secret';
$lang->thisissecret = 'This is a secret article.';
$lang->thisissecret = 'This is a secret post.';
$lang->admin_mail = 'Administrator\'s Mail';
$lang->update_log = 'Update Log';
$lang->last_updater = 'Latest Update by';
$lang->cmd_board_list = 'Boards List';
$lang->cmd_module_config = 'Common Board Setting';
$lang->cmd_module_config = 'Common Board Settings';
$lang->cmd_board_info = 'Board Info';
$lang->cmd_list_setting = 'List Setting';
$lang->cmd_list_setting = 'List Settings';
$lang->cmd_list_items = 'Displayed Items and Order';
$lang->cmd_create_board = 'Create a new board';
$lang->cmd_create_board = 'Create a New Board';
$lang->cmd_manage_selected_board = 'Manage Selected Board';
$lang->about_layout_setup = 'You can manually modify board layout code. Insert or manage the widget code anywhere you want';
$lang->about_board_category = 'You can make board categories. When board category is broken, try rebuilding the cache file manually.';
$lang->about_except_notice = 'Notices will not be displayed in the normal list.<br />Caution: using this option can increase DB load if you have many visitors and lots of articles.';
$lang->about_use_bottom_list = 'Display the list at the bottom when viewing an article.';
$lang->about_customize_bottom_list = 'Calculating the bottom list consumes a lot of server resources.<br />You may be able to reduce DB load by not calculating it exactly when not needed.<br />This should have no effect on SEO.';
$lang->about_layout_setup = 'You can manually modify the board layout code. Insert or manage the widget code anywhere you want.';
$lang->about_board_category = 'You can make board categories. When a board category is broken, try rebuilding the cache file manually.';
$lang->about_except_notice = 'Notices will not be displayed in the normal list.<br />Caution: Using this option may increase DB load if you have many visitors and lots of posts.';
$lang->about_use_bottom_list = 'Display the list at the bottom when viewing a post.';
$lang->about_customize_bottom_list = 'Exact calculations of the lists consume a lot of server resources.<br />You can save server resources by calculating it roughly.<br />This should have no effect on SEO.';
$lang->about_use_anonymous_part1 = 'Hide the author\'s nickname to turn this board into an anonymous board.';
$lang->about_use_anonymous_part2 = 'It is more useful if you also hide the nickname in the skin.<br>Please also turn off document history, or the author\'s information may be revealed by the history.';
$lang->about_use_anonymous_part2 = 'It is more useful if you hide the nickname in the skin, as well.<br>Please concurrently turn off post history, which may unveil the author\'s information.';
$lang->about_anonymous_except_admin = 'The administrator\'s nickname will not be hidden.';
$lang->about_anonymous_name = 'You can customize the anonymous name that is displayed instead of the author\'s nickname.<br><b>$NUM</b> will be replaced with a random number that is unique to each member. (e.g. anon_$NUM → anon_12345678)<br><b>$DAILYNUM</b> will be replaced with a random number that is unique to each member but changes every day.<br><b>$DOCNUM</b> will be replaced with a random number that is unique to each member and changes from document to document.<br><b>$DOCDAILYNUM</b> will be replaced with a random number that is unique to each member and changes every day from document to document.<br>You can append a number to each variable, like <strong>$DAILYNUM:5</strong> to control the number of digits from 1 to 8.<br>To use hexadecimal digits that include some alphabets, use <strong>STR</strong> instead of <strong>NUM</strong>.';
$lang->about_anonymous_name = 'You can customize the anonymous name that will be displayed instead of the author\'s nickname.<br><b>$NUM</b> will be replaced with a random number that is unique to each member. (e.g. anon_$NUM → anon_12345678)<br><b>$DAILYNUM</b> will be replaced with a random number that is unique to each member but changes every day.<br><b>$DOCNUM</b> will be replaced with a random number that is unique to each member and changes from post to post.<br><b>$DOCDAILYNUM</b> will be replaced with a random number that is unique to each member and changes every day from post to post.<br>You can append a number to each variable, like <strong>$DAILYNUM:5</strong> to control the number of digits from 1 to 8.<br>To use hexadecimal digits that include some alphabets, use <strong>STR</strong> instead of <strong>NUM</strong>.';
$lang->about_board = 'This module is for creating and managing boards.';
$lang->about_consultation = 'Members who are not maangers will only see their own articles.<br>When this feature is enabled, non-members cannot read or write any articles on this board.';
$lang->about_secret = 'Users will be able to write secret articles or comments.';
$lang->about_admin_mail = 'A mail will be sent when an article or comment is submitted. Mails can be sent to mutiple mail addresses if connecting addresses with commas(,).';
$lang->about_consultation = 'Members who are not managers will only see their own posts.<br>When this feature is enabled, non-members cannot read or write any posts on this board.';
$lang->about_secret = 'Users will be able to write secret posts or comments.';
$lang->about_admin_mail = 'A mail will be sent when a post or comment is submitted. Mails can be sent to mutiple mail addresses if connecting addresses with commas(,).';
$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 article.';
$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 document every time it is updated.';
$lang->skip_bottom_list_for_olddoc = 'Do not calculate the bottom list exactly when viewing an old article.';
$lang->about_update_log = 'Store a log of every version of a post every time it is updated.';
$lang->skip_bottom_list_for_olddoc = 'Do not calculate the bottom list exactly when viewing an old post.';
$lang->skip_bottom_list_for_robot = 'Do not calculate the bottom list exactly when a robot is visiting.';
$lang->msg_not_enough_point = 'Your point is not enough to write an article in this board.';
$lang->msg_not_enough_point = 'Your point is not enough to write a post in this board.';
$lang->write_comment = 'Write a comment';
$lang->msg_not_allow_comment = 'This article is not allowed to write comment.';
$lang->msg_not_allow_comment = 'This post is not allowed to write comment.';
$lang->no_board_instance = 'There is no board created.';
$lang->choose_board_instance = 'Please choose one or more board instance.';
$lang->comment_status = 'Comments Allowed';
@ -62,33 +63,41 @@ $lang->protect_comment = 'Protect Comment';
$lang->protect_admin_content = 'Protect Admin Content';
$lang->protect_regdate = 'Update/Delete Time Limit';
$lang->filter_specialchars = 'Block Abuse of Unicode Symbols';
$lang->document_length_limit = 'Limit Document Size';
$lang->comment_length_limit = 'Limit Comment Size';
$lang->document_length_limit = 'Limit Post Length';
$lang->comment_length_limit = 'Limit Comment Length';
$lang->inline_data_url_limit = 'Limit Data URLs';
$lang->about_document_length_limit = 'Restrict documents that are too large. This limit may be triggered by pasting content that contains a lot of unnecessary markup.<br>This setting has no effect on the administrator and board managers.';
$lang->about_document_length_limit = 'Restrict posts that are too large. This limit may be triggered by pasting content that contains a lot of unnecessary markup.<br>This setting has no effect on the administrator and board managers.';
$lang->about_comment_length_limit = 'Restrict comments that are too large.<br>This setting has no effect on the administrator and board managers.';
$lang->about_inline_data_url_limit = 'Restrict data: URLs that can be used to evade file size limits or cause processing issues.<br>This setting also applies to the administrator and board managers.';
$lang->update_order_on_comment = 'Update Document on New Comment';
$lang->about_update_order_on_comment = 'When a new comment is posted, update the update timestamp of the parent document. This is needed for forums.';
$lang->update_order_on_comment = 'Update Post on New Comment';
$lang->about_update_order_on_comment = 'When a new comment is posted, update the update timestamp of the parent post. This is needed for forums.';
$lang->about_filter_specialchars = 'Prevent use of excessive Unicode accents, RLO characters, and other symbols that hinder readability.';
$lang->document_force_to_move = 'Delete to Trash';
$lang->about_document_force_to_move = 'When a document is deleted, move to Trash instead of deleting it permamently.';
$lang->about_protect_regdate = 'Prevent updating or deleting a document or comment after a certain amount of time has passed. (Unit: day)';
$lang->about_protect_content = 'Prevent updating a document if there are comments on it.';
$lang->about_protect_admin_content = 'Prevent updating or deleting a document 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 document with comments on it.';
$lang->msg_protect_update_content = 'You cannot update a document with comments on it.';
$lang->msg_admin_document_no_modify = 'You cannot edit the administrator\'s document.';
$lang->about_protect_regdate = 'Prevent updating or deleting a post or comment after a certain amount of time has passed. (Unit: day)';
$lang->about_protect_content = 'Prevent updating a post if there are comments on it.';
$lang->about_protect_admin_content = 'Prevent updating or deleting a post or comment written by the administrator, even by a user who is permitted to manage the board.';
$lang->msg_protect_delete_content = 'You cannot delete a post with comments on it.';
$lang->msg_protect_update_content = 'You cannot update a post with comments on it.';
$lang->msg_admin_document_no_modify = 'You cannot edit the administrator\'s post.';
$lang->msg_admin_comment_no_modify = 'You cannot edit the administrator\'s comment.';
$lang->msg_board_delete_protect_comment = 'You cannot delete a comment when there are replies.';
$lang->msg_board_update_protect_comment = 'You cannot update a comment when there are replies.';
$lang->msg_protect_regdate_document = 'You cannot update or delete a document 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_dont_have_update_log = 'This document has no update log.';
$lang->msg_dont_have_update_log = 'This post has no update log.';
$lang->msg_content_too_long = 'The content is too long.';
$lang->msg_data_url_restricted = 'The content has been restricted due to excessively large data URLs (such as inline images).';
$lang->original_letter = 'Original';
$lang->msg_warning_update_log = '<span class="x_label x_label-important">Warning!</span> This can massively increase the size of your database.';
$lang->reason_update = 'Reason for the update';
$lang->msg_no_update_id = 'The update ID field is mandatory.';
$lang->msg_no_update_log = 'There is no log for updates.';
$lang->cmd_modify_by_update_log = 'Modify this post with this log';
$lang->msg_admin_update_log = 'This post has been edited by the administrator. Please refer to the administrator.';
$lang->msg_update_log_revert = 'Are you sure to revert the post to this version?';
$lang->write_admin = 'Written by the administrator';
$lang->revert_reason_update = 'Revert to this version';
$lang->document_force_to_move = 'Delete to Recycle Bin';
$lang->about_document_force_to_move = 'When a post is deleted, depositing it in Recycle Bin instead of deleting it permamently.';
$lang->comment_delete_message = 'Leave Placeholder for Deleted Comment';
$lang->about_comment_delete_message = 'When a comment is deleted, leave a placeholder saying that it has been deleted.';
$lang->cmd_only_p_comment = 'Only if there are replies';
@ -96,10 +105,13 @@ $lang->cmd_all_comment_message = 'Always';
$lang->cmd_do_not_message = 'Never';
$lang->delete_placeholder = 'Delete Placeholder';
$lang->msg_document_notify_mail = '[%s] The new post : %s';
$lang->cmd_document_vote_user = 'Upvoted by';
$lang->cmd_comment_vote_user = 'Upvoted by';
$lang->msg_not_target = 'You can only see the referrers\' lists for posts and comments.';
$lang->cmd_board_combined_board = 'Combined Board';
$lang->about_board_combined_board = 'You can use this board to view documents from other boards. Press the Ctrl key and click to select multiple boards.<br /><span style="color:red">Warning: permissions for the current board will apply to all affected documents and comments.</span>';
$lang->about_board_combined_board = 'You can use this board to view posts from other boards. Press the Ctrl key and click to select multiple boards.<br /><span style="color:red">Warning: permissions for the current board will apply to all affected posts and comments.</span>';
$lang->cmd_board_include_modules = 'Include Boards';
$lang->cmd_board_include_modules_none = '(None)';
$lang->cmd_board_include_days = 'Include Duration';
$lang->about_board_include_days = 'Only combine recent documents. If this value is set to 0, all documents from selected boards will be combined.<br />Durations shorter than 1 day can be set as fractions of a day, e.g. 0.25 days = 6 hours.';
$lang->about_board_include_days = 'Only combine recent posts. If this value is set to 0, all posts from selected boards will be combined.<br />Durations shorter than 1 day can be set as fractions of a day, e.g. 0.25 days = 6 hours.';
$lang->cmd_board_include_notice = 'Include Notices';

View file

@ -22,8 +22,10 @@
{@ $_extra_vars = $oDocument->getExtraVars(); }
<dl class="xv">
<!--@foreach($_extra_vars as $key => $val)-->
<dt>{$val->name}</dt>
<dd>{$val->getValueHTML()}</dd>
<!--@if($val->hasValue())-->
<dt>{$val->name}</dt>
<dd>{$val->getValueHTML()}</dd>
<!--@end-->
<!--@end-->
</dl>
<!--@end-->

View file

@ -22,7 +22,7 @@
<!-- Extra Output -->
<div class="exOut" cond="$oDocument->isExtraVarsExists() && $oDocument->isAccessible()">
<table border="1" cellspacing="0" summary="Extra Form Output">
<tr loop="$oDocument->getExtraVars() => $key,$val">
<tr loop="$oDocument->getExtraVars() => $key,$val" cond="$val->hasValue()">
<th scope="row">{$val->name}</th>
<td>{$val->getValueHTML()}&nbsp;</td>
</tr>

View file

@ -26,7 +26,7 @@
<!-- Extra Output -->
<div class="exOut" cond="$oDocument->isExtraVarsExists() && $oDocument->isAccessible()">
<table border="1" cellspacing="0" summary="Extra Form Output">
<tr loop="$oDocument->getExtraVars() => $key,$val">
<tr loop="$oDocument->getExtraVars() => $key,$val" cond="$val->hasValue()">
<th scope="row">{$val->name}</th>
<td>{$val->getValueHTML()}&nbsp;</td>
</tr>

View file

@ -19,8 +19,13 @@
<div class="x_controls">
<select name="domain_srl" id="domain_srl">
<option value="-1" selected="selected"|cond="!isset($module_info->domain_srl) || $module_info->domain_srl == -1">{$lang->cmd_any_domain}</option>
{@ $domain_srl_list = []}
<!--@foreach(ModuleModel::getAllDomains(100)->data as $domain)-->
<option value="{$domain->domain_srl}" selected="selected"|cond="$domain->domain_srl == $module_info->domain_srl">{$domain->domain}</option>
{@ $domain_srl_list[] = $domain->domain_srl}
<!--@endif-->
<!--@if(isset($module_info->domain_srl) && $module_info->domain_srl > -1 && !in_array($module_info->domain_srl, $domain_srl_list))-->
<option value="-1" selected="selected">{$lang->deleted_domain}</option>
<!--@endif-->
</select>
<span class="baseurl">{\RX_BASEURL}<!--@if(!config('url.rewrite'))-->index.php?mid=<!--@endif--></span>

View file

@ -30,7 +30,14 @@
</block>
<block cond="$val->module_category_srl">{$module_category[$val->module_category_srl]->title}</block>
</td>
<td class="domain_prefix"><span class="domain">{$val->domain ?? ''}</span>{\RX_BASEURL}</td>
<td class="domain_prefix">
{@
if (isset($val->domain_srl) && $val->domain_srl > -1 && !isset($val->domain)):
$val->domain = lang('deleted_domain');
endif;
}
<span class="domain">{$val->domain ?? ''}</span>{\RX_BASEURL}
</td>
<td>{$val->mid}</td>
<td><a href="{getSiteUrl($val->domain,'','mid',$val->mid)}" target="_blank">{$val->browser_title}</a></td>
<td>{zdate($val->regdate,"Y-m-d")}</td>

View file

@ -839,7 +839,10 @@ class CommentController extends Comment
}
}
$this->sendEmailToAdminAfterInsertComment($obj);
if (config('mail.default_from'))
{
$this->sendEmailToAdminAfterInsertComment($obj);
}
$output->add('comment_srl', $obj->comment_srl);
@ -890,10 +893,13 @@ class CommentController extends Comment
Author: " . $member_info->nick_name . "
<br />Author e-mail: " . $member_info->email_address . "
<br />From : <a href=\"" . $url_comment . "\">" . $url_comment . "</a>
<br />
<br />Comment:
<br />\"" . $obj->content . "\"
<br />
<br />Document:
<br />\"" . $oDocument->getContentText(). "\"
<br />\"" . $oDocument->getTitleText(). "\"
<br />\"" . $oDocument->getContentPlainText(). "\"
<br />
<br />
Approve it: <a href=\"" . $url_approve . "\">" . $url_approve . "</a>
@ -908,10 +914,13 @@ class CommentController extends Comment
Author: " . $member_info->nick_name . "
<br />Author e-mail: " . $member_info->email_address . "
<br />From : <a href=\"" . $url_comment . "\">" . $url_comment . "</a>
<br />
<br />Comment:
<br />\"" . $obj->content . "\"
<br />
<br />Document:
<br />\"" . $oDocument->getContentText(). "\"
<br />\"" . $oDocument->getTitleText(). "\"
<br />\"" . $oDocument->getContentPlainText(). "\"
";
}
@ -919,17 +928,11 @@ class CommentController extends Comment
$oMail = new \Rhymix\Framework\Mail();
$oMail->setSubject($mail_title);
$oMail->setBody($mail_content);
$oMail->setFrom(config('mail.default_from') ?: $member_info->email_address, $member_info->nick_name);
if($member_info->email_address)
{
$oMail->setReplyTo($member_info->email_address);
}
foreach (array_map('trim', explode(',', $module_info->admin_mail)) as $email_address)
{
$oMail->addTo($email_address);
}
$oMail->send();
// send email to all admins - STOP
}
$comment_srl_list = array(0 => $obj->comment_srl);
@ -1711,6 +1714,12 @@ class CommentController extends Comment
$output->add('blamed_count', $trigger_obj->after_point);
}
// Prevent session data getting too large
if (count($_SESSION['voted_comment']) > 200)
{
$_SESSION['voted_comment'] = array_slice($_SESSION['voted_comment'], 100, null, true);
}
return $output;
}
@ -1870,6 +1879,12 @@ class CommentController extends Comment
// leave into the session information
$_SESSION['declared_comment'][$comment_srl] = TRUE;
// Prevent session data getting too large
if (count($_SESSION['declared_comment']) > 200)
{
$_SESSION['declared_comment'] = array_slice($_SESSION['declared_comment'], 100, null, true);
}
$this->setMessage('success_declared');
}

View file

@ -241,6 +241,10 @@ class CommentItem extends BaseObject
{
$_SESSION['accessible'][$this->comment_srl] = $this->get('last_update');
}
if(is_array($_SESSION['accessible']) && count($_SESSION['accessible']) > 200)
{
$_SESSION['accessible'] = array_slice($_SESSION['accessible'], 100, null, true);
}
}
function isEditable()
@ -673,7 +677,7 @@ class CommentItem extends BaseObject
return;
}
$file_list = FileModel::getFiles($this->comment_srl, array(), 'file_srl', TRUE);
$file_list = FileModel::getFiles($this->comment_srl, array(), 'file_srl', true, 'com', true);
return $file_list;
}

View file

@ -737,7 +737,7 @@ class CommentModel extends Comment
// generate a list
$list[$comment_srl] = $source_list[$i];
if($parent_srl)
if($parent_srl && isset($list[$parent_srl]))
{
$list[$parent_srl]->child[] = &$list[$comment_srl];
}

View file

@ -2,14 +2,14 @@
$lang->cmd_comment_do = 'I want to';
$lang->comment_list = 'Comments List';
$lang->cmd_toggle_checked_comment = 'Invert Selection';
$lang->cmd_delete_checked_comment = 'Delete selected item';
$lang->cmd_delete_checked_comment = 'Delete Selected Item';
$lang->trash = 'Recycle Bin';
$lang->cmd_trash = 'Move to Recycle Bin';
$lang->comment_count = 'Number of Comments per Page';
$lang->comment_page_count = 'Number of Pages';
$lang->comment_default_page = 'Default Page';
$lang->comment_default_page_first = 'First page';
$lang->comment_default_page_last = 'Last page';
$lang->comment_default_page_first = 'First Page';
$lang->comment_default_page_last = 'Last Page';
$lang->about_comment_count = 'Set the number of comments to show on each page.';
$lang->about_comment_page_count = 'Set the number of pagination links to show at the bottom.';
$lang->max_thread_depth = 'Maximum Thread Depth';
@ -29,14 +29,14 @@ $lang->search_target_list['last_update'] = 'Last update';
$lang->search_target_list['ipaddress'] = 'IP Address';
$lang->search_target_list['is_secret'] = 'Status';
$lang->no_text_comment = 'No text in this comment.';
$lang->no_text_document = 'No text in this document.';
$lang->no_text_document = 'No text in this post.';
$lang->secret_name_list['Y'] = 'Secret';
$lang->secret_name_list['N'] = 'Public';
$lang->published_name_list[0] = 'Waiting';
$lang->published_name_list[1] = 'Published';
$lang->published_name_list[2] = 'Secret';
$lang->published_name_list[3] = 'Embargo';
$lang->published_name_list[4] = 'Trash';
$lang->published_name_list[4] = 'Recycle Bin';
$lang->published_name_list[5] = 'Blocked';
$lang->published_name_list[6] = 'Blocked';
$lang->published_name_list[7] = 'Deleted';
@ -47,13 +47,15 @@ $lang->published_name_list['N'] = 'Unpublished';
$lang->comment_manager = 'Manage Selected Comment';
$lang->selected_comment = 'Selected Comment';
$lang->cmd_comment_validation = 'Use comment validation';
$lang->about_comment_validation = 'If you want to use comment validation before displaying on your module frontend select USE, otherwise select NOT USE.';
$lang->published = 'Publish status';
$lang->about_comment_validation = 'If you want to use comment validation before displaying on your module frontend, select USE; otherwise, select NOT USE.';
$lang->published = 'Publish Status';
$lang->cmd_publish = 'Publish';
$lang->cmd_unpublish = 'Unpublish';
$lang->select_module = 'Select Module';
$lang->page = 'Page';
$lang->msg_not_selected_comment = 'There are no selected comment.';
$lang->msg_not_selected_comment = 'There are no selected comments.';
$lang->msg_admin_comment_no_delete = 'You cannot delete the superadmin\'s comments.';
$lang->msg_admin_c_comment_no_delete = 'You cannot delete this comment due to the supperadmin reply.';
$lang->improper_comment_declare = 'Report an improper comment';
$lang->declaring_user = 'Reporter';
$lang->improper_comment_declare_reason = 'Reason';
@ -71,4 +73,6 @@ $lang->msg_admin_censored_comment = 'This comment has been hidden by an administ
$lang->msg_deleted_comment = 'This comment has been deleted.';
$lang->msg_admin_deleted_comment = 'This comment has been deleted by an administrator.';
$lang->msg_no_text_comment = 'This comment contains no text.';
$lang->msg_comment_notify_mail = "[%s] A new comment was posted on document: \" %s \"";
$lang->msg_comment_notify_mail = "[%s] A new comment on the post: \" %s \"";
$lang->msg_admin_comment_no_move_to_trash = 'You have no permission to move the superadmin\'s comments to the trash bin.';
$lang->msg_module_srl_not_exists = 'Module serial number not found.';

View file

@ -38,7 +38,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<tr>
<th scope="col">{$lang->comment}</th>
<th scope="col" class="nowr">{$lang->writer}</th>
<th scope="col" class="nowr rx_detail_marks">{$lang->cmd_vote}(+/-)</th>
<th scope="col" class="nowr rx_detail_marks">{$lang->cmd_vote} / {$lang->cmd_vote_down}</th>
<th scope="col" class="nowr">{$lang->date}</th>
<th scope="col" class="nowr rx_detail_marks">{$lang->ipaddress}</th>
<th scope="col" class="nowr rx_detail_marks">{$lang->status}</th>

View file

@ -290,8 +290,9 @@ class CommunicationView extends communication
$option->editor_skin = $this->config->editor_skin;
$option->sel_editor_colorset = $this->config->editor_colorset;
$option->editor_focus = Context::get('source_message') ? 'Y' : 'N';
if(Context::get('m'))
if(Context::get('m') || stripos($_SERVER['HTTP_USER_AGENT'] ?? '', 'mobile') !== false)
{
$option->editor_toolbar = 'simple';
$option->editor_toolbar_hide = 'Y';
}
if ($option->allow_fileupload)

View file

@ -50,3 +50,7 @@ $lang->enable_communication_friend = 'Friend Enable';
$lang->enable_communication_message = 'Message Enable';
$lang->enable_attachment = 'Allow Attachment';
$lang->attachment_size_limit = 'Attachment Size Limit';
$lang->warning = 'Caution!';
$lang->msg_allow_message_friend = 'You can only receive direct messages from your friends.';
$lang->msg_allow_meesage_Block = 'Your direct message box is turned off.';
$lang->msg_allow_message_please = 'You should allow direct messages from everyone in order to receive the replies for this message.';

View file

@ -49,6 +49,7 @@
<action name="procDocumentAdminInsertExtraVar" type="controller" permission="manager:config:*" check_var="module_srl" ruleset="insertExtraVar" />
<action name="procDocumentAdminDeleteExtraVar" type="controller" permission="manager:config:*" check_var="module_srl" />
<action name="procDocumentAdminMoveExtraVar" type="controller" permission="manager:config:*" check_var="module_srl" />
<action name="procDocumentAdminRecalculateCategoryCounts" type="controller" />
</actions>
<eventHandlers>
<eventHandler after="module.deleteModule" class="controller" method="triggerDeleteModuleDocuments" />

View file

@ -731,6 +731,38 @@ class DocumentAdminController extends Document
$output = $oDocumentController->deleteDocument($oDocument->get('document_srl'), true, true, $oDocument);
return $output;
}
/**
* Recalculate category document counts
*/
public function procDocumentAdminRecalculateCategoryCounts()
{
// Get the document count for each category.
$output = executeQueryArray('document.getCategoryDocumentCounts', []);
$module_srl_list = [];
// Update the document count of each category.
$oDB = DB::getInstance();
$oDB->beginTransaction();
$oDB->query('UPDATE document_categories SET document_count = 0');
$stmt = $oDB->prepare('UPDATE document_categories SET document_count = ? WHERE category_srl = ?');
foreach ($output->data ?: [] as $row)
{
$module_srl_list[$row->module_srl] = true;
$stmt->execute([$row->count, $row->category_srl]);
}
$oDB->commit();
// Refresh category cache files for affected modules.
$oDocumentController = DocumentController::getInstance();
foreach ($module_srl_list as $module_srl => $unused)
{
$oDocumentController->makeCategoryFile($module_srl);
}
$this->setError(-1);
$this->setMessage('success_updated');
}
}
/* End of file document.admin.controller.php */
/* Location: ./modules/document/document.admin.controller.php */

View file

@ -699,7 +699,7 @@ class DocumentController extends Document
unset($obj->user_id);
}
$obj->uploaded_count = FileModel::getFilesCount($obj->document_srl);
$obj->uploaded_count = FileModel::getFilesCount($obj->document_srl, 'doc');
// Call a trigger (before)
$output = ModuleHandler::triggerCall('document.insertDocument', 'before', $obj);
@ -996,7 +996,7 @@ class DocumentController extends Document
if(($obj->title_color ?? 'N') === 'N') $obj->title_color = 'N';
if(($obj->notify_message ?? 'N') !== 'Y') $obj->notify_message = 'N';
if(($obj->allow_trackback ?? 'N') !== 'Y') $obj->allow_trackback = 'N';
$obj->uploaded_count = FileModel::getFilesCount($obj->document_srl);
$obj->uploaded_count = FileModel::getFilesCount($obj->document_srl, 'doc');
// Call a trigger (before)
$output = ModuleHandler::triggerCall('document.updateDocument', 'before', $obj);
@ -1274,7 +1274,7 @@ class DocumentController extends Document
{
// Check if deletion is allowed
$ev_output = $extra_item->validate(null);
if (!$ev_output->toBool())
if ($ev_output && !$ev_output->toBool())
{
$oDB->rollback();
return $ev_output;
@ -1724,6 +1724,12 @@ class DocumentController extends Document
$_SESSION['readed_document'][$document_srl] = true;
}
// Prevent session data getting too large
if (is_array($_SESSION['readed_document']) && count($_SESSION['readed_document']) > 1000)
{
$_SESSION['readed_document'] = array_slice($_SESSION['readed_document'], 500, null, true);
}
return TRUE;
}
@ -2111,6 +2117,12 @@ class DocumentController extends Document
$output->add('blamed_count', $trigger_obj->after_point);
}
// Prevent session data getting too large
if (count($_SESSION['voted_document']) > 200)
{
$_SESSION['voted_document'] = array_slice($_SESSION['voted_document'], 100, null, true);
}
return $output;
}
@ -2270,6 +2282,12 @@ class DocumentController extends Document
// Leave in the session information
$_SESSION['declared_document'][$document_srl] = true;
// Prevent session data getting too large
if (count($_SESSION['declared_document']) > 200)
{
$_SESSION['declared_document'] = array_slice($_SESSION['declared_document'], 100, null, true);
}
$this->setMessage('success_declared');
}
@ -3757,7 +3775,7 @@ Content;
$args = new stdClass;
$args->document_srl = $document_srl;
$args->uploaded_count = FileModel::getFilesCount($document_srl);
$args->uploaded_count = FileModel::getFilesCount($document_srl, 'doc');
executeQuery('document.updateUploadedCount', $args);
}
}

View file

@ -285,6 +285,10 @@ class DocumentItem extends BaseObject
{
$_SESSION['accessible'][$this->document_srl] = $this->get('last_update');
}
if(is_array($_SESSION['accessible']) && count($_SESSION['accessible']) > 200)
{
$_SESSION['accessible'] = array_slice($_SESSION['accessible'], 100, null, true);
}
}
function allowComment()
@ -1456,7 +1460,7 @@ class DocumentItem extends BaseObject
if(!isset($this->uploadedFiles[$sortIndex]))
{
$this->uploadedFiles[$sortIndex] = FileModel::getFiles($this->document_srl, array(), $sortIndex, true);
$this->uploadedFiles[$sortIndex] = FileModel::getFiles($this->document_srl, array(), $sortIndex, true, 'doc', true);
}
return $this->uploadedFiles[$sortIndex];

View file

@ -1438,7 +1438,7 @@ class DocumentModel extends Document
}
// add subcategories
if(isset($args->category_srl) && $args->category_srl)
if(isset($args->category_srl) && $args->category_srl && !is_array($args->category_srl))
{
$category_list = self::getCategoryList($args->module_srl);
if(isset($category_list[$args->category_srl]))

View file

@ -105,6 +105,7 @@ $lang->select_category = 'Select a category.';
$lang->category_description = 'Category Description';
$lang->no_title_document = 'No title in this document.';
$lang->send_default_message = 'Send the default message';
$lang->msg_admin_document_no_move_to_trash = 'You are not allowed to move the superadmin\'s article to the trash bin.';
$lang->default_message_format = '%1$s the document by manager.';
$lang->default_message_verbs['move'] = 'moved';
$lang->default_message_verbs['copy'] = 'copied';
@ -134,3 +135,6 @@ $lang->allow_declare_from_same_ip = 'Allow reporting from same IP';
$lang->allow_declare_cancel = 'Allow report cancellation';
$lang->cmd_search_division = 'Search division';
$lang->about_search_division = 'Divide search results into sections in order to reduce time and server load. Setting this value to 0 will disable divisions entirely.<br />Disabling divisions or using large values may cause serious problems such as timeouts or server overload. Values between 5000 and 10000 are recommended.';
$lang->cmd_recalculate_category_counts = 'Recalculate per-category document counts';
$lang->about_recalculate_category_counts = 'If per-category document counts are displayed incorrectly after batch move or deletion, click the button above to refresh the statistics.<br />This may take a long time if you have a large number of posts.';
$lang->prevent_redeclare = 'Prevent the same user from reporting this post again.';

View file

@ -126,4 +126,6 @@ $lang->allow_declare_from_same_ip = '동일 IP 신고 허용';
$lang->allow_declare_cancel = '신고 취소 허용';
$lang->cmd_search_division = '검색 결과 분할';
$lang->about_search_division = '검색 소요시간과 서버 부하를 줄이기 위해 일정 갯수만큼 끊어서 검색합니다. 0으로 설정할 경우 분할하지 않습니다.<br />분할하지 않거나 지나치게 많은 게시물을 한 번에 검색하려고 하면 타임아웃, 서버 다운 등 심각한 부작용이 발생할 수 있으므로 5000~10000 내외를 권장합니다.';
$lang->cmd_recalculate_category_counts = '분류별 문서 수 다시 계산';
$lang->about_recalculate_category_counts = '게시물 일괄 이동 등으로 각 분류별 문서 수가 정확하게 표시되지 않는 경우, 위의 버튼을 클릭하여 갱신할 수 있습니다.<br />문서가 많은 사이트라면 오랜 시간이 걸릴 수 있으니 주의하시기 바랍니다.';
$lang->prevent_redeclare = '같은 사용자가 이 게시물을 다시 신고하는 것을 방지합니다.';

View file

@ -0,0 +1,17 @@
<query id="getCategoryDocumentCounts" action="select">
<tables>
<table name="documents" />
</tables>
<columns>
<column name="module_srl" />
<column name="category_srl" />
<column name="count(*)" alias="count" />
</columns>
<conditions>
<condition operation="notequal" column="category_srl" default="0" />
</conditions>
<groups>
<group column="module_srl" />
<group column="category_srl" />
</groups>
</query>

View file

@ -6,6 +6,7 @@
<input type="hidden" name="type" value="" />
<div class="x_modal-header">
<h1>{$lang->cmd_manage_document}</h1>
<a class="close_window" href="javascript:window.close()">&times;</a>
</div>
<div class="x_modal-body x_form-horizontal" style="max-height:none">
<!--@if(count($document_list)==0)-->
@ -75,4 +76,4 @@ jQuery(function($){
doGetCategoryFromModule({$module_srl});
<!--@end-->
});
</script>
</script>

View file

@ -34,7 +34,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<th scope="col" class="title">{$lang->title}</th>
<th scope="col" class="nowr">{$lang->writer}</th>
<th scope="col" class="nowr">{$lang->readed_count}</th>
<th scope="col" class="nowr">{$lang->cmd_vote}(+/-)</th>
<th scope="col" class="nowr">{$lang->cmd_vote} / {$lang->cmd_vote_down}</th>
<th scope="col" class="nowr"><a href="{getUrl('sort_index', 'declared_count')}">{$lang->declared_count} <block cond="$sort_index == 'declared_count'"></block></a></th>
<th scope="col" class="nowr"><a href="{getUrl('sort_index', 'regdate')}">{$lang->original_date} <block cond="$sort_index == 'regdate'"></block></a></th>
<th scope="col" class="nowr"><a href="{getUrl('sort_index', 'declared_latest')}">{$lang->latest_declared_date} <block cond="$sort_index == 'declared_latest'"></block></a></th>

View file

@ -48,6 +48,13 @@
<p class="x_help-block">{$lang->about_search_division}</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->cmd_recalculate_category_counts}</label>
<div class="x_controls">
<p><button type="button" class="recalculate_category_counts">{$lang->cmd_recalculate_category_counts}</button></p>
<p class="x_help-block">{$lang->about_recalculate_category_counts}</p>
</div>
</div>
<div class="btnArea x_clearfix">
<span class="x_pull-right" style="margin-left:10px;"><input class="btn" type="button" value="{$lang->cmd_delete_all_thumbnail}" onclick="doDeleteAllThumbnail()"/></span>
<span class="x_pull-right"><input class="x_btn x_btn-primary" type="submit" value="{$lang->cmd_save}" /></span>

View file

@ -1,4 +1,5 @@
<load target="js/document_admin.js" />
<load target="js/document_extra_keys.js" />
<!--%import("filter/insert_extra_var.xml")-->
<!--%import("filter/delete_extra_var.xml")-->
@ -49,7 +50,7 @@
<label class="x_inline" for="is_required_n"><input type="radio" name="is_required" id="is_required_n" value="N" checked="checked"|cond="$selected_var->is_required != 'Y'" /> {$lang->not}</label>
</div>
</div>
<div class="x_control-group">
<div class="x_control-group" data-visible-types="select,radio,checkbox">
<label class="x_control-label">{$lang->extra_vars_is_strict}</label>
<div class="x_controls">
<label class="x_inline" for="is_strict_y"><input type="radio" name="is_strict" id="is_strict_y" value="Y" checked="checked"|cond="$selected_var->is_strict == 'Y'" /> {$lang->yes}</label>
@ -57,14 +58,14 @@
<p class="x_help-block">{$lang->about_extra_vars_is_strict}</p>
</div>
</div>
<div class="x_control-group">
<div class="x_control-group" data-invisible-types="file">
<label class="x_control-label" for="default">{$lang->default_value}</label>
<div class="x_controls">
<input type="text" name="default" id="default" value="{$selected_var->default}" />
<p class="x_help-block">{$lang->about_extra_vars_default_value}</p>
</div>
</div>
<div class="x_control-group">
<div class="x_control-group" data-visible-types="select,radio,checkbox">
<label class="x_control-label" for="default">{$lang->extra_vars_options}</label>
<div class="x_controls">
<textarea type="text" name="options" id="options">{$selected_var ? implode("\n", $selected_var->getOptions()) : ''}</textarea>

View file

@ -21,7 +21,7 @@ function doManageDocument(type) {
/* 선택된 글의 삭제 또는 이동 후 */
function completeManageDocument(ret_obj) {
if(opener) {
if(opener) {
opener.window.location.href = opener.window.current_url.setQuery('document_srl', '');
}
alert(ret_obj['message']);
@ -106,7 +106,7 @@ function getDocumentList() {
var documentListTable = jQuery('#documentListTable');
var cartList = [];
documentListTable.find(':checkbox[name=cart]').each(function(){
if(this.checked) cartList.push(this.value);
if(this.checked) cartList.push(this.value);
});
var params = new Array();
@ -174,12 +174,16 @@ function completeGetModuleList(ret_obj, response_tags)
}
jQuery(document).ready(function($){
$('#module_list').bind('change', function(e){
$('#module_list').on('change', function(e){
makeMidList($('#module_list').val());
});
$('#mid_list').bind('change', function(e){
$('#mid_list').on('change', function(e){
doGetCategoryFromModule($('#mid_list').val());
});
$('.recalculate_category_counts').on('click', function(e) {
exec_json('document.procDocumentAdminRecalculateCategoryCounts', { });
e.preventDefault();
});
});
function makeMidList(moduleName)

View file

@ -156,7 +156,7 @@ function clearValue(){
// clear value
$w.find('input[type="text"], textarea').val('');
$w.find('.x_inline.checked').removeClass('checked');
$w.find('input[type="checkbox"]').removeAttr('checked');
$w.find('input[type="checkbox"]').prop('checked', false);
$w.find('.lang_code').trigger('reload-multilingual');
$w.find('.color-indicator').trigger('keyup');
$w.find('.rx-spectrum').trigger('keyup');
@ -204,14 +204,14 @@ function modifyNode(node,e){
$w.find('textarea[name="category_description"]').val(data.category_info.description).trigger('reload-multilingual');
for(var i in data.category_info.group_srls){
var group_srl = data.category_info.group_srls[i];
$w.find('input[name="group_srls[]"][value="' + group_srl + '"]').attr('checked', 'checked')
$w.find('input[name="group_srls[]"][value="' + group_srl + '"]').prop('checked', true)
.parent().addClass('checked');
}
if(data.category_info.expand == 'Y'){
$w.find('input[name="expand"]').attr('checked', 'checked');
$w.find('input[name="expand"]').prop('checked', true).parent().addClass('checked');
}
if(data.category_info.is_default == 'Y'){
$w.find('input[name="is_default"]').attr('checked', 'checked');
$w.find('input[name="is_default"]').prop('checked', true).parent().addClass('checked');
}
});

View file

@ -0,0 +1,25 @@
(function($) {
$(function() {
$('select#type').on('change', function() {
const selected_type = $(this).val();
$(this).parents('form').find('.x_control-group').each(function() {
const visible_types = $(this).data('visibleTypes');
if (visible_types) {
if (visible_types.split(',').indexOf(selected_type) >= 0) {
$(this).show();
} else {
$(this).hide();
}
}
const invisible_types = $(this).data('invisibleTypes');
if (invisible_types) {
if (invisible_types.split(',').indexOf(selected_type) >= 0) {
$(this).hide();
} else {
$(this).show();
}
}
});
}).triggerHandler('change');
});
})(jQuery);

View file

@ -111,6 +111,10 @@ class EditorAdminView extends Editor
// Get a group list to set a group
$group_list = MemberModel::getGroups(0);
foreach ($group_list ?: [] as $group)
{
$group->title = Context::replaceUserLang($group->title, true);
}
Context::set('group_list', $group_list);
// Get a mid list

View file

@ -165,6 +165,10 @@ class EditorView extends Editor
// Get a group list
$group_list = MemberModel::getGroups();
Context::set('group_list', $group_list);
foreach ($group_list ?: [] as $group)
{
$group->title = Context::replaceUserLang($group->title, true);
}
//Security
$security = new Security();

View file

@ -1,4 +1,5 @@
<?php
$lang->editor_now = 'Editor Preview with the Current Settings';
$lang->editor_component = 'Editor Component';
$lang->main_editor = 'Main Editor';
$lang->comment_editor = 'Comment Editor';
@ -58,8 +59,8 @@ $lang->component_extra_vars = 'Option Variable';
$lang->component_grant = 'Permission Setting';
$lang->content_font = 'Content Font';
$lang->content_font_size = 'Content Font Size';
$lang->about_component = 'About component';
$lang->about_component_mid = 'Editor components can select targets.(All targets will be selected when nothing is selected.)';
$lang->about_component = 'About Component';
$lang->about_component_mid = 'Editor components can select targets. (All targets will be selected when nothing is selected.)';
$lang->msg_component_is_not_founded = 'Cannot find editor component %s.';
$lang->msg_component_is_disabled = 'Editor component %s is disabled.';
$lang->msg_component_is_inserted = 'Selected component is already inserted.';
@ -78,7 +79,7 @@ $lang->enable_extra_component_grant = 'Permission to use extra components';
$lang->enable_html_grant = 'Permission to edit HTML';
$lang->enable_autosave = 'Enable Auto-Save';
$lang->editor_auto_dark_mode = 'Automatic dark mode';
$lang->allow_html = 'allow HTML';
$lang->allow_html = 'Allow HTML';
$lang->height_resizable = 'Height Resizable';
$lang->editor_height = 'Height of Editor';
$lang->about_default_editor_settings = 'Follow the default settings from the Editor module.';

View file

@ -121,6 +121,24 @@ class Value
$this->value = $value;
}
/**
* Check if this extra variable has a value.
*
* @return bool
*/
public function hasValue(): bool
{
$value = self::_getTypeValue($this->type, $this->value);
if ($value === null || $value === '' || (is_array($value) && !count($value)))
{
return false;
}
else
{
return true;
}
}
/**
* Get the raw value.
*
@ -233,9 +251,9 @@ class Value
*
* @param mixed $value
* @param mixed $old_value
* @return ?BaseObject
* @return BaseObject
*/
public function validate($value, $old_value = null): ?BaseObject
public function validate($value, $old_value = null): BaseObject
{
// Take legacy encoding into consideration.
if (is_array($value))
@ -295,7 +313,7 @@ class Value
}
}
return null;
return new BaseObject;
}
/**

View file

@ -9,6 +9,7 @@
@required(toBool($definition->is_required))
@disabled(toBool($definition->is_disabled))
@readonly(toBool($definition->is_readonly))>
<option value="">@lang('cmd_select')</option>
@foreach ($definition->getOptions() as $v)
<option value="{{ $v }}" @selected($has_value ? in_array($v, $value) : ($v === $default_value))>{{ $v }}</option>
@endforeach

View file

@ -14,11 +14,14 @@
<action name="procFileGetList" type="controller" permission="root" />
<action name="dispFileAdminList" type="view" admin_index="true" menu_name="file" menu_index="true" />
<action name="dispFileAdminEdit" type="view" menu_name="file" />
<action name="dispFileAdminUploadConfig" type="view" menu_name="file" />
<action name="dispFileAdminDownloadConfig" type="view" menu_name="file" />
<action name="dispFileAdminOtherConfig" type="view" menu_name="file" />
<action name="procFileAdminAddCart" type="controller" />
<action name="procFileAdminEditFileName" type="controller" />
<action name="procFileAdminEditImage" type="controller" />
<action name="procFileAdminDeleteChecked" type="controller" ruleset="deleteChecked" />
<action name="procFileAdminInsertUploadConfig" type="controller" ruleset="insertConfig" />
<action name="procFileAdminInsertDownloadConfig" type="controller" />

View file

@ -72,16 +72,22 @@ class FileAdminController extends File
$config->allowed_filetypes = Context::get('allowed_filetypes');
// Image settings
$config->image_autoconv['bmp2jpg'] = Context::get('image_autoconv_bmp2jpg') === 'Y' ? true : false;
$config->image_autoconv['png2jpg'] = Context::get('image_autoconv_png2jpg') === 'Y' ? true : false;
$config->image_autoconv['webp2jpg'] = Context::get('image_autoconv_webp2jpg') === 'Y' ? true : false;
$config->image_autoconv['avif2jpg'] = Context::get('image_autoconv_avif2jpg') === 'Y' ? true : false;
$config->image_autoconv['heic2jpg'] = Context::get('image_autoconv_heic2jpg') === 'Y' ? true : false;
$config->image_autoconv['gif2mp4'] = Context::get('image_autoconv_gif2mp4') === 'Y' ? true : false;
$config->image_autoconv = [];
foreach (Context::get('image_autoconv') ?: [] as $source_type => $target_type)
{
if (in_array($target_type, ['Y', 'N']))
{
$config->image_autoconv[$source_type] = tobool($target_type);
}
elseif (in_array($target_type, ['', 'jpg', 'png', 'webp']))
{
$config->image_autoconv[$source_type] = $target_type;
}
}
$config->max_image_width = intval(Context::get('max_image_width')) ?: '';
$config->max_image_height = intval(Context::get('max_image_height')) ?: '';
$config->max_image_size_action = Context::get('max_image_size_action') ?: '';
$config->max_image_size_same_format = Context::get('max_image_size_same_format') === 'Y' ? 'Y' : 'N';
$config->max_image_size_same_format = strval(Context::get('max_image_size_same_format'));
$config->max_image_size_admin = Context::get('max_image_size_admin') === 'Y' ? 'Y' : 'N';
$config->image_quality_adjustment = max(50, min(100, intval(Context::get('image_quality_adjustment'))));
$config->image_autorotate = Context::get('image_autorotate') === 'Y' ? true : false;
@ -296,6 +302,167 @@ class FileAdminController extends File
else $_SESSION['file_management'][$output->file_srl] = true;
}
}
/**
* Edit filename
*/
public function procFileAdminEditFileName()
{
$file_srl = Context::get('file_srl');
if (!$file_srl)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
$file = FileModel::getFile($file_srl);
if (!$file)
{
throw new Rhymix\Framework\Exceptions\TargetNotFound;
}
$file_name = trim(utf8_normalize_spaces(utf8_clean(Context::get('file_name'))));
$file_name = Rhymix\Framework\Filters\FilenameFilter::clean($file_name);
if ($file_name === '')
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
$output = executeQuery('file.updateFileName', [
'file_srl' => $file_srl,
'source_filename' => $file_name,
]);
if (!$output->toBool())
{
return $output;
}
$this->setMessage('success_updated');
$this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl(['module' => 'admin', 'act' => 'dispFileAdminEdit', 'file_srl' => $file_srl]));
}
/**
* Edit image
*/
public function procFileAdminEditImage()
{
$file_srl = Context::get('file_srl');
if (!$file_srl)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
$file = FileModel::getFile($file_srl);
if (!$file)
{
throw new Rhymix\Framework\Exceptions\TargetNotFound;
}
// Validate user input.
$width = intval(Context::get('new_width'));
$height = intval(Context::get('new_height'));
$format = Context::get('format');
$quality = intval(Context::get('quality'));
if ($width <= 0 || $height <= 0 || !in_array($format, ['jpg', 'png', 'webp']) || $quality <= 0 || $quality > 100)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
// Generate filenames.
$uploaded_filename = FileHandler::getRealPath($file->uploaded_filename);
$temp_filename = \RX_BASEDIR . 'files/cache/temp/' . Rhymix\Framework\Security::getRandom(32, 'hex') . '.' . $format;
$new_filename = preg_replace('/\.[a-z]+$/', '.' . $format, $file->source_filename);
$del_filename = null;
// Should this file be moved from binaries to images?
if (str_starts_with($uploaded_filename, \RX_BASEDIR . 'files/attach/binaries/'))
{
$del_filename = $uploaded_filename;
$uploaded_filename = preg_replace('!/files/attach/binaries/!', '/files/attach/images/', $uploaded_filename, 1) . '.' . $format;
}
// Resize the image using GD or ImageMagick.
$config = FileModel::getFileConfig();
$result = FileHandler::createImageFile(FileHandler::getRealPath($file->uploaded_filename), $temp_filename, $width, $height, $format, 'fill', $quality);
if (!$result && !empty($config->magick_command))
{
$command = vsprintf('%s %s -resize %dx%d -quality %d %s %s %s', [
\RX_WINDOWS ? escapeshellarg($config->magick_command) : $config->magick_command,
escapeshellarg(FileHandler::getRealPath($file->uploaded_filename)),
$width, $height, $quality,
'-auto-orient -strip',
'-limit memory 64MB -limit map 128MB -limit disk 1GB',
escapeshellarg($temp_filename),
]);
@exec($command, $output, $return_var);
$result = $return_var === 0 ? true : false;
}
// If successfully resized, replace original file and update the image size in DB.
if ($result && Rhymix\Framework\Storage::exists($temp_filename) && filesize($temp_filename) > 0)
{
$moved = Rhymix\Framework\Storage::move($temp_filename, $uploaded_filename);
if (!$moved)
{
throw new Rhymix\Framework\Exception(lang('file.msg_image_conversion_failed'));
}
if ($del_filename)
{
Rhymix\Framework\Storage::delete($del_filename);
}
clearstatcache(true, $uploaded_filename);
$filesize = filesize($uploaded_filename);
$relative_path = preg_replace('!^' . preg_quote(\RX_BASEDIR, '!') . '!', './', $uploaded_filename, 1);
$updated = executeQuery('file.updateFile', [
'file_srl' => $file_srl,
'module_srl' => $file->module_srl,
'upload_target_srl' => $file->upload_target_srl,
'source_filename' => $new_filename,
'uploaded_filename' => $relative_path,
'direct_download' => 'Y',
'mime_type' => Rhymix\Framework\MIME::getTypeByFilename($new_filename),
'original_type' => $file->original_type ?: $file->mime_type,
'is_cover' => $file->cover_image,
'file_size' => $filesize,
'width' => $width,
'height' => $height,
]);
if (!$updated->toBool())
{
return $updated;
}
if (isset($config->save_changelog) && $config->save_changelog === 'Y')
{
$changelog1 = executeQuery('file.insertFileChangelog', [
'change_type' => 'D',
'file_srl' => $file->file_srl,
'file_size' => $file->file_size,
'uploaded_filename' => $file->uploaded_filename,
]);
if (!$changelog1->toBool())
{
return $changelog1;
}
$changelog2 = executeQuery('file.insertFileChangelog', [
'change_type' => 'I',
'file_srl' => $file->file_srl,
'file_size' => $filesize,
'uploaded_filename' => $relative_path,
]);
if (!$changelog2->toBool())
{
return $changelog2;
}
}
}
else
{
throw new Rhymix\Framework\Exception(lang('file.msg_image_conversion_failed'));
}
$this->setMessage(sprintf(lang('file.msg_image_converted'), FileHandler::filesize($file->file_size), FileHandler::filesize($filesize)));
$this->setRedirectUrl(Context::get('success_return_url') ?: getNotEncodedUrl(['module' => 'admin', 'act' => 'dispFileAdminEdit', 'file_srl' => $file_srl]));
}
}
/* End of file file.admin.controller.php */
/* Location: ./modules/file/file.admin.controller.php */

View file

@ -6,20 +6,12 @@
*/
class FileAdminView extends File
{
/**
* Initialization
* @return void
*/
function init()
{
}
/**
* Display output list (for administrator)
*
* @return Object
*/
function dispFileAdminList()
public function dispFileAdminList()
{
// Options to get a list
$args = new stdClass();
@ -213,11 +205,35 @@ class FileAdminView extends File
}
/**
* Upload config screen
*
* @return Object
* File edit screen
*/
function dispFileAdminUploadConfig()
public function dispFileAdminEdit()
{
$file_srl = intval(Context::get('file_srl'));
if (!$file_srl)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
$file = FileModel::getFile($file_srl);
if (!$file)
{
throw new Rhymix\Framework\Exceptions\TargetNotFound;
}
$config = FileModel::getFileConfig();
Context::set('config', $config);
Context::set('file', $file);
Context::set('is_ffmpeg', function_exists('exec') && !empty($config->ffmpeg_command) && Rhymix\Framework\Storage::isExecutable($config->ffmpeg_command) && !empty($config->ffprobe_command) && Rhymix\Framework\Storage::isExecutable($config->ffprobe_command));
Context::set('is_magick', function_exists('exec') && !empty($config->magick_command) && Rhymix\Framework\Storage::isExecutable($config->magick_command));
$this->setTemplatePath($this->module_path . 'tpl');
$this->setTemplateFile('file_edit');
}
/**
* Upload config screen
*/
public function dispFileAdminUploadConfig()
{
$oFileModel = getModel('file');
$config = $oFileModel->getFileConfig();
@ -233,10 +249,8 @@ class FileAdminView extends File
/**
* Download config screen
*
* @return Object
*/
function dispFileAdminDownloadConfig()
public function dispFileAdminDownloadConfig()
{
$oFileModel = getModel('file');
$config = $oFileModel->getFileConfig();
@ -249,10 +263,8 @@ class FileAdminView extends File
/**
* Other config screen
*
* @return Object
*/
function dispFileAdminOtherConfig()
public function dispFileAdminOtherConfig()
{
$oFileModel = getModel('file');
$config = $oFileModel->getFileConfig();

View file

@ -29,7 +29,10 @@ class FileController extends File
$file_info = Context::get('Filedata');
// An error appears if not a normally uploaded file
if(!$file_info || !is_uploaded_file($file_info['tmp_name'])) exit();
if (!$file_info || !is_uploaded_file($file_info['tmp_name']))
{
throw new Rhymix\Framework\Exceptions\InvalidRequest();
}
// Validate editor_sequence and module_srl.
$editor_sequence = Context::get('editor_sequence');
@ -156,12 +159,17 @@ class FileController extends File
// Create the response
Context::setResponseMethod('JSON');
$this->add('file_srl', $output->get('file_srl'));
$this->add('file_size', $output->get('file_size'));
$this->add('direct_download', $output->get('direct_download'));
$this->add('source_filename', $output->get('source_filename'));
$this->add('upload_target_srl', $output->get('upload_target_srl'));
$this->add('source_filename', $output->get('source_filename'));
$this->add('thumbnail_filename', $output->get('thumbnail_filename'));
$this->add('file_size', $output->get('file_size'));
$this->add('disp_file_size', FileHandler::filesize($output->get('file_size')));
$this->add('mime_type', $output->get('mime_type'));
$this->add('original_type', $output->get('original_type'));
$this->add('width', $output->get('width'));
$this->add('height', $output->get('height'));
$this->add('duration', $output->get('duration'));
$this->add('direct_download', $output->get('direct_download'));
if ($output->get('direct_download') === 'Y')
{
$this->add('download_url', FileModel::getDirectFileUrl($output->get('uploaded_filename')));
@ -772,6 +780,10 @@ class FileController extends File
{
$_SESSION['upload_info'] = array();
}
if(count($_SESSION['upload_info']) > 200)
{
$_SESSION['upload_info'] = array_slice($_SESSION['upload_info'], 100, null, true);
}
if(!isset($_SESSION['upload_info'][$editor_sequence]))
{
$_SESSION['upload_info'][$editor_sequence] = new stdClass();
@ -821,6 +833,21 @@ class FileController extends File
return $output;
}
/**
* Update upload target type
*
* @param int|array $file_srl
* @param string $upload_target_type
* @return BaseObject
*/
public function updateTargetType($file_srl, $upload_target_type)
{
$args = new stdClass;
$args->file_srl = $file_srl;
$args->upload_target_type = $upload_target_type;
return executeQuery('file.updateFileTargetType', $args);
}
/**
* Add an attachement
*
@ -1097,13 +1124,17 @@ class FileController extends File
$output->add('file_srl', $args->file_srl);
$output->add('file_size', $args->file_size);
$output->add('sid', $args->sid);
$output->add('upload_target_srl', $upload_target_srl);
$output->add('direct_download', $args->direct_download);
$output->add('source_filename', $args->source_filename);
$output->add('upload_target_srl', $upload_target_srl);
$output->add('uploaded_filename', $args->uploaded_filename);
$output->add('thumbnail_filename', $args->thumbnail_filename);
$output->add('mime_type', $args->mime_type);
$output->add('original_type', $args->original_type);
$output->add('width', $args->width);
$output->add('height', $args->height);
$output->add('duration', $args->duration);
$output->add('sid', $args->sid);
return $output;
}
@ -1163,23 +1194,11 @@ class FileController extends File
{
$adjusted['type'] = 'mp4';
}
elseif ($config->image_autoconv['png2jpg'] && $image_info['type'] === 'png' && function_exists('imagepng'))
elseif (!empty($config->image_autoconv[$image_info['type']]))
{
$adjusted['type'] = 'jpg';
$adjusted['type'] = $config->image_autoconv[$image_info['type']];
}
elseif ($config->image_autoconv['webp2jpg'] && $image_info['type'] === 'webp' && function_exists('imagewebp'))
{
$adjusted['type'] = 'jpg';
}
elseif ($config->image_autoconv['bmp2jpg'] && $image_info['type'] === 'bmp' && function_exists('imagebmp'))
{
$adjusted['type'] = 'jpg';
}
elseif ($config->image_autoconv['avif2jpg'] && $image_info['type'] === 'avif')
{
$adjusted['type'] = 'jpg';
}
elseif ($config->image_autoconv['heic2jpg'] && $image_info['type'] === 'heic')
elseif (!empty($config->image_autoconv[$image_info['type'] . '2jpg']))
{
$adjusted['type'] = 'jpg';
}
@ -1246,7 +1265,7 @@ class FileController extends File
$adjusted['height'] = (int)$resize_height;
if (!$is_animated && $adjusted['type'] === $image_info['type'] && $config->max_image_size_same_format !== 'Y')
{
$adjusted['type'] = 'jpg';
$adjusted['type'] = $config->max_image_size_same_format ?: 'jpg';
}
}
}

View file

@ -82,7 +82,7 @@ class FileModel extends File
// Set file list
$filter_type = $_SESSION['upload_info'][$editor_sequence]->upload_target_type ?? null;
$files = self::getFiles($upload_target_srl, [], 'file_srl', false, $filter_type);
$files = self::getFiles($upload_target_srl, [], 'file_srl', false, $filter_type, true);
foreach ($files as $file_info)
{
$obj = new stdClass;
@ -93,6 +93,9 @@ class FileModel extends File
$obj->disp_file_size = FileHandler::filesize($file_info->file_size);
$obj->mime_type = $file_info->mime_type;
$obj->original_type = $file_info->original_type;
$obj->width = $file_info->width;
$obj->height = $file_info->height;
$obj->duration = $file_info->duration;
$obj->direct_download = $file_info->direct_download;
$obj->cover_image = ($file_info->cover_image === 'Y') ? true : false;
if($obj->direct_download === 'Y' && self::isDownloadable($file_info))
@ -291,15 +294,20 @@ class FileModel extends File
*
* @param int $upload_target_srl The sequence to get a number of files
* @param ?string $upload_target_type
* @param bool $include_null_target_type
* @return int Returns a number of files
*/
public static function getFilesCount($upload_target_srl, $upload_target_type = null)
public static function getFilesCount($upload_target_srl, $upload_target_type = null, $include_null_target_type = false)
{
$args = new stdClass();
$args->upload_target_srl = $upload_target_srl;
if ($upload_target_type)
{
$args->upload_target_type = $upload_target_type;
if ($include_null_target_type)
{
$args->include_null_target_type = true;
}
}
$output = executeQuery('file.getFilesCount', $args);
return (int)$output->data->count;
@ -435,9 +443,12 @@ class FileModel extends File
* @param int $upload_target_srl The sequence of target to get file list
* @param array $columnList The list of columns to get from DB
* @param string $sortIndex The column that used as sort index
* @param bool $valid_files_only
* @param ?string $upload_target_type
* @param bool $include_null_target_type
* @return array Returns array of object that contains file information. If no result returns null.
*/
public static function getFiles($upload_target_srl, $columnList = array(), $sortIndex = 'file_srl', $valid_files_only = false, $upload_target_type = null)
public static function getFiles($upload_target_srl, $columnList = array(), $sortIndex = 'file_srl', $valid_files_only = false, $upload_target_type = null, $include_null_target_type = false)
{
$args = new stdClass();
$args->upload_target_srl = $upload_target_srl;
@ -449,6 +460,10 @@ class FileModel extends File
if ($upload_target_type)
{
$args->upload_target_type = $upload_target_type;
if ($include_null_target_type)
{
$args->include_null_target_type = true;
}
}
$output = executeQueryArray('file.getFiles', $args, $columnList);
@ -458,12 +473,23 @@ class FileModel extends File
}
$fileList = array();
$nullList = array();
foreach ($output->data as $file)
{
$file->source_filename = escape($file->source_filename, false);
$file->download_url = self::getDownloadUrl($file->file_srl, $file->sid, 0, $file->source_filename);
$fileList[] = $file;
if ($file->upload_target_type === null)
{
$nullList[] = $file->file_srl;
}
}
if (count($nullList) && $upload_target_type)
{
FileController::getInstance()->updateTargetType($nullList, $upload_target_type);
}
return $fileList;
}

View file

@ -54,6 +54,7 @@ $lang->msg_not_permitted_download = 'You do not have a permission to download.';
$lang->msg_file_cart_is_null = 'Please select a file(s) to delete.';
$lang->msg_checked_file_is_deleted = '%d attachment(s) was(were) deleted.';
$lang->msg_exceeds_limit_size = 'This file exceeds the attachment limit.';
$lang->msg_not_allowed_filetype = 'This file format is not allowed to be uploaded.';
$lang->msg_exceeds_max_image_size = 'This image is too large. Images must be no larger than %dx%dpx.';
$lang->msg_exceeds_max_image_width = 'This image is too large. The maximum permitted width is %dpx.';
$lang->msg_exceeds_max_image_height = 'This image is too large. The maximum permitted height is %dpx.';
@ -90,11 +91,6 @@ $lang->use_video_default_file_config = 'Use Default Settings Of Video File';
$lang->about_use_video_default_file_config = 'Follow the video settings of image file from the File module.';
$lang->image_autoconv = 'Convert Type';
$lang->about_image_autoconv = 'Automatically convert uploaded images. This may help you handle image formats that are not widely supported or waste disk space.';
$lang->image_autoconv_bmp2jpg = 'BMP → JPG';
$lang->image_autoconv_png2jpg = 'PNG → JPG';
$lang->image_autoconv_webp2jpg = 'WebP → JPG';
$lang->image_autoconv_avif2jpg = 'AVIF → JPG';
$lang->image_autoconv_heic2jpg = 'HEIC → JPG';
$lang->max_image_size = 'Limit Image Size';
$lang->about_max_image_size = 'Limit the dimensions of uploaded images. Note that this is only indirectly related to file size.';
$lang->max_image_size_action_nothing = 'If exceeded, do nothing';
@ -102,7 +98,8 @@ $lang->max_image_size_action_block = 'If exceeded, block upload';
$lang->max_image_size_action_resize = 'If exceeded, resize automatically';
$lang->max_image_size_action_cut = 'If exceeded, cut automatically';
$lang->max_image_size_same_format_Y = 'Maintain file format';
$lang->max_image_size_same_format_N = 'Convert to JPG';
$lang->max_image_size_same_format_to_jpg = 'Convert to JPG';
$lang->max_image_size_same_format_to_webp = 'Convert to WebP';
$lang->max_image_size_admin = 'Also apply to administrator';
$lang->image_quality_adjustment = 'Image Quality';
$lang->about_image_quality_adjustment = 'adjust the quality of images that will is converted by other settings.<br />If set to more than 75% (Standard), the file size may be larger than the original.';
@ -114,6 +111,8 @@ $lang->image_autoconv_gif2mp4 = 'Convert GIF to MP4';
$lang->about_image_autoconv_gif2mp4 = 'convert animated GIF images into MP4 videos to save storage and bandwidth.<br />This requires ffmpeg settings below. Videos may not play properly in older browsers.';
$lang->max_video_size = 'Limit Video Size';
$lang->about_max_video_size = 'Limit the dimensions of uploaded videos. Note that this is only indirectly related to file size.';
$lang->max_video_duration = 'Limit Video Duration';
$lang->about_max_video_duration = 'Restrict the maximum length of videos. This is independent of the limit of filesize (e.g., MB, GB) or two-dimensional size for videos.';
$lang->video_autoconv_any2mp4 = 'Convert to MP4';
$lang->about_video_autoconv_any2mp4 = 'Convert all other types of videos to MP4 format that can be played on the web.<br />Supported original formats vary by ffmpeg version and system environment, but usually include AVI and MOV.';
$lang->video_always_reencode = 'Always Reencode';
@ -132,3 +131,8 @@ $lang->msg_cannot_use_exec = 'The exec() function is disabled on this server.';
$lang->msg_cannot_use_ffmpeg = 'In order to use this feature, PHP must be able to execute \'ffmpeg\' and \'ffprobe\' commands.';
$lang->msg_cannot_use_exif = 'In order to use this feature, PHP must be installed with the \'exif\' extension.';
$lang->msg_need_magick = 'In order to handle AVIF and HEIC formats, PHP must be able to execute the \'magick\' command from ImageMagick 7.x or higher.';
$lang->image_conversion = 'Image conversion';
$lang->image_size = 'Image size';
$lang->image_format = 'Image format';
$lang->msg_image_converted = 'The image has been converted. (%s → %s)';
$lang->msg_image_conversion_failed = 'The image conversion has failed.';

View file

@ -38,7 +38,7 @@ $lang->about_allow_indexing_format = '구글 등 검색엔진에 의한 색인
$lang->about_allow_outlink = '다른 사이트에서 파일 다운로드 링크에 직접 접근하는 것을 허용합니다.<br />본문에 바로 삽입할 수 있는 이미지 파일은 라이믹스에서 접근을 통제할 수 없으며, 이를 차단하려면 웹서버 설정이 필요합니다.';
$lang->about_allow_outlink_format = '파일 외부 링크 설정에 상관없이 허용하는 파일 확장자입니다.<br />여러 개 입력시 쉼표(,)을 이용해서 구분해 주세요. 예) doc, zip, pdf';
$lang->about_allow_outlink_site = '파일 외부 링크 설정에 상관없이 허용하는 사이트 주소입니다.<br />여러 개 입력시 줄을 바꿔서 구분해 주세요. 예) https://www.rhymix.org/';
$lang->about_allow_multimedia_direct_download = '오디오, 동영상 등의 멀티미디어 파일 링크를 본문에 삽입할 때 직접 접근이 가능한 링크를 사용합니다.<br>다운로드시 PHP를 거치지 않게 되므로 서버 부하가 줄어들지만, 권한이 없는 사람에게 링크가 노출되지 않도록 주의해야 합니다.<br>&quot;아니오&quot;를 선택하면 본문에 삽입된 동영상을 재생할 때마다 첨부파일의 다운로드 횟수가 증가됩니다.';
$lang->about_allow_multimedia_direct_download = '오디오, 동영상 등의 멀티미디어 파일 링크를 본문에 삽입할 때 직접 접근이 가능한 링크를 사용합니다.<br>다운로드시 PHP를 거치지 않게 되므로 서버 부하가 줄어들지만, 권한이 없는 사람에게 링크가 노출되지 않도록 주의해야 합니다.<br>&quot;아니오&quot;를 선택하면 본문에 삽입된 멀티미디어 파일이 자동 재생되지 않을 수 있습니다.';
$lang->about_allowed_filesize = '각 파일의 용량을 제한할 수 있습니다.<br />관리자에게는 이 게시판의 제한과 <a href="%s" target="_blank">파일 모듈</a>의 제한 중 높은 쪽이 적용됩니다.';
$lang->about_allowed_attach_size = '하나의 문서에 첨부할 수 있는 최대 용량을 제한할 수 있습니다.<br />관리자에게는 이 게시판의 제한과 <a href="%s" target="_blank">파일 모듈</a>의 제한 중 높은 쪽이 적용됩니다.';
$lang->about_allowed_filesize_global = '관리자를 포함하여 사이트 전체에 적용되는 파일 용량 제한입니다.';
@ -91,11 +91,6 @@ $lang->use_video_default_file_config = '동영상 파일 기본 설정 사용';
$lang->about_use_video_default_file_config = '파일 모듈의 동영상 파일 기본 설정을 따릅니다.';
$lang->image_autoconv = '이미지 자동 변환';
$lang->about_image_autoconv = '업로드된 이미지의 타입을 변환합니다. 다양한 환경에서 호환되지 않거나, 용량을 낭비하는 이미지를 처리할 수 있습니다.';
$lang->image_autoconv_bmp2jpg = 'BMP → JPG';
$lang->image_autoconv_png2jpg = 'PNG → JPG';
$lang->image_autoconv_webp2jpg = 'WebP → JPG';
$lang->image_autoconv_avif2jpg = 'AVIF → JPG';
$lang->image_autoconv_heic2jpg = 'HEIC → JPG';
$lang->max_image_size = '이미지 크기 제한';
$lang->about_max_image_size = '업로드된 이미지의 크기를 제한하거나 조정합니다. 파일 용량과는 직접적인 관계가 없으니 참고하세요.';
$lang->max_image_size_action_nothing = '초과시 아무 것도 하지 않음';
@ -103,7 +98,8 @@ $lang->max_image_size_action_block = '초과시 업로드 금지';
$lang->max_image_size_action_resize = '초과시 자동 크기 조정';
$lang->max_image_size_action_cut = '초과시 자르기';
$lang->max_image_size_same_format_Y = '동일한 포맷 유지';
$lang->max_image_size_same_format_N = 'JPG로 변환';
$lang->max_image_size_same_format_to_jpg = 'JPG로 변환';
$lang->max_image_size_same_format_to_webp = 'WebP로 변환';
$lang->max_image_size_admin = '관리자에게도 적용';
$lang->image_quality_adjustment = '이미지 화질';
$lang->about_image_quality_adjustment = '다른 설정에 의해 이미지가 변환될 경우 화질을 조정합니다.<br />75% (표준) 이상으로 설정시 오히려 원본보다 용량이 늘어날 수 있습니다.';
@ -135,3 +131,8 @@ $lang->msg_cannot_use_exec = '이 서버에서 exec() 함수를 사용할 수
$lang->msg_cannot_use_ffmpeg = '이 기능을 사용하려면 PHP에서 ffmpeg 및 ffprobe 명령을 실행할 수 있어야 합니다.';
$lang->msg_cannot_use_exif = '이 기능을 사용하려면 PHP exif 확장모듈이 필요합니다.';
$lang->msg_need_magick = 'AVIF, HEIC 변환을 위해서는 PHP에서 ImageMagick 7.x 이상의 magick 명령을 실행할 수 있어야 합니다.';
$lang->image_conversion = '이미지 변환';
$lang->image_size = '이미지 크기';
$lang->image_format = '이미지 포맷';
$lang->msg_image_converted = '이미지가 변환되었습니다. (%s → %s)';
$lang->msg_image_conversion_failed = '이미지 변환에 실패했습니다.';

View file

@ -4,7 +4,10 @@
</tables>
<conditions>
<condition operation="equal" column="upload_target_srl" var="upload_target_srl" filter="number" notnull="notnull" />
<condition operation="equal" column="upload_target_type" var="upload_target_type" pipe="and" />
<group pipe="and">
<condition operation="equal" column="upload_target_type" var="upload_target_type" />
<condition operation="null" column="upload_target_type" if="include_null_target_type" pipe="or" />
</group>
<condition operation="equal" column="isvalid" var="isvalid" pipe="and" />
</conditions>
<navigation>

View file

@ -7,7 +7,10 @@
</columns>
<conditions>
<condition operation="equal" column="upload_target_srl" var="upload_target_srl" filter="number" />
<condition operation="equal" column="upload_target_type" var="upload_target_type" pipe="and" />
<group pipe="and">
<condition operation="equal" column="upload_target_type" var="upload_target_type" />
<condition operation="null" column="upload_target_type" if="include_null_target_type" pipe="or" />
</group>
<condition operation="like_prefix" column="regdate" var="regDate" pipe="and" />
</conditions>
</query>

View file

@ -3,11 +3,19 @@
<table name="files" />
</tables>
<columns>
<column name="module_srl" var="module_srl" filter="number" notnull="notnull" />
<column name="upload_target_srl" var="upload_target_srl" filter="number" notnull="notnull" />
<column name="upload_target_type" var="upload_target_type" />
<column name="module_srl" var="module_srl" filter="number" notnull="notnull" />
<column name="source_filename" var="source_filename" />
<column name="uploaded_filename" var="uploaded_filename" notnull="notnull" minlength="1" maxlength="250" />
<column name="cover_image" var="is_cover" default="N" />
<column name="direct_download" var="direct_download" />
<column name="mime_type" var="mime_type" />
<column name="original_type" var="original_type" />
<column name="file_size" var="file_size" />
<column name="width" var="width" />
<column name="height" var="height" />
<column name="duration" var="duration" />
</columns>
<conditions>
<condition operation="equal" column="file_srl" var="file_srl" filter="number" notnull="notnull" />

View file

@ -0,0 +1,11 @@
<query id="updateFileName" action="update">
<tables>
<table name="files" />
</tables>
<columns>
<column name="source_filename" var="source_filename" notnull="notnull" />
</columns>
<conditions>
<condition operation="equal" column="file_srl" var="file_srl" filter="number" notnull="notnull" />
</conditions>
</query>

View file

@ -6,6 +6,6 @@
<column name="upload_target_type" var="upload_target_type" />
</columns>
<conditions>
<condition operation="equal" column="file_srl" var="file_srl" filter="number" notnull="notnull" />
<condition operation="in" column="file_srl" var="file_srl" filter="number" notnull="notnull" />
</conditions>
</query>
</query>

View file

@ -2,4 +2,23 @@
margin-top: -10px;
border-bottom: 1px solid #ccc;
background: #f5f5f5;
}
}
.image_autoconv_types {
margin-bottom: 5px;
}
.image_autoconv_types:last-of-type {
margin-bottom: 10px;
}
.image_autoconv_types .x_inline {
display: inline-block;
min-width: 40px;
}
.image_autoconv_types select {
min-width: 0 !important;
margin-left: 16px;
}
.x_help-block .preset_size {
font-size: 12px;
}

View file

@ -0,0 +1,83 @@
<include target="header.html" />
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/file/tpl/edit/1'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/file/tpl/edit/2'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<section class="section">
<h2>{$lang->file_name}</h2>
<form action="./" method="post" class="x_form-horizontal">
<input type="hidden" name="module" value="file" />
<input type="hidden" name="act" value="procFileAdminEditFileName" />
<input type="hidden" name="xe_validator_id" value="modules/file/tpl/edit/1" />
<input type="hidden" name="file_srl" value="{$file->file_srl}" />
<div class="x_control-group">
<label class="x_control-label" for="file_name">{$lang->file_name}</label>
<div class="x_controls">
<input type="text" name="file_name" id="file_name" value="{$file->source_filename}" />
</div>
</div>
<div class="x_clearfix btnArea">
<div class="x_pull-right">
<button type="submit" class="x_btn x_btn-primary">{$lang->cmd_save}</button>
</div>
</div>
</form>
</section>
<!--@if(preg_match('/\.(gif|jpe?g|png|bmp|webp|heic|avif)$/i', $file->source_filename, $matches))-->
<!--@if(!$file->width || !$file->height)-->
{@ list($file->width, $file->height) = getimagesize($file->uploaded_filename)}
<!--@endif-->
{@ $extension = strtolower($matches[1]); if ($extension === 'jpeg') $extension = 'jpg'; }
<section class="section">
<h2>{$lang->image_conversion}</h2>
<form action="./" method="post" class="x_form-horizontal">
<input type="hidden" name="module" value="file" />
<input type="hidden" name="act" value="procFileAdminEditImage" />
<input type="hidden" name="xe_validator_id" value="modules/file/tpl/edit/2" />
<input type="hidden" name="file_srl" value="{$file->file_srl}" />
<input type="hidden" name="original_width" value="{$file->width}" />
<input type="hidden" name="original_height" value="{$file->height}" />
<div class="x_control-group">
<label class="x_control-label">{$lang->image_size}</label>
<div class="x_controls">
<input type="number" name="new_width" id="new_width" value="{$file->width}" /> x
<input type="number" name="new_height" id="new_height" value="{$file->height}" />
<p class="x_help-block">
<button type="button" class="preset_size">2560</button>
<button type="button" class="preset_size">1920</button>
<button type="button" class="preset_size">1440</button>
<button type="button" class="preset_size">1280</button>
<button type="button" class="preset_size">1024</button>
</p>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="format">{$lang->image_format}</label>
<div class="x_controls">
<select name="format" id="format">
<option value="jpg" selected="selected"|cond="$extension === 'jpg'">JPG</option>
<option value="png" selected="selected"|cond="$extension === 'png'">PNG</option>
<option value="webp" selected="selected"|cond="$extension === 'webp'">WebP</option>
</select>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="quality">{$lang->image_quality}</label>
<div class="x_controls">
<input type="number" min="50" max="100" name="quality" id="quality" value="{$config->image_quality_adjustment ?? 75}" /> %
</div>
</div>
<div class="x_clearfix btnArea">
<div class="x_pull-right">
<button type="submit" class="x_btn x_btn-primary">{$lang->cmd_save}</button>
</div>
</div>
</form>
</section>
<!--@endif-->

View file

@ -31,6 +31,9 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
</block>
</a>
</th>
<th scope="col" class="nowr">
{$lang->image_size}
</th>
<th scope="col" class="nowr">
<a href="{getUrl('', 'module', 'admin', 'act', 'dispFileAdminList', 'sort_index', 'download_count', 'order_type', ($order_type == 'desc' && $sort_index == 'download_count') ? 'asc' : 'desc', 'isvalid', $isvalid ?? null)}">
{$lang->cmd_download}
@ -50,6 +53,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
</th>
<th scope="col" class="nowr">{$lang->ipaddress}</th>
<th scope="col" class="nowr">{$lang->status}</th>
<th scope="col" class="nowr">{$lang->cmd_edit}</th>
<th scope="col"><input type="checkbox" data-name="cart" title="Check All" /></th>
</tr>
</thead>
@ -66,7 +70,7 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<!--@end-->
{@ $cur_upload_target_srl = $val->upload_target_srl}
<tr>
<th colspan="8" scope="col">
<th colspan="10" scope="col">
<!--@if(!$val->upload_target_type)-->
<!--@if($val->isvalid=='Y')-->
{$lang->is_valid}
@ -99,6 +103,14 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<!--@end-->
<a href="{$val->download_url}">{escape($val->source_filename, false)}</a></td>
<td class="nowr">{FileHandler::filesize($val->file_size)}</td>
<td class="nowr">
<!--@if($val->width && $val->height)-->
{$val->width}x{$val->height}
<!--@endif-->
<!--@if($val->duration)-->
<br>({$val->duration}{$lang->unit_sec})
<!--@endif-->
</td>
<td class="nowr">{$val->download_count}</td>
<td class="nowr">
<!--@if($val->upload_target_type == 'doc' && $document_list[$document_srl])-->
@ -112,6 +124,9 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<td class="nowr">{zdate($val->regdate,"Y-m-d H:i")}</td>
<td class="nowr"><a href="{getUrl('search_target','ipaddress','search_keyword',$val->ipaddress)}">{$val->ipaddress}</a></td>
<td class="nowr"><!--@if($val->isvalid=='Y')-->{$lang->is_valid}<!--@else-->{$lang->is_stand_by}<!--@end--></td>
<td class="nowr">
<a href="{getUrl(['module' => 'admin', 'act' => 'dispFileAdminEdit', 'file_srl' => $val->file_srl])}">{$lang->cmd_edit}</a>
</td>
<td>
<input type="checkbox" name="cart" value="{$val->file_srl}" />
</td>

View file

@ -1,3 +1,4 @@
<load target="css/config.css" />
<load target="js/file_admin.js" />
<div class="x_page-header">

View file

@ -6,7 +6,7 @@ function getFileList() {
var fileListTable = jQuery('#fileListTable');
var cartList = [];
fileListTable.find(':checkbox[name=cart]').each(function(){
if(this.checked) cartList.push(this.value);
if(this.checked) cartList.push(this.value);
});
var params = new Array();
@ -58,3 +58,24 @@ function checkSearch(form)
}
*/
}
(function() {
$(function() {
$('.preset_size').on('click', function() {
const preset_size = parseInt($(this).text(), 10);
const width = parseInt($('input[name=original_width]').val(), 10);
const height = parseInt($('input[name=original_height]').val(), 10);
let new_width = 0;
let new_height = 0;
if (width > height) {
new_width = preset_size;
new_height = Math.round(preset_size * (height / width));
} else {
new_width = Math.round(preset_size * (width / height));
new_height = preset_size;
}
$('input[name=new_width]').val(new_width);
$('input[name=new_height]').val(new_height);
});
});
})(jQuery);

View file

@ -35,26 +35,20 @@
<div class="x_control-group">
<label class="x_control-label">{$lang->image_autoconv}</label>
<div class="x_controls">
<label for="image_autoconv_bmp2jpg">
<input type="checkbox" name="image_autoconv_bmp2jpg" id="image_autoconv_bmp2jpg" value="Y" checked="checked"|cond="$config->image_autoconv['bmp2jpg']" disabled="disabled"|cond="!function_exists('imagebmp')" />
{$lang->image_autoconv_bmp2jpg}
</label>
<label for="image_autoconv_png2jpg">
<input type="checkbox" name="image_autoconv_png2jpg" id="image_autoconv_png2jpg" value="Y" checked="checked"|cond="$config->image_autoconv['png2jpg']" disabled="disabled"|cond="!function_exists('imagepng')" />
{$lang->image_autoconv_png2jpg}
</label>
<label for="image_autoconv_webp2jpg">
<input type="checkbox" name="image_autoconv_webp2jpg" id="image_autoconv_webp2jpg" value="Y" checked="checked"|cond="$config->image_autoconv['webp2jpg']" disabled="disabled"|cond="!function_exists('imagewebp')" />
{$lang->image_autoconv_webp2jpg}
</label>
<label for="image_autoconv_avif2jpg">
<input type="checkbox" name="image_autoconv_avif2jpg" id="image_autoconv_avif2jpg" value="Y" checked="checked"|cond="$config->image_autoconv['avif2jpg']" disabled="disabled"|cond="!$is_magick" />
{$lang->image_autoconv_avif2jpg}
</label>
<label for="image_autoconv_heic2jpg">
<input type="checkbox" name="image_autoconv_heic2jpg" id="image_autoconv_heic2jpg" value="Y" checked="checked"|cond="$config->image_autoconv['heic2jpg']" disabled="disabled"|cond="!$is_magick" />
{$lang->image_autoconv_heic2jpg}
</label>
{@ $source_types = ['bmp', 'jpg', 'png', 'webp', 'avif', 'heic']}
<!--@foreach($source_types as $source_type)-->
<div class="image_autoconv_types">
<label for="image_autoconv_{$source_type}" class="x_inline">
{strtoupper($source_type)}
</label>
<select name="image_autoconv[{$source_type}]" id="image_autoconv_{$source_type}" disabled="disabled"|cond="!$is_magick && in_array($source_type, ['avif', 'heic'])">
<option value=""></option>
<option value="jpg" selected="selected"|cond="($config->image_autoconv[$source_type] ?? '') === 'jpg' || !empty($config->image_autoconv[$source_type . '2jpg'])">JPG</option>
<option value="png" selected="selected"|cond="($config->image_autoconv[$source_type] ?? '') === 'png'">PNG</option>
<option value="webp" selected="selected"|cond="($config->image_autoconv[$source_type] ?? '') === 'webp'">WebP</option>
</select>
</div>
<!--@endforeach-->
<p class="x_help-block">
{$lang->about_image_autoconv}<br />
{$lang->msg_need_magick}
@ -76,12 +70,16 @@
</p>
<p class="x_help-block">
<label class="x_inline" for="max_image_size_same_format_Y">
<input type="radio" name="max_image_size_same_format" id="max_image_size_same_format_Y" value="Y" checked="checked"|cond="$config->max_image_size_same_format === 'Y'" />
<input type="radio" name="max_image_size_same_format" id="max_image_size_same_format_Y" value="Y" checked="checked"|cond="!isset($config->max_image_size_same_format) || $config->max_image_size_same_format === 'Y'" />
{$lang->max_image_size_same_format_Y}
</label>
<label class="x_inline" for="max_image_size_same_format_N">
<input type="radio" name="max_image_size_same_format" id="max_image_size_same_format_N" value="N" checked="checked"|cond="$config->max_image_size_same_format !== 'Y'" />
{$lang->max_image_size_same_format_N}
<label class="x_inline" for="max_image_size_same_format_to_jpg">
<input type="radio" name="max_image_size_same_format" id="max_image_size_same_format_to_jpg" value="jpg" checked="checked"|cond="$config->max_image_size_same_format === 'jpg' || $config->max_image_size_same_format === 'N'" />
{$lang->max_image_size_same_format_to_jpg}
</label>
<label class="x_inline" for="max_image_size_same_format_to_webp">
<input type="radio" name="max_image_size_same_format" id="max_image_size_same_format_to_webp" value="webp" checked="checked"|cond="$config->max_image_size_same_format === 'webp'" />
{$lang->max_image_size_same_format_to_webp}
</label>
<label for="max_image_size_admin">
<input type="checkbox" name="max_image_size_admin" id="max_image_size_admin" value="Y" checked="checked"|cond="$config->max_image_size_admin === 'Y'" />
@ -135,11 +133,11 @@
<label class="x_control-label">{$lang->image_autoconv_gif2mp4}</label>
<div class="x_controls">
<label for="image_autoconv_gif2mp4_Y" class="x_inline">
<input type="radio" name="image_autoconv_gif2mp4" id="image_autoconv_gif2mp4_Y" value="Y" checked="checked"|cond="$config->image_autoconv['gif2mp4'] === true" disabled="disabled"|cond="!$is_ffmpeg" />
<input type="radio" name="image_autoconv[gif2mp4]" id="image_autoconv_gif2mp4_Y" value="Y" checked="checked"|cond="$config->image_autoconv['gif2mp4'] === true" disabled="disabled"|cond="!$is_ffmpeg" />
{$lang->cmd_yes}
</label>
<label for="image_autoconv_gif2mp4_N" class="x_inline">
<input type="radio" name="image_autoconv_gif2mp4" id="image_autoconv_gif2mp4_N" value="N" checked="checked"|cond="$config->image_autoconv['gif2mp4'] !== true" disabled="disabled"|cond="!$is_ffmpeg" />
<input type="radio" name="image_autoconv[gif2mp4]" id="image_autoconv_gif2mp4_N" value="N" checked="checked"|cond="$config->image_autoconv['gif2mp4'] !== true" disabled="disabled"|cond="!$is_ffmpeg" />
{$lang->cmd_no}
</label>
<p class="x_help-block">{$lang->about_image_autoconv_gif2mp4}</p>

View file

@ -337,7 +337,7 @@ class installController extends install
}
// Check curl
if(function_exists('curl_init'))
if(function_exists('curl_init') && function_exists('curl_exec'))
{
$checklist['curl'] = true;
}
@ -347,7 +347,7 @@ class installController extends install
}
// Check GD
if(function_exists('imagecreatefromgif'))
if(function_exists('imagecreatefromjpeg') && function_exists('imagecreatefrompng'))
{
$checklist['gd'] = true;
}
@ -367,7 +367,7 @@ class installController extends install
}
// Check json
if(function_exists('json_encode'))
if(function_exists('json_encode') && function_exists('json_decode'))
{
$checklist['json'] = true;
}

View file

@ -1,11 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="0.2">
<title xml:lang="ko">한국 우편번호</title>
<title xml:lang="en">Korean Postal Code</title>
<description xml:lang="ko">공개 API를 이용해 우편번호 검색 서비스를 이용합니다.</description>
<description xml:lang="en">Module to utilize public postal code searching APIs in South Korea.</description>
<version>RX_VERSION</version>
<date>RX_CORE</date>
<author email_address="developers@xpressengine.com" link="http://www.xpressengine.com/">
<name xml:lang="ko">NAVER</name>
<name xml:lang="en">NAVER</name>
</author>
</module>

20
modules/krzip/lang/en.php Normal file
View file

@ -0,0 +1,20 @@
<?php
$lang->krzip = 'Korean Postal Code';
$lang->cmd_krzip_api_type = 'Select API Provider';
$lang->cmd_krzip_daumapi = 'Daum-Kakao API';
$lang->cmd_krzip_epostapi = 'Korea Post API';
$lang->cmd_krzip_postcodify = 'Postcodify';
$lang->cmd_krzip_regkey = 'Registration Key';
$lang->cmd_krzip_postcode = 'Postal Code';
$lang->cmd_krzip_address = 'Mailing Address';
$lang->cmd_krzip_detail_address = 'Detailed Address';
$lang->about_krzip = 'Postal code searching using public APIs for postal codes in South Korea.';
$lang->about_krzip_api_handler = 'Determining which API will be used to find the postal codes.';
$lang->about_krzip_epostapi_regkey = 'Entering the registration key from the Korea Post for using their API.';
$lang->msg_krzip_road_address_expectation = 'Road-Name Based Address: %s';
$lang->msg_krzip_jibun_address_expectation = 'Land-Lot Based Address: %s';
$lang->msg_krzip_no_query = 'Please provide a search keyword.';
$lang->msg_krzip_is_maintenance = 'Under maintenance.';
$lang->msg_krzip_wrong_regkey = 'This is an invalid registration key.';
$lang->msg_krzip_no_result = 'There is no found address.';
$lang->msg_krzip_riddling_wrong = 'Unknown error in the postal code module.';

View file

@ -19,7 +19,7 @@ $lang->about_downloaded_layouts = 'List of downloaded layouts';
$lang->about_title = 'Please enter the title that is easy to verify when connecting to the page';
$lang->about_not_apply_menu = 'Layouts of all pages connected via menu will be changed en bloc by checking this option.';
$lang->about_layout = 'Layout module helps you create the site\'s layout easily. By using layout setting and menu connection, website\'s completed shape will be displayed with various modules. Layouts which you cannot delete are the default layouts of blogs or other moduels, thus you have to delete them from their setting pages.';
$lang->about_layout_code = 'It will be applied to the service when you save the layout code after editing it. Please first preview your code and then save it. You can refer grammar of XE\'s template from <a href="http://code.google.com/p/xe-core/wiki/TemplateSyntax" target="_blank">XE Template</a>.';
$lang->about_layout_code = 'It will be applied to the service when you save the layout code after editing it. Please first preview your code and then save it. You can refer the syntax of Rhymix\'s template from <a href="https://rhymix.org/manual/theme/intro" target="_blank">Rhymix Template Manual (Korean)</a>.';
$lang->layout_export = 'Export';
$lang->layout_btn_export = 'Download My Layout';
$lang->about_layout_export = 'Export currently edited layout.';
@ -114,3 +114,9 @@ $lang->faceoff_migration['5'] = 'Upload to ./layouts through FTP.';
$lang->faceoff_migration['6'] = 'Insert new layout from installed layout. Make sure to check if the path of layout is the same as the uploaded path. You need to set the layout including logo images.';
$lang->msg_empty_origin_layout = 'Original layout is not exist';
$lang->msg_empty_target_layout = 'Target layout is not assigned';
$lang->msg_at_least_one_layout = 'You cannot delete this copy. At least one layout copy of this layout should be remained.';
$lang->use_site_default_layout = 'Use the default layout of the website';
$lang->use_responsive_pc_layout = 'Use the same responsive layout as the PC';
$lang->msg_unabled_preview = 'You can\'t preview because there is no page with this menu type.';
$lang->article_preview_title = 'Title of the document';
$lang->article_preview_content = 'Welcome. Nice to meet you.';

View file

@ -19,7 +19,7 @@ $lang->about_downloaded_layouts = '다운로드되어 있는 레이아웃 목록
$lang->about_title = '페이지에 연결 시 쉽게 구분할 수 있는 제목을 입력해주세요.';
$lang->about_not_apply_menu = '지정한 메뉴에 연결된 모든 페이지의 레이아웃을 현재 레이아웃으로 지정합니다.';
$lang->about_layout = '사이트의 레이아웃을 쉽게 만들 수 있도록 도와줍니다. 레이아웃 설정과 메뉴의 연결을 통해서 완성된 사이트의 모습으로 보여줄 수 있도록 합니다. 삭제나 수정이 불가능한 레이아웃은 페이지에 포함된 레이아웃이므로 해당 페이지에서 설정해야 합니다.';
$lang->about_layout_code = '아래 레이아웃의 코드를 직접 수정 후 저장하면 서비스에 반영이 됩니다. 꼭 미리보기를 한 후에 저장을 하세요. XE의 템플릿 문법은 <a href="http://code.google.com/p/xe-core/wiki/TemplateSyntax" target="_blank">XE 템플릿</a> 을 참고하면 됩니다.';
$lang->about_layout_code = '아래 레이아웃의 코드를 직접 수정 후 저장하면 서비스에 반영이 됩니다. 꼭 미리보기를 한 후에 저장을 하세요. Rhymix의 템플릿 문법은 <a href="https://rhymix.org/manual/theme/intro" target="_blank">테마 제작 매뉴얼</a>을 참고하면 됩니다.';
$lang->layout_export = '내보내기';
$lang->layout_btn_export = '내 레이아웃 다운로드';
$lang->about_layout_export = '현재 수정된 레이아웃을 내보내기를 합니다.';

View file

@ -87,6 +87,8 @@ $lang->verify_by_sms_confirm = 'Confirm';
$lang->verify_by_sms_message = 'Your verification code is %s.';
$lang->verify_by_sms_code_sent = 'A verification code has been sent to the number you entered.';
$lang->verify_by_sms_code_incorrect = 'The code you entered is incorrect.';
$lang->verify_by_sms_code_too_many_tries = 'Too many incorrect attempts. Please request a new code.';
$lang->verify_by_sms_code_expired = 'The code has expired. Please request a new code.';
$lang->verify_by_sms_code_confirmed = 'Your phone number has been confirmed.';
$lang->verify_by_sms_incomplete = 'Your phone number has not been verified. Please go through the verification process first.';
$lang->verify_by_sms_error = 'This website cannot send SMS.';

View file

@ -87,6 +87,8 @@ $lang->verify_by_sms_confirm = '인증번호 확인';
$lang->verify_by_sms_message = '인증번호는 %s입니다.';
$lang->verify_by_sms_code_sent = '인증번호가 SMS로 발송되었습니다.';
$lang->verify_by_sms_code_incorrect = '인증번호가 올바르지 않습니다.';
$lang->verify_by_sms_code_too_many_tries = '여러 번 틀려서 인증번호가 초기화됩니다. 다시 인증해 주세요.';
$lang->verify_by_sms_code_expired = '인증번호의 유효기간이 만료되었습니다. 다시 인증해 주세요.';
$lang->verify_by_sms_code_confirmed = '인증이 완료되었습니다.';
$lang->verify_by_sms_incomplete = '전화번호가 인증되지 않았습니다. 인증 과정을 거쳐 주십시오.';
$lang->verify_by_sms_error = 'SMS를 발송할 수 없습니다.';

View file

@ -26,7 +26,7 @@
<fieldset class="sn">
<ul>
<li>
<li cond="$identifierForm->name !== 'phone_number'">
<label for="identifierForm">{$identifierForm->title} <em style="color:red">*</em></label>
<input id="identifierForm" type="text" name="{$identifierForm->name}" value="{$identifierForm->value}" disabled="disabled" />
<input type="hidden" name="{$identifierForm->name}" value="{$identifierForm->value}" />
@ -78,4 +78,4 @@
return false;});
});
})(jQuery);
</script>
</script>

View file

@ -31,7 +31,7 @@
</div>
</div>
<ul>
<li>
<li cond="$identifierForm->name !== 'phone_number'">
<label for="{$identifierForm->name}">{$identifierForm->title} <em style="color:red">*</em></label>
<input type="text"|cond="$identifierForm->name!='email_address'" type="email"|cond="$identifierForm->name=='email_address'" name="{$identifierForm->name}" id="{$identifierForm->name}" value="" />
</li>

View file

@ -123,14 +123,20 @@ class MemberAdminController extends Member
}
// remove whitespace
$checkInfos = array('user_id', 'user_name', 'nick_name', 'email_address');
foreach($checkInfos as $val)
foreach(['user_id', 'nick_name', 'email_address'] as $val)
{
if(isset($args->{$val}))
{
$args->{$val} = preg_replace('/[\pZ\pC]+/u', '', utf8_clean(html_entity_decode($args->{$val})));
}
}
foreach(['user_name'] as $val)
{
if(isset($args->{$val}))
{
$args->{$val} = utf8_normalize_spaces(utf8_clean(html_entity_decode($args->{$val})));
}
}
// 실제로 디비쿼리시 빈값이 없다면 해당 쿼리를 무시하고 업데이트 하기 때문에 메모의 내용이 삭제가 되지 않습니다.
if(!isset($args->description))
@ -666,7 +672,33 @@ class MemberAdminController extends Member
$args->mskin = 'default';
}
// Update member module config
$output = $oModuleController->updateModuleConfig('member', $args);
if (!$output->toBool())
{
return $output;
}
// Sync member mid info with module config
$config = MemberModel::getMemberConfig();
if ($config->mid)
{
$module_info = ModuleModel::getModuleInfoByMid($config->mid);
if ($module_info->module === 'member')
{
$module_info->layout_srl = $args->layout_srl ?? -1;
$module_info->mlayout_srl = $args->mlayout_srl ?? -1;
$module_info->skin = $args->skin;
$module_info->mskin = $args->mskin;
$module_info->is_skin_fix = str_starts_with($module_info->skin, '/') ? 'N' : 'Y';
$module_info->is_mskin_fix = str_starts_with($module_info->mskin, '/') ? 'N' : 'Y';
$output = ModuleController::getInstance()->updateModule($module_info);
if (!$output->toBool())
{
return $output;
}
}
}
// default setting end
$this->setMessage('success_updated');
@ -1357,7 +1389,7 @@ class MemberAdminController extends Member
}
$args->group_srl = !empty($args->group_srl) ? $args->group_srl : getNextSequence();
$args->list_order = $args->list_order ?? $args->group_srl;
$args->title = escape($args->title);
$args->title = escape($args->title, false, true);
$args->description = escape($args->description);
$output = executeQuery('member.insertGroup', $args);
@ -1408,7 +1440,7 @@ class MemberAdminController extends Member
$output = executeQuery('member.updateGroupDefaultClear', $args);
if(!$output->toBool()) return $output;
}
$args->title = isset($args->title) ? escape($args->title) : null;
$args->title = isset($args->title) ? escape($args->title, false, true) : null;
$args->description = isset($args->description) ? escape($args->description) : null;
$output = executeQuery('member.updateGroup', $args);

View file

@ -58,9 +58,12 @@ class MemberAdminView extends Member
// retrieve group list
$this->group_list = $oMemberModel->getGroups();
foreach ($this->group_list as $group)
if ($this->act !== 'dispMemberAdminGroupList')
{
$group->title = Context::replaceUserLang($group->title, true);
foreach ($this->group_list as $group)
{
$group->title = Context::replaceUserLang($group->title, true);
}
}
Context::set('group_list', $this->group_list);
@ -455,18 +458,19 @@ class MemberAdminView extends Member
}
}
$identifier = array_first($member_config->identifiers);
$identifierForm = new stdClass;
$identifierForm->title = lang($identifier);
$identifierForm->name = $identifier;
$identifierForm->value = $member_info->$identifier;
Context::set('identifierForm', $identifierForm);
if ($member_info->limit_date < date('Ymd'))
{
$member_info->limit_date = '';
}
if (Context::get('member_srl'))
{
Context::setBrowserTitle(lang('member.msg_update_member'));
}
else
{
Context::setBrowserTitle(lang('member.msg_new_member'));
}
$this->setTemplateFile('insert_member');
}
@ -508,7 +512,11 @@ class MemberAdminView extends Member
foreach($member_config->signupForm as $formInfo)
{
if(!$formInfo->isUse || (in_array($formInfo->name, $identifiers) && $formInfo->name === array_first($identifiers)) || $formInfo->name == 'password')
if(!$formInfo->isUse || ($formInfo->name == 'password' && !$isAdmin))
{
continue;
}
if((in_array($formInfo->name, $identifiers) && $formInfo->name === array_first($identifiers)) && !$isAdmin)
{
continue;
}
@ -675,6 +683,16 @@ class MemberAdminView extends Member
$input->value = $memberInfo[$formInfo->name] ?? '';
$inputTag = $input->getFormHTML();
}
else if($formInfo->name == 'password')
{
$formTag->type = 'password';
$input = new Rhymix\Modules\Extravar\Models\Value(0, 1, '', 'password');
$input->parent_type = 'member';
$input->input_name = $formInfo->name;
$input->input_id = $formInfo->name;
$input->value = '';
$inputTag = $input->getFormHTML();
}
else
{
if($formInfo->name === 'nick_name' && ($member_config->allow_nickname_change ?? 'Y') === 'N' && !$isAdmin && !$isSignup)

View file

@ -796,14 +796,20 @@ class MemberController extends Member
}
// remove whitespace
$checkInfos = array('user_id', 'user_name', 'nick_name', 'email_address');
foreach($checkInfos as $val)
foreach(['user_id', 'nick_name', 'email_address'] as $val)
{
if(isset($args->{$val}))
{
$args->{$val} = preg_replace('/[\pZ\pC]+/u', '', utf8_clean(html_entity_decode($args->{$val})));
}
}
foreach(['user_name'] as $val)
{
if(isset($args->{$val}))
{
$args->{$val} = utf8_normalize_spaces(utf8_clean(html_entity_decode($args->{$val})));
}
}
// Check symbols in nickname
if($config->nickname_symbols === 'N')
@ -867,12 +873,24 @@ class MemberController extends Member
$this->putSignature($args->member_srl, $signature);
// Log-in
if($config->enable_confirm != 'Y')
if ($config->enable_confirm != 'Y')
{
$output = $this->doLogin($args->{$config->identifier});
if(!$output->toBool()) {
if($output->error == -9)
if (isset($config->identifiers) && is_array($config->identifiers))
{
$identifier = array_first($config->identifiers);
}
else
{
$identifier = $config->identifier ?? 'user_id';
}
$output = $this->doLogin($args->{$identifier});
if (!$output->toBool())
{
if ($output->error == -9)
{
$output->error = -11;
}
return $this->setRedirectUrl(getUrl('', 'act', 'dispMemberLoginForm'), $output);
}
}
@ -1080,14 +1098,20 @@ class MemberController extends Member
$args->extra_vars = serialize($extra_vars);
// remove whitespace
$checkInfos = array('user_id', 'user_name', 'nick_name', 'email_address');
foreach($checkInfos as $val)
foreach(['user_id', 'nick_name', 'email_address'] as $val)
{
if(isset($args->{$val}))
{
$args->{$val} = preg_replace('/[\pZ\pC]+/u', '', utf8_clean(html_entity_decode($args->{$val})));
}
}
foreach(['user_name'] as $val)
{
if(isset($args->{$val}))
{
$args->{$val} = utf8_normalize_spaces(utf8_clean(html_entity_decode($args->{$val})));
}
}
// Check if nickname change is allowed
if(isset($config->allow_nickname_change) && $config->allow_nickname_change === 'N')
@ -3772,6 +3796,8 @@ class MemberController extends Member
'country' => $phone_country,
'number' => $phone_number,
'code' => $is_special ? intval($config->special_phone_code) : $code,
'time' => time(),
'count' => 0,
'status' => false,
);
@ -3820,10 +3846,25 @@ class MemberController extends Member
}
$code = intval($code);
if(!isset($_SESSION['verify_by_sms']) || $_SESSION['verify_by_sms']['code'] !== $code)
if(!isset($_SESSION['verify_by_sms']))
{
throw new Rhymix\Framework\Exception('verify_by_sms_code_incorrect');
}
if (isset($_SESSION['verify_by_sms']['count']) && $_SESSION['verify_by_sms']['count'] >= 10)
{
unset($_SESSION['verify_by_sms']);
throw new Rhymix\Framework\Exception('verify_by_sms_code_too_many_tries');
}
if (isset($_SESSION['verify_by_sms']['time']) && $_SESSION['verify_by_sms']['time'] < time() - 600)
{
unset($_SESSION['verify_by_sms']);
throw new Rhymix\Framework\Exception('verify_by_sms_code_expired');
}
if ($_SESSION['verify_by_sms']['code'] !== $code)
{
$_SESSION['verify_by_sms']['count']++;
throw new Rhymix\Framework\Exception('verify_by_sms_code_incorrect');
}
$_SESSION['verify_by_sms']['status'] = true;
return new BaseObject(0, 'verify_by_sms_code_confirmed');

View file

@ -19,7 +19,7 @@
<input type="hidden" name="signature" value="{escape($member_info->signature)}" />
<input type="hidden" name="page" value="{$page}" />
<input type="hidden" name="xe_validator_id" value="modules/member/skins/default/1" />
<div class="control-group">
<div class="control-group" cond="$identifierForm->name !== 'phone_number'">
<label for="{$identifierForm->name}" class="control-label"><em style="color:red">*</em> {$identifierForm->title}</label>
<div class="controls">
<input type="hidden" name="{$identifierForm->name}" value="{$identifierForm->value}" />

View file

@ -27,7 +27,7 @@
</label>
</div>
</div>
<div class="control-group">
<div class="control-group" cond="$identifierForm->name !== 'phone_number'">
<label for="{$identifierForm->name}" class="control-label"><em style="color:red">*</em> {$identifierForm->title}</label>
<div class="controls">
<input type="text"|cond="$identifierForm->name!='email_address'" type="email"|cond="$identifierForm->name=='email_address'" name="{$identifierForm->name}" id="{$identifierForm->name}" value="" required />

View file

@ -5,13 +5,16 @@
xe.lang.deleteImageMark = '{$lang->msg_delete_extend_form}';
xe.lang.deleteImageName = '{$lang->msg_delete_extend_form}';
</script>
<div class="x_page-header">
<h1 cond="$member_srl">{$lang->msg_update_member}</h1>
<h1 cond="!$member_srl">{$lang->msg_new_member}</h1>
</div>
<div cond="$XE_VALIDATOR_MESSAGE && $XE_VALIDATOR_ID == 'modules/member/tpl/1'" class="message {$XE_VALIDATOR_MESSAGE_TYPE}">
<p>{$XE_VALIDATOR_MESSAGE}</p>
</div>
<form action="./" class="x_form-horizontal" ruleset="insertAdminMember" method="post" enctype="multipart/form-data">
<input type="hidden" name="module" value="member" />
<input type="hidden" name="act" value="procMemberAdminInsert" />
@ -20,40 +23,26 @@
<input type="hidden" name="success_return_url" value="{getUrl('act', $act)}" cond="$member_srl" />
<input type="hidden" name="success_return_url" value="{getUrl('act', 'dispMemberAdminList')}" cond="!$member_srl" />
<input type="hidden" name="xe_validator_id" value="modules/member/tpl/1" />
<div cond="$member_srl" class="x_control-group">
<label class="x_control-label" for="identifierForm"><em style="color:red">*</em> {$identifierForm->title}</label>
<div class="x_controls">
<input type="hidden" name="{$identifierForm->name}" value="{$identifierForm->value}" />
<input id="identifierForm" type="email" name="{$identifierForm->name}" value="{$identifierForm->value}" disabled="disabled" />
<!--@foreach($formTags as $formTag)-->
<div class="x_control-group">
<label class="x_control-label" for="{$formTag->name}">{$formTag->title}</label>
<div class="x_controls">
<!--@if($formTag->name === 'password')-->
<!--@if($member_srl)-->
<input id="password" type="password" name="reset_password" value="" autocomplete="off" />
<!--@else-->
<input id="password" type="password" name="password" value="" autocomplete="off" />
<!--@endif-->
<!--@elseif($formTag->name === 'signature')-->
{$editor|noescape}
<!--@else-->
{$formTag->inputTag}
<!--@endif-->
</div>
</div>
</div>
<div cond="!$member_srl" class="x_control-group">
<label class="x_control-label" for="identifierForm"><em style="color:red">*</em> {$identifierForm->title}</label>
<div class="x_controls">
<input id="identifierForm" type="text" name="{$identifierForm->name}" value="" />
</div>
</div>
<div cond="$member_srl" class="x_control-group">
<label class="x_control-label" for="password"><em style="color:red">*</em> {$lang->password}</label>
<div class="x_controls">
<input id="password" type="password" name="reset_password" value="" autocomplete="off" />
</div>
</div>
<div cond="!$member_srl" class="x_control-group">
<label class="x_control-label" for="password"><em style="color:red">*</em> {$lang->password}</label>
<div class="x_controls">
<input id="password" type="text" name="password" value="" autocomplete="off" />
</div>
</div>
<div loop="$formTags=>$formTag" class="x_control-group">
<label class="x_control-label" for="{$formTag->name}">{$formTag->title}</label>
<div class="x_controls" cond="$formTag->name != 'signature'">{$formTag->inputTag}</div>
<div class="x_controls" cond="$formTag->name =='signature'">{$editor|noescape}</div>
</div>
<style scoped>
.xpress-editor>#smart_content,
.xpress-editor>#smart_content>.tool{clear:none}
</style>
<!--@endforeach-->
<div class="x_control-group">
<label class="x_control-label">{$lang->allow_mailing}</label>
<div class="x_controls">
@ -61,6 +50,7 @@
<label class="x_inline" for="mailingNo"><input type="radio" name="allow_mailing" id="mailingNo" value="N" checked="checked"|cond="$member_info->allow_mailing != 'Y'" > {$lang->cmd_no}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->allow_message}</label>
<div class="x_controls">
@ -69,6 +59,7 @@
</block>
</div>
</div>
<div class="x_control-group div_status" cond="$member_srl">
<label class="x_control-label">{$lang->status}</label>
<div class="x_controls">
@ -77,6 +68,7 @@
<label class="x_inline" for="status_unauthed"><input type="radio" name="status" id="status_unauthed" value="UNAUTHED" checked="checked"|cond="$member_info->status == 'UNAUTHED' && $member_info->member_srl != $logged_info->member_srl" disabled="disabled"|cond="$member_info->member_srl == $logged_info->member_srl" /> {$lang->member_unauthenticated}</label>
</div>
</div>
<div class="x_control-group div_refused_reason">
<label class="x_control-label">{$lang->refused_reason}</label>
<div class="x_controls">
@ -84,6 +76,7 @@
<span class="x_help-inline">{$lang->about_refused_reason}</span>
</div>
</div>
<div class="x_control-group" cond="$member_srl">
<label class="x_control-label" for="until">{$lang->limit_date}</label>
<div class="x_controls">
@ -93,6 +86,7 @@
<span class="x_help-inline">{$lang->about_limit_date}</span>
</div>
</div>
<div class="x_control-group div_limited_reason">
<label class="x_control-label">{$lang->limited_reason}</label>
<div class="x_controls">
@ -100,6 +94,7 @@
<span class="x_help-inline">{$lang->about_limited_reason}</span>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->is_admin}</label>
<div class="x_controls">
@ -107,6 +102,7 @@
<label class="x_inline" for="not_admin"><input type="radio" name="is_admin" id="not_admin" value="N" checked="checked"|cond="$member_info->is_admin != 'Y'" disabled="disabled"|cond="$member_info->member_srl == $logged_info->member_srl"> {$lang->cmd_no}</label>
</div>
</div>
<div class="x_control-group">
<label class="x_control-label" for="description">{$lang->description}</label>
<div class="x_controls">
@ -114,6 +110,7 @@
<span class="x_help-inline">{$lang->about_member_description}</span>
</div>
</div>
<div class="x_control-group" cond="$member_srl">
<label class="x_control-label">{$lang->signup_date}</label>
<div class="x_controls">
@ -123,6 +120,7 @@
<!--@end-->
</div>
</div>
<div class="x_control-group" cond="$member_srl">
<label class="x_control-label">{$lang->last_login}</label>
<div class="x_controls">
@ -132,6 +130,7 @@
<!--@end-->
</div>
</div>
<div class="x_control-group">
<label class="x_control-label">{$lang->member_group}</label>
<div class="x_controls">
@ -141,11 +140,14 @@
</label>
</div>
</div>
<div class="x_clearfix btnArea">
<span class="x_pull-left" cond="$member_srl"><button class="x_btn" type="button" onclick="history.go(-1)">{$lang->cmd_cancel}</button></span>
<span class="x_pull-right"><input class="x_btn x_btn-primary" type="submit" value="{$lang->cmd_save}" /></span>
</div>
</form>
<script>
(function($){
$(function(){

View file

@ -2178,7 +2178,7 @@ class MenuAdminController extends Menu
"normal_btn" => %s,
"hover_btn" => %s,
"active_btn" => %s,
"selected" => (array(%s) && in_array(Context::get("mid"), array(%s)) ? 1 : 0),
"selected" => ((%s === "Y" && %s === \RX_BASEURL . \RX_REQUEST_URL) || (array(%s) && in_array(Context::get("mid"), array(%s))) ? 1 : 0),
"expand" => %s,
"list" => array(%s),
"link" => (%s ? (array(%s) && in_array(Context::get("mid"), array(%s)) ? %s : %s) : "")' . PHP_EOL,
@ -2201,6 +2201,8 @@ class MenuAdminController extends Menu
var_export($normal_btn, true),
var_export($hover_btn, true),
var_export($active_btn, true),
var_export($is_shortcut, true),
var_export($url, true),
$selected,
$selected,
var_export($expand, true),

View file

@ -350,7 +350,9 @@
<h1>{$lang->menu_img_btn}</h1>
<div class="cnt">
<p style="border-bottom:1px solid #ddd;width:220px;min-width:100%;padding-bottom:10px">{$lang->about_imgbtn}</p>
<form action="?module=menu&act=procMenuAdminButtonUpload" class="_btn_normal" target="submitTarget" method="post" enctype="multipart/form-data">
<form action="{\RX_BASEURL}" class="_btn_normal" target="submitTarget" method="post" enctype="multipart/form-data">
<input name="module" type="hidden" value="menu" />
<input name="act" type="hidden" value="procMenuAdminButtonUpload" />
<input name="menu_item_srl" type="hidden" value=""/>
<input name="xe_js_callback" type="hidden" value="top.onBtnImgUploaded"/>
<input name="isNormalDelete" type="hidden" value="Y"/>
@ -368,7 +370,9 @@
</span>
</div>
</form>
<form action="?module=menu&act=procMenuAdminButtonUpload" class="_btn_hover" target="submitTarget" method="post" enctype="multipart/form-data">
<form action="{\RX_BASEURL}" class="_btn_hover" target="submitTarget" method="post" enctype="multipart/form-data">
<input name="module" type="hidden" value="menu" />
<input name="act" type="hidden" value="procMenuAdminButtonUpload" />
<input name="menu_item_srl" type="hidden" value=""/>
<input name="xe_js_callback" type="hidden" value="top.onBtnImgUploaded"/>
<input name="isHoverDelete" type="hidden" value="Y"/>
@ -386,7 +390,9 @@
</span>
</div>
</form>
<form action="?module=menu&act=procMenuAdminButtonUpload" class="_btn_selected" target="submitTarget" method="post" enctype="multipart/form-data">
<form action="{\RX_BASEURL}" class="_btn_selected" target="submitTarget" method="post" enctype="multipart/form-data">
<input name="module" type="hidden" value="menu" />
<input name="act" type="hidden" value="procMenuAdminButtonUpload" />
<input name="menu_item_srl" type="hidden" value=""/>
<input name="xe_js_callback" type="hidden" value="top.onBtnImgUploaded"/>
<input name="isActiveDelete" type="hidden" value="Y"/>

View file

@ -497,23 +497,43 @@ class ModuleModel extends Module
public static function addModuleExtraVars($module_info)
{
// Process although one or more module informaion is requested
if(!is_array($module_info)) $target_module_info = array($module_info);
else $target_module_info = $module_info;
if (!is_array($module_info))
{
$target_module_info = array($module_info);
}
else
{
$target_module_info = $module_info;
}
// Get module_srl
$module_srls = array();
foreach($target_module_info as $key => $val)
{
$module_srl = $val->module_srl;
if(!$module_srl) continue;
$module_srls[] = $val->module_srl;
if ($val->module_srl)
{
$module_srls[] = $val->module_srl;
}
}
if (!count($module_srls))
{
return $module_info;
}
// Extract extra information of the module and skin
$extra_vars = self::getModuleExtraVars($module_srls);
if(!count($module_srls) || !count($extra_vars)) return $module_info;
if (!count($extra_vars))
{
return $module_info;
}
foreach($target_module_info as $key => $val)
{
if(!$extra_vars[$val->module_srl] || !count(get_object_vars($extra_vars[$val->module_srl]))) continue;
if (!isset($extra_vars[$val->module_srl]))
{
continue;
}
foreach($extra_vars[$val->module_srl] as $k => $v)
{
if(isset($target_module_info[$key]->{$k}) && $target_module_info[$key]->{$k})
@ -524,8 +544,14 @@ class ModuleModel extends Module
}
}
if(is_array($module_info)) return $target_module_info;
return $target_module_info[0];
if(is_array($module_info))
{
return $target_module_info;
}
else
{
return $target_module_info[0];
}
}
/**
@ -2270,6 +2296,10 @@ class ModuleModel extends Module
else if(count($member_group) && in_array($val->group_srl, $member_group))
{
$grant->{$val->name} = true;
if ($val->name === 'manager' && !$grant->scopes)
{
$grant->scopes = true;
}
}
}
}

View file

@ -0,0 +1,12 @@
<table name="task_schedule">
<column name="task_srl" type="bigint" notnull="notnull" primary_key="primary_key" />
<column name="task_type" type="varchar" size="40" index="idx_task_type" />
<column name="run_interval" type="varchar" size="191" index="idx_run_interval" />
<column name="run_count" type="bigint" notnull="notnull" default="0" index="idx_run_count" />
<column name="first_run" type="datetime" index="idx_first_run" />
<column name="last_run" type="datetime" index="idx_last_run" />
<column name="handler" type="varchar" size="191" notnull="notnull" />
<column name="args" type="longtext" notnull="notnull" />
<column name="options" type="longtext" notnull="notnull" />
<column name="regdate" type="datetime" notnull="notnull" index="idx_regdate" />
</table>

View file

@ -21,7 +21,7 @@
<div id="zone_{$grant_name}" hidden style="margin-top:8px">
<label loop="$group_list => $group_srl, $group_item" for="grant_{$grant_name}_{$group_srl}">
<input type="checkbox" name="{$grant_name}[]" value="{$group_item->group_srl}" id="grant_{$grant_name}_{$group_srl}" />
{$group_item->title}
{Context::replaceUserLang($group_item->title, true)}
</label>
</div>
</div>

View file

@ -26,7 +26,7 @@
<div id="zone_{$grant_name}" hidden style="margin:8px 0 0 0">
<label loop="$group_list => $group_srl, $group_item" for="grant_{$grant_name}_{$group_srl}">
<input type="checkbox" class="checkbox" name="{$grant_name}" value="{$group_item->group_srl}" id="grant_{$grant_name}_{$group_srl}" />
{$group_item->title}
{Context::replaceUserLang($group_item->title, true)}
</label>
</div>
</div>

View file

@ -65,7 +65,10 @@
</select>
<div id="zone_{$grant_name}" hidden style="margin:8px 0 0 0">
<!--@foreach($group_list as $group_srl => $group_item)-->
<label for="grant_{$grant_name}_{$group_srl}" class="x_inline"><input type="checkbox" class="checkbox" name="{$grant_name}" value="{$group_item->group_srl}" id="grant_{$grant_name}_{$group_srl}" checked="checked"|cond="is_array($selected_group[$grant_name])&&in_array($group_srl,$selected_group[$grant_name])" /> {$group_item->title}</label>
<label for="grant_{$grant_name}_{$group_srl}" class="x_inline">
<input type="checkbox" class="checkbox" name="{$grant_name}" value="{$group_item->group_srl}" id="grant_{$grant_name}_{$group_srl}" checked="checked"|cond="is_array($selected_group[$grant_name])&&in_array($group_srl,$selected_group[$grant_name])" />
{Context::replaceUserLang($group_item->title, true)}
</label>
<!--@end-->
</div>
</div>

View file

@ -1,19 +1,19 @@
<?php
$lang->ncenterlite = 'Notification Center';
$lang->ncenterlite_notify = 'notification';
$lang->ncenterlite_install_version = 'Installed version';
$lang->ncenterlite_install_version = 'Installed Version';
$lang->ncenterlite_advenced_config = 'Advenced Setting';
$lang->ncenterlite_document = 'post';
$lang->ncenterlite_comment = 'comment';
$lang->ncenterlite_type_document = 'New document';
$lang->ncenterlite_type_comment = 'New comment';
$lang->ncenterlite_type_comment_comment = 'Reply on comment';
$lang->ncenterlite_type_document = 'New Post';
$lang->ncenterlite_type_comment = 'New Comment';
$lang->ncenterlite_type_comment_comment = 'Reply on Comments';
$lang->ncenterlite_type_mention = 'Mention';
$lang->ncenterlite_type_vote = 'Vote';
$lang->ncenterlite_type_scrap = 'Scrap';
$lang->ncenterlite_type_message = 'Direct message';
$lang->ncenterlite_type_test = 'Test notification';
$lang->ncenterlite_type_admin_content = 'Admin notification';
$lang->ncenterlite_type_message = 'Direct Message';
$lang->ncenterlite_type_test = 'Dummy Notification';
$lang->ncenterlite_type_admin_content = 'Admin Notification';
$lang->ncenterlite_type_custom = 'Other';
$lang->ncenterlite_comment_noti = $lang->ncenterlite_type_comment;
$lang->ncenterlite_comment_comment_noti = $lang->ncenterlite_type_comment_comment;
@ -24,15 +24,20 @@ $lang->ncenterlite_message_noti = $lang->ncenterlite_type_message;
$lang->ncenterlite_sender = 'Sender';
$lang->ncenterlite_addressee = 'Recipient';
$lang->ncenterlite_noti_contents = 'Contents';
$lang->ncenterlite_read = 'Have read';
$lang->ncenterlite_notify_setting = 'Turn Off Notifications at:';
$lang->ncenterlite_about_notify_setting = 'You can turn off notifications in the selected pages and modules. Please select the pages and modules to turn off notifications in the following list.';
$lang->ncenterlite_notify_mid_all = 'Forwarding Notifications to the Administrators';
$lang->ncenterlite_about_mid_all = "You can listen to all the notifications from the selected pages and modules. Please select the pages and modules to receive forwarded notifications in the following list. (Caution: This setting may let you know the other members' activities in the selected pages.)";
$lang->ncenterlite_read = 'Have Read';
$lang->ncenterlite_read_y = 'Read';
$lang->ncenterlite_read_n = 'Not read';
$lang->ncenterlite_read_n = 'Not Read';
$lang->ncenterlite_no_target = 'no target';
$lang->ncenterlite_my_list = 'My notification list';
$lang->ncenterlite_my_settings = 'My notification settings';
$lang->ncenterlite_user_settings = 'User notification settings';
$lang->ncenterlite_my_list = 'Received Notifications';
$lang->ncenterlite_my_settings = 'My Notification Settings';
$lang->ncenterlite_user_settings = 'User Notification Settings';
$lang->ncenterlite_notify_settings = 'Notification Settings';
$lang->ncenterlite_userconfig_title = 'Notification Center Settings of %s';
$lang->ncenterlite_userconfig_about = 'Personalized settings of notification center can be controlled by you.';
$lang->ncenterlite_userconfig_about = 'Please manage your notification settings here.';
$lang->ncenterlite_comment_noti_about = 'Receive notifications for new comments on my posts.';
$lang->ncenterlite_comment_comment_noti_about = 'Receive notifications for replies to my comments.';
$lang->ncenterlite_mention_noti_about = 'Receive notifications for mentions (@%s).';
@ -41,9 +46,15 @@ $lang->ncenterlite_vote_noti_about = 'Receive notifications when someone votes o
$lang->ncenterlite_scrap_noti_about = 'Receive notifications when someone scraps my post.';
$lang->ncenterlite_admin_content_noti_about = 'Receive administrator notifications.';
$lang->ncenterlite_custom_noti_about = 'Receive all other notifications.';
$lang->ncneterlite_block_individual = 'Turn off notifications from each post/comment';
$lang->ncneterlite_block_individual_about = 'You can turn off notifications from a particular post or comment.';
$lang->ncenterlite_activate = 'Activate';
$lang->ncenterlite_inactivate = 'Inactivate';
$lang->ncenterlite_userconfig_about_warning = 'Watch out! You are controlling other user\'s settings via this page.';
$lang->ncenterlite_comment_all = 'Let every commenter know';
$lang->ncenterlite_comment_all_setting = 'Notification settings for comment authors';
$lang->ncenterlite_comment_all_select_mid = 'Modules with notifications for commenters';
$lang->ncenterlite_about_comment_all_select_mid = 'Select pages and modules to turn on the notifications for commenters. If there are no selected modules, this function will be inactive.';
$lang->ncenterlite_article = '<strong>%1$s</strong> wrote "%2$s".';
$lang->ncenterlite_board = '<strong>%1$s</strong> wrote "%3$s" on <strong>%2$s</strong>.';
$lang->ncenterlite_commented = '<strong>%1$s</strong> commented "%3$s" on your %2$s.';
@ -52,15 +63,15 @@ $lang->ncenterlite_mentioned = '<strong>%1$s</strong> mentioned you in a %4$s, "
$lang->ncenterlite_message_string = 'You have <strong>%d</strong> unread message.';
$lang->ncenterlite_message_string_plural = 'You have <strong>%d</strong> unread messages.';
$lang->ncenterlite_message_mention = '<strong>%1$s</strong> sent you a message, "%2$s".';
$lang->ncenterlite_test_noti = 'Hello, <strong>%s</strong>! This is a test notification.';
$lang->ncenterlite_test_noti = 'Hi <strong>%s</strong>! This is a dummy notification.';
$lang->ncenterlite_vote = '<strong>%1$s</strong> liked your %3$s, "%2$s".';
$lang->ncenterlite_vote_anonymous = 'Your %2$s, "%1$s" was liked.';
$lang->ncenterlite_scrap = '<strong>%1$s</strong> scrapped your %3$s, "%2$s".';
$lang->ncenterlite_scrap_anonymous = 'Your %2$s, "%1$s" was scrapped.';
$lang->ncenterlite_admin_content_message = '<strong>%1$s</strong> wrote "%3$s" on <strong>%2$s</strong>.';
$lang->ncenterlite_insert_member_message = '<strong>%s!</strong> Welcome to the <strong>membership!!</strong>';
$lang->ncenterlite_insert_member_message = '<strong>%s!</strong> Welcome to join us!';
$lang->ncenterlite_content_image = '(Image)';
$lang->ncenterlite_content_empty = '(No Content)';
$lang->ncenterlite_content_empty = '(No content to display)';
$lang->ncenterlite_ago = 'ago';
$lang->ncenterlite_date['0'] = 'year';
$lang->ncenterlite_date['1'] = 'month';
@ -71,12 +82,13 @@ $lang->ncenterlite_date['5'] = 'second';
$lang->ncenterlite_sir = ' ';
$lang->ncenterlite_message = 'You have <strong class="num">%s</strong> new notification.';
$lang->ncenterlite_messages = 'You have <strong class="num">%s</strong> new notifications.';
$lang->ncenterlite_not_have_message = 'You have no new notifications.';
$lang->ncenterlite_thisistest = '[*] This is a test notice.';
$lang->ncenterlite_delete_all = 'delete all';
$lang->ncenterlite_not_have_message = 'There is no new notification for you.';
$lang->ncenterlite_thisistest = '[*] This is a dummy notification.';
$lang->ncenterlite_delete_all = 'Delete All';
$lang->ncenterlite_more = 'More';
$lang->ncenterlite_stop_no_permission_other_user = 'You don\'t have the authority to read settings of other members.';
$lang->ncenterlite_stop_no_permission_other_user_settings = 'You don\'t have the authority to control settings of other members.';
$lang->ncenterlite_stop_no_permission_other_user_block_settings = 'You are not allowed to change the other member\'s notification settings.';
$lang->ncenterlite_message_delete_notification_before = 'Notifications before %s are deleted.';
$lang->ncenterlite_message_delete_notification_all = 'Every notification is deleted.';
$lang->ncenterlite_click_to_open = 'Click here to open';
@ -86,6 +98,7 @@ $lang->ncenterlite_warning = 'Watch out!';
$lang->ncenterlite_io = 'Activate Notifications';
$lang->ncenterlite_io_about = 'You can activate or inactivate every function of Notification Center Lite module.';
$lang->ncenterlite_on = 'Active';
$lang->ncenterlite_only_message = 'For direct messages only';
$lang->ncenterlite_off = 'Inactive';
$lang->ncenterlite_display = 'Display Notifications';
$lang->ncenterlite_display_all = 'All display';
@ -106,41 +119,61 @@ $lang->ncenterlite_test_mention = 'Web page notification test';
$lang->ncenterlite_test_mention_about = 'Create dummy data for module and/or skin test.';
$lang->ncenterlite_test_push = 'Push notification test';
$lang->ncenterlite_test_push_about = 'Create dummy data for mobile push notification test.';
$lang->ncenterlite_document_event_settings = 'Document event notification';
$lang->ncenterlite_document_event_vote = 'Recommendation';
$lang->ncenterlite_document_event_vote_about = 'When someone recommend document, the author of it can get notifying.';
$lang->ncenterlite_document_event_settings = 'Post Event Notification';
$lang->ncenterlite_document_event_vote = 'Vote';
$lang->ncenterlite_document_event_vote_about = 'When someone vote up or down a post, its author can get notifying.';
$lang->ncenterlite_document_event_read = 'Delete notifying after read the article';
$lang->ncenterlite_document_event_read_preserve = 'Preserve notification';
$lang->ncenterlite_document_event_read_delete = 'Delete notification';
$lang->ncenterlite_document_event_read_preserve = 'Preserve Notification';
$lang->ncenterlite_document_event_read_delete = 'Delete Notification';
$lang->ncenterlite_document_event_read_about = 'Delete every notification after read the article. Default is do not delete (preserve).';
$lang->ncenterlite_commnet_event = 'Comments';
$lang->ncenterlite_commnet_event_noti_all = 'Notice every comments to the author';
$lang->ncenterlite_commnet_event_noti_some = 'Notice only direct replies to the author';
$lang->ncenterlite_message_event = 'Notify message';
$lang->ncenterlite_message_event_about = 'Do not notify message (Use XE Core message notification system).';
$lang->ncenterlite_message_event = 'Notify direct message';
$lang->ncenterlite_message_event_about = 'Do not notify direct messages via this module (Use notifications via the direct message module only).';
$lang->ncenterlite_mid_use = 'Module specific settings';
$lang->ncenterlite_to_unsubscribe = 'Disable notification';
$lang->ncenterlite_subscribe = 'Activate notification';
$lang->ncenterlite_cmd_unsubscribe_settings = 'Notification settings';
$lang->ncenterlite_notify_count = 'Notification count';
$lang->ncenterlite_notify_count_about = 'Set the number of notifications per page.';
$lang->this_message_unsubscribe = 'Unsubscribe from this post';
$lang->about_this_message_unsubscribe = 'Stop receiving notifications abou this post.';
$lang->this_message_unsubscribe = 'Unsubscribe notifications from this post';
$lang->about_this_message_unsubscribe = 'Stop receiving notifications about this post.';
$lang->unsubscribe_list = 'Unsubscribe List';
$lang->unsubscribe = 'Unsubscribe individually';
$lang->about_unsubscribe = 'Allow users to unsubscribe from individual posts.';
$lang->about_unsubscribe = 'Allow users to unsubscribe notifications from individual posts.';
$lang->fcm_push_format = 'Push notification format';
$lang->fcm_push_format_notification = 'Use notification';
$lang->fcm_push_format_data = 'Use data';
$lang->about_fcm_push_format = 'Select where to place the notification data when sending push notifications with Google FCM.<br>This setting should match the requirements of your client application or frontend code.';
$lang->member_menu_view = 'Display personalized notification panel';
$lang->member_menu_on = 'Display';
$lang->member_menu_off = 'Hide';
$lang->about_member_menu_view = 'Each member may have their own settings panel for their notification center. They can manipulate the notification settings in their panel. Please select if you will allow them to have their panel or not.';
$lang->user_notify_setting = 'User notification settings';
$lang->about_user_notify_setting = 'Each member can set a notify settings. Warning! If a member setting not use notifications, they will not be notified regardless of their default settings.';
$lang->ncenterlite_push_before_sms = 'Try a push notification before sending an SMS';
$lang->ncenterlite_push_before_sms_about = 'Don\'t send an SMS if the recipient has at least one device to which a push notification has been successfully sent.';
$lang->ncenterlite_no_notify = 'There is no notification to present.';
$lang->ncenterlite_all_delete = 'Delete all';
$lang->ncenterlite_month_before_delete = 'Delete older than 1 month';
$lang->dont_check_notify_delete = 'Unread notifications will be deleted, too.';
$lang->user_notify_setting = 'User notify setting.';
$lang->about_user_notify_setting = 'Each member can set a notify settings. Warning! If a member setting not use notifications, they will not be notified regardless of their default settings.';
$lang->msg_not_use_user_setting = 'user setting\'s not use. Please contact your administrator.';
$lang->ncenterlite_push_before_sms = 'Try Push before SMS';
$lang->ncenterlite_push_before_sms_about = 'Don\'t send SMS if the recipient has at least one device to which a push notification has been successfully sent.';
$lang->anonymous_nick_name_setting = 'Alternative nickname for anonymous';
$lang->about_anonymous_nick_name = 'Defining an alternative nickname for notifications from anonymous.';
$lang->mention_suffixes = 'Common name suffixes';
$lang->about_mention_suffixes = 'Please define common suffixes for names. This notification system will identify the name with and without the defined suffixes. For instance, if " Doe" is defined as a suffix, both "@John Doe" and "@John" will point to "@John" in this system. Please separate multiple suffixes with a comma (,) between each.';
$lang->mention_suffix_always_cut = 'Handling nicknames with the defined suffixes';
$lang->mention_suffix_always_cut_y = 'Prioritize members\' nicknames withOUT the suffixes';
$lang->mention_suffix_always_cut_n = 'Prioritize members\' nicknames WITH the suffixes';
$lang->about_mention_suffix_always_cut = 'Decide which one should receive a notification for "@John Doe" when both John Doe and John are in your database.';
$lang->mention_limit = 'Maximum numbers of notifications';
$lang->about_mention_limit = 'To prevent a server-side overload, you can limit the maximum numbers of notifications in a single post or comment.';
$lang->ncenterlite_msg_setting_error = 'There are errors in your settings. Please check your inputs.';
$lang->ncenterlite_use_help = 'Select which kinds of notifications can be sent to the members via selected methods. Your members can personalize their settings in their own settings panel among your selections here.';
$lang->ncenterlite_use_othercomment_help = 'Send notifications to every commenter when the author of the original post leaves a comment.';
$lang->member_phone_variable = 'Variable of member\'s phone number';
$lang->member_phone_variable_about = 'Define where the phone number will be referred. Either member\'s account information or the extended variable of the post can be selected.<br />If there is only one extended variable in the form of a phone number, the settings are automatically saved on installation.';
$lang->member_phone_builtin_field = 'Phone number in the member\'s account information';
$lang->anonymous_voter = 'anonymous voter';
$lang->about_anonymous_voter = 'anonymize voter in vote notification';
$lang->anonymous_scrap = 'anonymous scrap';
@ -152,6 +185,16 @@ $lang->cmd_web_notify = 'Web';
$lang->cmd_mail_notify = 'Email';
$lang->cmd_sms_notify = 'SMS';
$lang->cmd_push_notify = 'Push';
$lang->msg_denger_rhymix_user = '<strong>Warning!</strong> Rhymix includes notification center by default.<br />Please remove this XE-only module and reinstall the Rhymix native version.';
$lang->ncenterlite_content_type = 'Type of the contents';
$lang->msg_unsubscribe_not_in_list = 'This contents is not in the unsubscribed list.';
$lang->ncenterlite_type_id = 'Notification Type ID';
$lang->ncenterlite_type_objects = 'Value of Notification Type Variable';
$lang->ncenterlite_type_content = 'Content of Notification Type';
$lang->ncenterlite_notify_type = 'List of Notification Type';
$lang->msg_do_not_notify_type = 'There is no matched type for generating a notification.';
$lang->ncenterlite_custom_list = 'Tailored list';
$lang->msg_not_use_user_setting = 'You cannot change your notification settings. Please contact your administrator.';
$lang->msg_denger_rhymix_user = '<strong>Warning!</strong> Rhymix already includes the notification center as a default module.<br />Please remove this XE-only module and reinstall the Rhymix bundled version.';
$lang->msg_test_notifycation_success = 'A dummy notification was successfully generated.';
$lang->msg_unsubscribe_block_not_support = 'You are not allowed to turn off your notification. Please refer to the website administrator.';
$lang->msg_unsubscribe_not_permission = 'You are not allowed to see the other members\' subscription lists.';
$lang->msg_unsubscribe_not_in_list = 'This content is not on the unsubscribed list.';

View file

@ -57,12 +57,9 @@ class NcenterliteAdminController extends Ncenterlite
}
}
if ($obj->disp_act == 'dispNcenterliteAdminNotifyConfig')
if ($obj->disp_act === 'dispNcenterliteAdminConfig')
{
if (!$obj->use)
{
$config->use = array();
}
$config->{'use'} = $obj->{'use'} ?? [];
}
if ($obj->disp_act == 'dispNcenterliteAdminAdvancedconfig')

View file

@ -1918,7 +1918,7 @@ class NcenterliteController extends Ncenterlite
*/
protected static function _createSummary($str): string
{
$str = escape(utf8_normalize_spaces(trim(strip_tags($str)), false));
$str = escape(utf8_normalize_spaces(trim(strip_tags($str))), false);
if (function_exists('mb_strimwidth'))
{
return mb_strimwidth($str, 0, 50, '...', 'UTF-8');
@ -1937,7 +1937,7 @@ class NcenterliteController extends Ncenterlite
*/
protected static function _createContent($str): string
{
$str = escape(utf8_normalize_spaces(trim(strip_tags($str)), false));
$str = escape(utf8_normalize_spaces(trim(strip_tags($str))), false);
if (function_exists('mb_strimwidth'))
{
return mb_strimwidth($str, 0, 200, '...', 'UTF-8');

View file

@ -3,7 +3,7 @@
<grants>
<grant name="modify" default="manager">
<title xml:lang="ko">페이지 수정</title>
<title xml:lang="en">page modify</title>
<title xml:lang="en">Edit Page</title>
</grant>
</grants>
<actions>

View file

@ -309,15 +309,10 @@ class PageAdminController extends Page
function procPageAdminArticleDocumentInsert()
{
$oDocumentModel = getModel('document');
$oDocumentController = getController('document');
// Check privileges
$logged_info = Context::get('logged_info');
$oModuleModel = getModel('module');
$grant = $oModuleModel->getGrant($this->module_info, $logged_info);
if(!$grant->manager)
$grant = ModuleModel::getGrant($this->module_info, $logged_info);
if(!$grant->manager && !$grant->modify)
{
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
@ -326,43 +321,60 @@ class PageAdminController extends Page
$obj->module_srl = $this->module_info->module_srl;
$obj->is_notice = 'N';
settype($obj->title, "string");
if($obj->title == '') $obj->title = cut_str(strip_tags($obj->content),20,'...');
//그래도 없으면 Untitled
if($obj->title == '') $obj->title = 'Untitled';
// If the tile is empty, extract string from the contents.
$obj->title = escape($obj->title, false);
if ($obj->title === '')
{
$obj->title = escape(cut_str(trim(utf8_normalize_spaces(strip_tags($obj->content))), 20, '...'), false);
}
if ($obj->title === '')
{
$obj->title = 'Untitled';
}
$document_srl = $obj->document_srl;
// Check original document
$oDocument = DocumentModel::getDocument($obj->document_srl);
if ($oDocument->isExists() && $oDocument->get('module_srl') != $this->module_info->module_srl)
{
throw new Rhymix\Framework\Exceptions\NotPermitted;
}
// 이미 존재하는 글인지 체크
$oDocument = $oDocumentModel->getDocument($obj->document_srl);
$bAnonymous = false;
$target = ($obj->isMobile == 'Y') ? 'mdocument_srl' : 'document_srl';
// 이미 존재하는 경우 수정
if($oDocument->isExists() && $oDocument->document_srl == $obj->document_srl)
// Insert or update document
$oDocumentController = DocumentController::getInstance();
if ($oDocument->isExists())
{
$output = $oDocumentController->updateDocument($oDocument, $obj);
if (!$output->toBool())
{
return $output;
}
$msg_code = 'success_updated';
$document_srl = $obj->document_srl;
}
else
{
// 그렇지 않으면 신규 등록
$output = $oDocumentController->insertDocument($obj, $bAnonymous);
$output = $oDocumentController->insertDocument($obj);
if (!$output->toBool())
{
return $output;
}
$msg_code = 'success_registed';
$document_srl = $output->get('document_srl');
}
// Update module info
$target = ($obj->isMobile == 'Y') ? 'mdocument_srl' : 'document_srl';
if(!isset($this->module_info->{$target}) || (isset($this->module_info->{$target}) && $this->module_info->{$target} !== $document_srl))
{
$oModuleController = getController('module');
$this->module_info->{$target} = $document_srl;
$oModuleController->updateModule($this->module_info);
$oModuleController = ModuleController::getInstance();
$output = $oModuleController->updateModule($this->module_info);
if (!$output->toBool())
{
return $output;
}
}
// 오류 발생시 멈춤
if(!$output->toBool()) return $output;
// 결과를 리턴
$this->add('mid', Context::get('mid'));
$this->add('document_srl', $output->get('document_srl'));

View file

@ -1,7 +1,8 @@
<block cond="$oDocument">
<h1 cond="($module_info->display_title ?? '') !== 'hide'">{$oDocument->getTitle()}</h1>
{$oDocument->getContent(false)}
</block>
<block cond="!$oDocument">
{$lang->none_content}
</block>
<!--@if($oDocument && $oDocument->isExists())-->
<!--@if(($module_info->display_title ?? '') !== 'hide')-->
<h1>{$oDocument->getTitle()}</h1>
<!--@endif-->
{$oDocument->getContent(false)}
<!--@else-->
{$lang->none_content}
<!--@endif-->

View file

@ -15,4 +15,13 @@
<!--@end-->
</span>
</div>
<!--@elseif($grant->modify && $module_info->page_type === 'ARTICLE')-->
<div class="btnArea">
<span class="btn-group">
<a class="btn" href="{getUrl('act','dispPageAdminContentModify','document_srl','')}">{$lang->cmd_page_modify}</a>
<!--@if($module_info->use_mobile === 'Y')-->
<a class="btn" href="{getUrl('act','dispPageAdminMobileContent','module_srl',$module_info->module_srl)}">{$lang->mobile}</a>
<!--@end-->
</span>
</div>
<!--@end-->

View file

@ -71,7 +71,14 @@ jQuery(function($){
<!--@end-->
</td>
<td>{$lang->page_type_name[$val->page_type] ?? $val->page_type}</td>
<td class="domain_prefix"><span class="domain">{$val->domain ?? ''}</span>{\RX_BASEURL}</td>
<td class="domain_prefix">
{@
if (isset($val->domain_srl) && $val->domain_srl > -1 && !isset($val->domain)):
$val->domain = lang('deleted_domain');
endif;
}
<span class="domain">{$val->domain ?? ''}</span>{\RX_BASEURL}
</td>
<td>{$val->mid}</td>
<td><a href="{getSiteUrl($val->domain,'','mid',$val->mid)}" target="_blank">{$val->browser_title}</a></td>
<td>{zdate($val->regdate,"Y-m-d")}</td>

View file

@ -19,8 +19,13 @@
<div class="x_controls">
<select name="domain_srl" id="domain_srl">
<option value="-1" selected="selected"|cond="!isset($module_info->domain_srl) || $module_info->domain_srl == -1">{$lang->cmd_any_domain}</option>
{@ $domain_srl_list = []}
<!--@foreach(ModuleModel::getAllDomains(100)->data as $domain)-->
<option value="{$domain->domain_srl}" selected="selected"|cond="$domain->domain_srl == $module_info->domain_srl">{$domain->domain}</option>
{@ $domain_srl_list[] = $domain->domain_srl}
<!--@endif-->
<!--@if(isset($module_info->domain_srl) && $module_info->domain_srl > -1 && !in_array($module_info->domain_srl, $domain_srl_list))-->
<option value="-1" selected="selected">{$lang->deleted_domain}</option>
<!--@endif-->
</select>
<span class="baseurl">{\RX_BASEURL}<!--@if(!config('url.rewrite'))-->index.php?mid=<!--@endif--></span>

View file

@ -38,22 +38,22 @@ $lang->point_group_ratchet_no = 'Move to lower group if point is reduced';
$lang->about_point_link_group = 'If you specify level for a specific group, users are assigned into the group when they advance to the level by getting points.';
$lang->about_module_point = 'You can set point for each module, and modules which don\'t have any value will use the default point. All points will be restored on acting reverse.';
$lang->point_signup = 'Sign Up';
$lang->point_insert_document = 'Writing a document';
$lang->point_delete_document = 'Deleting a document';
$lang->point_insert_document = 'Writing a post';
$lang->point_delete_document = 'Deleting a post';
$lang->point_insert_comment = 'Writing a comment';
$lang->point_delete_comment = 'Deleting a comment';
$lang->point_upload_file = 'Uploading a file';
$lang->point_delete_file = 'Deleting a file';
$lang->point_download_file = 'Downloading a file (excluding images)';
$lang->point_read_document = 'Reading another person\'s post';
$lang->point_voter = 'Upvoting another person\'s document';
$lang->point_blamer = 'Downvoting another person\'s document';
$lang->point_voter = 'Upvoting another person\'s post';
$lang->point_blamer = 'Downvoting another person\'s post';
$lang->point_voter_comment = 'Upvoting another person\'s comment';
$lang->point_blamer_comment = 'Downvoting another person\'s comment';
$lang->point_download_file_author = 'Downloaded by others (without images)';
$lang->point_read_document_author = 'Read by others';
$lang->point_voted = 'One\'s document is upvoted';
$lang->point_blamed = 'One\'s document is downvoted';
$lang->point_voted = 'One\'s post is upvoted';
$lang->point_blamed = 'One\'s post is downvoted';
$lang->point_voted_comment = 'One\'s comment is upvoted';
$lang->point_blamed_comment = 'One\'s comment is downvoted';
$lang->cmd_point_config = 'Default Setting';

View file

@ -11,6 +11,7 @@ $lang->success_poll = 'Thank you for joining the poll.';
$lang->msg_already_poll = 'You already polled!';
$lang->msg_poll_is_null = 'Please select a poll to delete.';
$lang->msg_checked_poll_is_deleted = '%d poll(s) are deleted.';
$lang->confirm_poll_delete = 'Are you sure to delete %s of poll(s)?';
$lang->msg_check_poll_item = 'Please select a poll item to poll.\\n(Required poll item(s) may be different in each poll.)';
$lang->msg_poll_not_exists = 'The selected poll does not exist.';
$lang->cmd_null_item = 'No item value exists to post a poll. Please re-try.';

View file

@ -3,15 +3,15 @@ $lang->feed = 'Publish RSS Feed';
$lang->total_feed = 'Aggregated Feeds';
$lang->rss_disable = 'Disable RSS Feed';
$lang->feed_copyright = 'Copyright';
$lang->feed_document_count = 'Number of articles per page';
$lang->feed_document_count = 'Number of Articles per Page';
$lang->feed_image = 'Feed Image';
$lang->rss_type = 'RSS feed type';
$lang->rss_type = 'RSS Feed Type';
$lang->module_feed_management = 'Feeds for Each Module';
$lang->open_rss = 'Open RSS';
$lang->open_rss_types['Y'] = 'Open all';
$lang->open_rss_types['H'] = 'Open summary';
$lang->open_rss_types['N'] = 'Not open';
$lang->open_feed_to_total = 'Included in aggregated feed';
$lang->open_rss_types['Y'] = 'Full';
$lang->open_rss_types['H'] = 'Summary';
$lang->open_rss_types['N'] = 'Not Open';
$lang->open_feed_to_total = 'Included in Aggregated Feed';
$lang->about_rss_disable = 'If checked, RSS will be disabled.';
$lang->about_rss_type = 'You can assign RSS feed type.';
$lang->about_open_rss = 'You can select RSS on the current page to be open to the public.\\nIf it is enabled, the article will be open to the public despite its view permissions.';

View file

@ -32,7 +32,7 @@ class reCAPTCHA
'secret' => self::$config->secret_key,
'response' => $response,
'remoteip' => \RX_CLIENT_IP,
]);
], [], [], ['timeout' => 10]);
if ($verify_request->getStatusCode() !== 200 || !$verify_request->getBody())
{
throw new Exception('msg_recaptcha_connection_error');

View file

@ -38,7 +38,7 @@ class Turnstile
'secret' => self::$config->secret_key,
'response' => $response,
'remoteip' => \RX_CLIENT_IP,
]);
], [], [], ['timeout' => 10]);
if ($verify_request->getStatusCode() !== 200 || !$verify_request->getBody())
{
throw new Exception('msg_recaptcha_connection_error');

View file

@ -2,7 +2,7 @@
$lang->tag_default_config = 'Default Config';
$lang->tag_separators = 'Tag Separators';
$lang->tag_separator_comma = 'comma(foo, bar)';
$lang->tag_separator_hash = 'hash(#foo #bar)';
$lang->tag_separator_space = 'space';
$lang->tag_separator_comma = 'Comma (foo, bar)';
$lang->tag_separator_hash = 'Hash (#foo #bar)';
$lang->tag_separator_space = 'Space (foo bar)';
$lang->tag_separator_help = 'If you select more than one type of separator, all of them will be recognized. For example, &quot;#foo,bar Rhymix&quot;';

View file

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="0.2">
<title xml:lang="ko">휴지통</title>
<title xml:lang="en">trash</title>
<title xml:lang="en">Recycle Bin</title>
<title xml:lang="jp">ゴミ箱</title>
<title xml:lang="zh-TW">回收桶</title>
<description xml:lang="ko">문서, 댓글 등을 완전히 삭제하지 않고 복구 가능한 상태로 만들어 관리합니다.</description>
<description xml:lang="jp">ドミュメンと、コメントなどを完全に削除せずに復旧可能な状態に作って管理します。</description>
<description xml:lang="en">Recycle Bin is a logical reservoir for deleted items, such as posts and comments, which enables the administrators to restore the deleted items.</description>
<version>RX_VERSION</version>
<date>RX_CORE</date>
<category>content</category>

Some files were not shown because too many files have changed in this diff Show more