Merge branch 'next' into next-push

This commit is contained in:
Kijin Sung 2020-06-22 16:46:38 +09:00 committed by GitHub
commit b986f826ba
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
41 changed files with 1860 additions and 931 deletions

View file

@ -847,7 +847,8 @@ class adminAdminController extends admin
Rhymix\Framework\Config::set('locale.default_timezone', $vars->default_timezone);
// Other settings
Rhymix\Framework\Config::set('use_rewrite', $vars->use_rewrite === 'Y');
Rhymix\Framework\Config::set('url.rewrite', intval($vars->use_rewrite));
Rhymix\Framework\Config::set('use_rewrite', $vars->use_rewrite > 0);
Rhymix\Framework\Config::set('session.delay', $vars->delay_session === 'Y');
Rhymix\Framework\Config::set('session.use_db', $vars->use_db_session === 'Y');
Rhymix\Framework\Config::set('view.manager_layout', $vars->manager_layout ?: 'module');

View file

@ -312,7 +312,26 @@ class adminAdminView extends admin
{
$needUpdate = FALSE;
$addTables = FALSE;
foreach($module_list AS $key => $value)
$priority = array(
'module' => 1000000,
'member' => 100000,
'document' => 10000,
'comment' => 1000,
'file' => 100,
);
usort($module_list, function($a, $b) use($priority) {
$a_priority = isset($priority[$a->module]) ? $priority[$a->module] : 0;
$b_priority = isset($priority[$b->module]) ? $priority[$b->module] : 0;
if ($a_priority == 0 && $b_priority == 0)
{
return strcmp($a->module, $b->module);
}
else
{
return $b_priority - $a_priority;
}
});
foreach($module_list as $value)
{
if($value->need_install)
{
@ -556,7 +575,7 @@ class adminAdminView extends admin
Context::set('selected_timezone', Rhymix\Framework\Config::get('locale.default_timezone'));
// Other settings
Context::set('use_rewrite', Rhymix\Framework\Config::get('use_rewrite'));
Context::set('use_rewrite', Rhymix\Framework\Router::getRewriteLevel());
Context::set('use_mobile_view', (config('mobile.enabled') !== null ? config('mobile.enabled') : config('use_mobile_view')) ? true : false);
Context::set('tablets_as_mobile', config('mobile.tablets') ? true : false);
Context::set('mobile_viewport', config('mobile.viewport') ?: 'width=device-width, initial-scale=1.0, user-scalable=yes');

View file

@ -264,7 +264,11 @@ $lang->trash = 'Recycle Bin';
$lang->accusation = 'Report';
$lang->status = 'Status';
$lang->action = 'Execute';
$lang->use_rewrite = 'Use Rewrite Mode';
$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->timezone = 'Time Zone';
$lang->use_mobile_view = 'Enable Mobile View';
$lang->about_use_mobile_view = 'Show mobile page when visitors access with mobile devices.';

View file

@ -261,6 +261,10 @@ $lang->accusation = '신고';
$lang->status = '상태';
$lang->action = '실행';
$lang->use_rewrite = '짧은 주소 사용';
$lang->use_rewrite_0 = '사용하지 않음';
$lang->use_rewrite_1 = 'XE와 호환되는 주소 형태만 사용';
$lang->use_rewrite_2 = '모든 주소 형태를 사용';
$lang->about_use_rewrite = '짧은 주소를 사용하려면 웹서버에서 rewrite 기능을 지원해야 합니다. 아파치의 경우 .htaccess 파일이 있으면 대부분 자동으로 인식합니다.<br />nginx 사용시 <a href="https://github.com/rhymix/rhymix-docs/blob/master/ko/introduction/nginx.md> target="_blank">매뉴얼</a>을 참고하여 직접 설정하셔야 합니다. 구 버전의 nginx 설정은 XE와 호환되는 주소만 지원하니 주의하십시오.';
$lang->timezone = '표준 시간대';
$lang->use_mobile_view = '모바일 뷰 사용';
$lang->about_use_mobile_view = '모바일 기기로 접속시 모바일 페이지를 보여줍니다.';

View file

@ -13,8 +13,10 @@
<div class="x_control-group">
<label class="x_control-label">{$lang->use_rewrite}</label>
<div class="x_controls">
<label for="use_rewrite_y" class="x_inline"><input type="radio" name="use_rewrite" id="use_rewrite_y" value="Y" checked="checked"|cond="$use_rewrite" /> {$lang->cmd_yes}</label>
<label for="use_rewrite_n" class="x_inline"><input type="radio" name="use_rewrite" id="use_rewrite_n" value="N" checked="checked"|cond="!$use_rewrite" /> {$lang->cmd_no}</label>
<label for="use_rewrite_0" class="x_inline"><input type="radio" name="use_rewrite" id="use_rewrite_0" value="0" checked="checked"|cond="$use_rewrite == 0" /> {$lang->use_rewrite_0}</label>
<label for="use_rewrite_1" class="x_inline"><input type="radio" name="use_rewrite" id="use_rewrite_1" value="1" checked="checked"|cond="$use_rewrite == 1" /> {$lang->use_rewrite_1}</label>
<label for="use_rewrite_2" class="x_inline"><input type="radio" name="use_rewrite" id="use_rewrite_2" value="2" checked="checked"|cond="$use_rewrite == 2" /> {$lang->use_rewrite_2}</label>
<p class="x_help-block">{$lang->about_use_rewrite}</p>
</div>
</div>
<div class="x_control-group">

View file

@ -25,18 +25,6 @@ class board extends ModuleObject
*/
function __construct()
{
if(!Context::isInstalled()) return;
if(!Context::isExistsSSLAction('dispBoardWrite') && Context::getSslStatus() == 'optional')
{
$ssl_actions = array('dispBoardWrite', 'dispBoardWriteComment', 'dispBoardReplyComment', 'dispBoardModifyComment', 'dispBoardDelete', 'dispBoardDeleteComment', 'procBoardInsertDocument', 'procBoardDeleteDocument', 'procBoardInsertComment', 'procBoardDeleteComment', 'procBoardVerificationPassword');
Context::addSSLActions($ssl_actions);
}
if(!Context::isExistsSSLAction('dispTempSavedList') && Context::getSslStatus() == 'optional')
{
Context::addSSLAction('dispTempSavedList');
}
parent::__construct();
}

View file

@ -1364,6 +1364,11 @@ class boardView extends board
Context::set('blame_member_info', $blame_member_infos);
$this->setTemplateFile('vote_log');
}
function dispBoardNotFound()
{
$this->alertMessage('msg_not_founded', 404);
}
/**
* @brief the method for displaying the warning messages

View file

@ -56,19 +56,43 @@
</grant>
</grants>
<actions>
<action name="dispBoardContent" type="view" permission="list" standalone="false" index="true" />
<action name="dispBoardWrite" type="view" permission="write_document" standalone="false" meta-noindex="true" />
<action name="dispBoardDelete" type="view" permission="write_document" standalone="false" meta-noindex="true" />
<action name="dispBoardWriteComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" />
<action name="dispBoardReplyComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" />
<action name="dispBoardModifyComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" />
<action name="dispBoardDeleteComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" />
<action name="dispBoardDeleteTrackback" type="view" permission="list,view" standalone="false" meta-noindex="true" />
<action name="dispBoardContent" type="view" permission="list" standalone="false" index="true">
<route route="$document_srl:int" priority="100" />
<route route="$document_srl:int/comment/$comment_srl:int" priority="100" />
<route route="$document_srl:int/page/$page:int" priority="100" />
<route route="category/$category:int/search/$search_target:word/$search_keyword:any" priority="60" />
<route route="category/$category:int/search/$search_target:word/$search_keyword:any/page/$page:int" priority="60" />
<route route="search/$search_target:word/$search_keyword:any" priority="50" />
<route route="search/$search_target:word/$search_keyword:any/page/$page:int" priority="50" />
<route route="category/$category:int" priority="40" />
<route route="category/$category:int/page/$page:int" priority="40" />
<route route="page/$page:int" priority="10" />
</action>
<action name="dispBoardWrite" type="view" permission="write_document" standalone="false" meta-noindex="true" use-ssl="true">
<route route="write" />
<route route="$document_srl/edit" />
</action>
<action name="dispBoardDelete" type="view" permission="write_document" standalone="false" meta-noindex="true" use-ssl="true" route="$document_srl/delete" />
<action name="dispBoardWriteComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" use-ssl="true" route="$document_srl/comment" />
<action name="dispBoardReplyComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" use-ssl="true">
<route route="comment/$comment_srl/reply" />
<route route="comment/$comment_srl/reply$document_srl:delete" />
</action>
<action name="dispBoardModifyComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" use-ssl="true">
<route route="comment/$comment_srl/edit" />
<route route="comment/$comment_srl/edit$document_srl:delete" />
</action>
<action name="dispBoardDeleteComment" type="view" permission="write_comment" standalone="false" meta-noindex="true" use-ssl="true">
<route route="comment/$comment_srl/delete" />
<route route="comment/$comment_srl/delete$document_srl:delete" />
</action>
<action name="dispBoardDeleteTrackback" type="view" permission="list,view" standalone="false" meta-noindex="true" use-ssl="true" />
<action name="dispBoardContentList" type="view" permission="list" standalone="false" />
<action name="dispBoardContentView" type="view" permission="view" standalone="false" />
<action name="dispBoardUpdateLog" type="view" permission="update_view" standalone="false" />
<action name="dispBoardUpdateLogView" type="view" permission="update_view" standalone="false" />
<action name="dispBoardVoteLog" type="view" permission="vote_log_view" standalone="false" />
<action name="dispBoardNotFound" type="view" standalone="false" error-handlers="404" />
<action name="dispBoardNoticeList" type="view" permission="list" standalone="false" />
<action name="dispBoardCategoryList" type="view" permission="list" standalone="false" />
@ -79,13 +103,13 @@
<action name="dispBoardCommentPage" type="view" permission="view" standalone="false" />
<action name="getBoardCommentPage" type="mobile" permission="view" standalone="false" />
<action name="procBoardInsertDocument" type="controller" permission="write_document" standalone="false" ruleset="insertDocument" />
<action name="procBoardDeleteDocument" type="controller" permission="write_document" standalone="false" />
<action name="procBoardRevertDocument" type="controller" permission="update_view" standalone="false" />
<action name="procBoardInsertComment" type="controller" permission="write_comment" standalone="false" />
<action name="procBoardDeleteComment" type="controller" permission="write_comment" standalone="false" />
<action name="procBoardDeleteTrackback" type="controller" permission="list,view" standalone="false" />
<action name="procBoardVerificationPassword" type="controller" permission="view" standalone="false" />
<action name="procBoardInsertDocument" type="controller" permission="write_document" standalone="false" use-ssl="true" ruleset="insertDocument" />
<action name="procBoardDeleteDocument" type="controller" permission="write_document" standalone="false" use-ssl="true" />
<action name="procBoardRevertDocument" type="controller" permission="update_view" standalone="false" use-ssl="true" />
<action name="procBoardInsertComment" type="controller" permission="write_comment" standalone="false" use-ssl="true" />
<action name="procBoardDeleteComment" type="controller" permission="write_comment" standalone="false" use-ssl="true" />
<action name="procBoardDeleteTrackback" type="controller" permission="list,view" standalone="false" use-ssl="true" />
<action name="procBoardVerificationPassword" type="controller" permission="view" standalone="false" use-ssl="true" />
<action name="procBoardVoteDocument" type="controller" permission="view" standalone="false" />
<action name="dispBoardAdminContent" type="view" admin_index="true" menu_name="board" menu_index="true" />
@ -102,7 +126,7 @@
<action name="getBoardAdminSimpleSetup" type="model" simple_setup_index="true" />
<action name="procBoardAdminInsertBoard" type="controller" permission="manager" check_var="module_srl" ruleset="insertBoard" />
<action name="procBoardAdminDeleteBoard" type="controller" />
<action name="procBoardAdminDeleteBoard" type="controller" permission="manager" check_var="module_srl" />
<action name="procBoardAdminUpdateBoardFroBasic" type="controller" ruleset="insertBoardForBasic" />
<action name="procBoardAdminSaveCategorySettings" type="controller" permission="manager" check_var="module_srl" ruleset="saveCategorySettings" />
</actions>

View file

@ -378,16 +378,13 @@ class communicationModel extends communication
$args = new stdClass();
$args->member_srl = $logged_info->member_srl;
$output = executeQueryArray('communication.getFriendGroups', $args);
$group_list = $output->data;
if(!$group_list)
$friend_group_list = array();
foreach ($output->data as $item)
{
return;
$friend_group_list[$item->friend_group_srl] = $item;
}
return $group_list;
return $friend_group_list;
}
/**

View file

@ -294,14 +294,7 @@ class communicationView extends communication
$oCommunicationModel = getModel('communication');
// get a group list
$tmp_group_list = $oCommunicationModel->getFriendGroups();
$group_count = count($tmp_group_list);
for($i = 0; $i < $group_count; $i++)
{
$friend_group_list[$tmp_group_list[$i]->friend_group_srl] = $tmp_group_list[$i];
}
$friend_group_list = $oCommunicationModel->getFriendGroups();
Context::set('friend_group_list', $friend_group_list);
// get a list of friends

View file

@ -4,7 +4,7 @@
<actions>
<action name="dispDocumentPrint" type="view" meta-noindex="true"/>
<action name="dispDocumentPreview" type="view" meta-noindex="true"/>
<action name="dispTempSavedList" type="view" permission="member" meta-noindex="true"/>
<action name="dispTempSavedList" type="view" permission="member" meta-noindex="true" use-ssl="true" />
<action name="dispDocumentDeclare" type="view" permission="member" meta-noindex="true" />
<action name="dispDocumentManageDocument" type="view" permission="all-managers" meta-noindex="true" />

View file

@ -49,9 +49,10 @@
html {
&.cke_panel_container, &.cke_panel_container body {
background-color: #fff;
.light_dark(default);
}
body.cke_editable {
min-height: 100vh;
padding: 10px;
.light_dark(@colorset);
}

View file

@ -24,7 +24,9 @@ class installAdminController extends install
$oInstallController = getController('install');
$oInstallController->installModule($module_name, './modules/'.$module_name);
$oModuleController = getController('module');
$oModuleController->registerActionForwardRoutes($module_name);
$oModuleController->registerSecureActions($module_name);
$this->setMessage('success_installed');
}
@ -41,13 +43,29 @@ class installAdminController extends install
if(!$oModule) throw new Rhymix\Framework\Exceptions\InvalidRequest;
Rhymix\Framework\Session::close();
$output = $oModule->moduleUpdate();
Rhymix\Framework\Session::start();
if($output instanceof BaseObject && !$output->toBool())
{
Rhymix\Framework\Session::start();
return $output;
}
$oModuleController = getController('module');
$output = $oModuleController->registerActionForwardRoutes($module_name);
if($output instanceof BaseObject && !$output->toBool())
{
Rhymix\Framework\Session::start();
return $output;
}
$output = $oModuleController->registerSecureActions($module_name);
if($output instanceof BaseObject && !$output->toBool())
{
Rhymix\Framework\Session::start();
return $output;
}
Rhymix\Framework\Session::start();
$this->setMessage('success_updated');
}

View file

@ -2,7 +2,11 @@
<module>
<grants />
<actions>
<action name="IS" type="view" meta-noindex="true" />
<action name="IS" type="view" meta-noindex="true" global-route="true">
<route route="search" />
<route route="search/$search_keyword" />
<route route="search/$search_target:word/$search_keyword" />
</action>
<action name="dispIntegration_searchAdminContent" type="view" admin_index="true" />
<action name="dispIntegration_searchAdminSkinInfo" type="view" />

View file

@ -38,6 +38,7 @@ class integration_search extends ModuleObject
if(is_dir($template_path)) return true;
}
}
return false;
}

View file

@ -2,44 +2,44 @@
<module>
<grants />
<actions>
<action name="dispMemberSignUpForm" type="view" meta-noindex="true" />
<action name="dispMemberLoginForm" type="view" meta-noindex="true" />
<action name="dispMemberFindAccount" type="view" meta-noindex="true" />
<action name="dispMemberResendAuthMail" type="view" meta-noindex="true" />
<action name="dispMemberInfo" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberModifyInfo" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberModifyPassword" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberModifyEmailAddress" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberLeave" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberScrappedDocument" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberSavedDocument" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberOwnDocument" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberOwnComment" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberActiveLogins" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberModifyNicknameLog" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberSignUpForm" type="view" meta-noindex="true" use-ssl="true" route="signup" />
<action name="dispMemberLoginForm" type="view" meta-noindex="true" use-ssl="true" route="login" />
<action name="dispMemberFindAccount" type="view" meta-noindex="true" use-ssl="true" />
<action name="dispMemberResendAuthMail" type="view" meta-noindex="true" use-ssl="true" />
<action name="dispMemberInfo" type="view" permission="member" meta-noindex="true" route="member_info" />
<action name="dispMemberModifyInfo" type="view" permission="member" meta-noindex="true" use-ssl="true" />
<action name="dispMemberModifyPassword" type="view" permission="member" meta-noindex="true" use-ssl="true" />
<action name="dispMemberModifyEmailAddress" type="view" permission="member" meta-noindex="true" use-ssl="true" />
<action name="dispMemberLeave" type="view" permission="member" meta-noindex="true" use-ssl="true" />
<action name="dispMemberScrappedDocument" type="view" permission="member" meta-noindex="true" use-ssl="true" route="my_scrap" />
<action name="dispMemberSavedDocument" type="view" permission="member" meta-noindex="true" use-ssl="true" route="my_saved_documents" />
<action name="dispMemberOwnDocument" type="view" permission="member" meta-noindex="true" use-ssl="true" route="my_documents" />
<action name="dispMemberOwnComment" type="view" permission="member" meta-noindex="true" use-ssl="true" route="my_comments" />
<action name="dispMemberActiveLogins" type="view" permission="member" meta-noindex="true" use-ssl="true" route="active_logins" />
<action name="dispMemberModifyNicknameLog" type="view" permission="member" meta-noindex="true" use-ssl="true" />
<action name="dispMemberLogout" type="view" permission="member" meta-noindex="true" />
<action name="dispMemberSpammer" type="view" permission="manager" check_var="module_srl" meta-noindex="true" />
<action name="getMemberMenu" type="model" />
<action name="getApiGroups" type="model" permission="root" />
<action name="procMemberInsert" type="controller" ruleset="@insertMember" />
<action name="procMemberInsert" type="controller" ruleset="@insertMember" use-ssl="true" route="signup" />
<action name="procMemberCheckValue" type="controller" />
<action name="procMemberLogin" type="controller" ruleset="@login" />
<action name="procMemberLogin" type="controller" ruleset="@login" use-ssl="true" route="login" />
<action name="procMemberRegisterDevice" type="controller" />
<action name="procMemberLoginWithDevice " type="controller" />
<action name="procMemberFindAccount" type="controller" method="GET|POST" ruleset="findAccount" />
<action name="procMemberFindAccountByQuestion" type="controller" method="GET|POST" />
<action name="procMemberAuthAccount" type="controller" method="GET|POST" />
<action name="procMemberAuthEmailAddress" type="controller" method="GET|POST" />
<action name="procMemberResendAuthMail" type="controller" ruleset="resendAuthMail" />
<action name="procMemberSendVerificationSMS" type="controller" />
<action name="procMemberConfirmVerificationSMS" type="controller" />
<action name="procMemberModifyInfoBefore" type="controller" permission="member" ruleset="recheckedPassword" />
<action name="procMemberModifyInfo" type="controller" permission="member" ruleset="@insertMember" />
<action name="procMemberModifyPassword" type="controller" permission="member" ruleset="modifyPassword" />
<action name="procMemberModifyEmailAddress" type="controller" permission="member" ruleset="modifyEmailAddress" />
<action name="procMemberLeave" type="controller" permission="member" ruleset="leaveMember" />
<action name="procMemberFindAccount" type="controller" method="GET|POST" ruleset="findAccount" use-ssl="true" />
<action name="procMemberFindAccountByQuestion" type="controller" method="GET|POST" use-ssl="true" />
<action name="procMemberAuthAccount" type="controller" method="GET|POST" use-ssl="true" />
<action name="procMemberAuthEmailAddress" type="controller" method="GET|POST" use-ssl="true" />
<action name="procMemberResendAuthMail" type="controller" ruleset="resendAuthMail" use-ssl="true" />
<action name="procMemberSendVerificationSMS" type="controller" use-ssl="true" />
<action name="procMemberConfirmVerificationSMS" type="controller" use-ssl="true" />
<action name="procMemberModifyInfoBefore" type="controller" permission="member" ruleset="recheckedPassword" use-ssl="true" />
<action name="procMemberModifyInfo" type="controller" permission="member" ruleset="@insertMember" use-ssl="true" />
<action name="procMemberModifyPassword" type="controller" permission="member" ruleset="modifyPassword" use-ssl="true" />
<action name="procMemberModifyEmailAddress" type="controller" permission="member" ruleset="modifyEmailAddress" use-ssl="true" />
<action name="procMemberLeave" type="controller" permission="member" ruleset="leaveMember" use-ssl="true" />
<action name="procMemberInsertProfileImage" type="controller" permission="member" ruleset="insertProfileImage" />
<action name="procMemberDeleteProfileImage" type="controller" permission="member" />
<action name="procMemberInsertImageName" type="controller" permission="member" ruleset="insertImageName" />

View file

@ -20,15 +20,6 @@ class member extends ModuleObject {
*/
function __construct()
{
if(!Context::isInstalled()) return;
// Set to use SSL upon actions related member join/information/password and so on. 2013.02.15
if(!Context::isExistsSSLAction('dispMemberModifyPassword') && Context::getSslStatus() == 'optional')
{
$ssl_actions = array('dispMemberModifyPassword', 'dispMemberSignUpForm', 'dispMemberModifyInfo', 'dispMemberModifyEmailAddress', 'dispMemberResendAuthMail', 'dispMemberLoginForm', 'dispMemberFindAccount', 'dispMemberLeave', 'procMemberLogin', 'procMemberModifyPassword', 'procMemberInsert', 'procMemberModifyInfo', 'procMemberFindAccount', 'procMemberModifyEmailAddress', 'procMemberResendAuthMail', 'procMemberLeave'/*, 'getMemberMenu'*/, 'procMemberFindAccountByQuestion');
Context::addSSLActions($ssl_actions);
}
parent::__construct();
}

View file

@ -131,6 +131,11 @@ class module extends ModuleObject
{
return true;
}
// check route columns in action_forward table
if(!$oDB->isColumnExists('action_forward', 'route_regexp')) return true;
if(!$oDB->isColumnExists('action_forward', 'route_config')) return true;
if(!$oDB->isColumnExists('action_forward', 'global_route')) return true;
}
/**
@ -448,6 +453,20 @@ class module extends ModuleObject
$oDB->addIndex('module_part_config', 'unique_module_part_config', array('module', 'module_srl'), false);
}
}
// check route columns in action_forward table
if(!$oDB->isColumnExists('action_forward', 'route_regexp'))
{
$oDB->addColumn('action_forward', 'route_regexp', 'text');
}
if(!$oDB->isColumnExists('action_forward', 'route_config'))
{
$oDB->addColumn('action_forward', 'route_config', 'text');
}
if(!$oDB->isColumnExists('action_forward', 'global_route'))
{
$oDB->addColumn('action_forward', 'global_route', 'char', 1, 'N', true);
}
}
/**

View file

@ -19,13 +19,15 @@ class moduleController extends module
* Action forward finds and forwards if an action is not in the requested module
* This is used when installing a module
*/
function insertActionForward($module, $type, $act)
function insertActionForward($module, $type, $act, $route_regexp = null, $route_config = null, $global_route = 'N')
{
$args = new stdClass();
$args->module = $module;
$args->type = $type;
$args->act = $act;
$args->route_regexp = is_scalar($route_regexp) ? $route_regexp : serialize($route_regexp);
$args->route_config = is_scalar($route_config) ? $route_config : serialize($route_config);
$args->global_route = $global_route === 'Y' ? 'Y' : 'N';
$output = executeQuery('module.insertActionForward', $args);
Rhymix\Framework\Cache::delete('action_forward');
@ -48,6 +50,32 @@ class moduleController extends module
return $output;
}
/**
* @brief Add action security
*/
function insertActionSecurity($act)
{
$args = new stdClass();
$args->act = $act;
$output = executeQuery('module.insertActionSecurity', $args);
Rhymix\Framework\Cache::delete('action_security');
return $output;
}
/**
* @brief Delete action security
*/
function deleteActionSecurity($act)
{
$args = new stdClass();
$args->act = $act;
$output = executeQuery('module.deleteActionSecurity', $args);
Rhymix\Framework\Cache::delete('action_security');
return $output;
}
/**
* @brief Add trigger callback function
*
@ -955,9 +983,8 @@ class moduleController extends module
{
$this->deleteModuleExtraVars($module_srl);
getDestroyXeVars($obj);
if(!$obj || !is_countable($obj) || !count($obj)) return;
foreach($obj as $key => $val)
foreach(get_object_vars($obj) as $key => $val)
{
if(is_object($val) || is_array($val)) continue;
@ -1289,6 +1316,102 @@ class moduleController extends module
Rhymix\Framework\Cache::clearGroup('site_and_module');
return $output;
}
/**
* Check if all action-forwardable routes are registered. If not, register them.
*
* @param string $module_name
* @return object
*/
public function registerActionForwardRoutes(string $module_name)
{
$action_forward = ModuleModel::getActionForward();
$module_action_info = ModuleModel::getModuleActionXml($module_name);
// Get the list of forwardable actions and their routes.
$forwardable_routes = array();
foreach ($module_action_info->action ?: [] as $action_name => $action_info)
{
if (count($action_info->route) && $action_info->standalone !== 'false')
{
$forwardable_routes[$action_name] = array(
'type' => $module_action_info->action->{$action_name}->type,
'regexp' => array(),
'config' => $action_info->route,
'global_route' => $action_info->global_route === 'true' ? 'Y' : 'N',
);
}
}
foreach ($module_action_info->route->GET as $regexp => $action_name)
{
if (isset($forwardable_routes[$action_name]))
{
$forwardable_routes[$action_name]['regexp'][] = ['GET', $regexp];
}
}
foreach ($module_action_info->route->POST as $regexp => $action_name)
{
if (isset($forwardable_routes[$action_name]))
{
$forwardable_routes[$action_name]['regexp'][] = ['POST', $regexp];
}
}
// Insert or delete from the action_forward table.
foreach ($forwardable_routes as $action_name => $route_info)
{
if (!isset($action_forward[$action_name]))
{
$output = $this->insertActionForward($module_name, $route_info['type'], $action_name,
$route_info['regexp'], $route_info['config'], $route_info['global_route']);
if (!$output->toBool())
{
return $output;
}
}
elseif ($action_forward[$action_name]->route_regexp !== $route_info['regexp'] ||
$action_forward[$action_name]->route_config !== $route_info['config'] ||
$action_forward[$action_name]->global_route !== $route_info['global_route'])
{
$output = $this->deleteActionForward($module_name, $route_info['type'], $action_name);
if (!$output->toBool())
{
return $output;
}
$output = $this->insertActionForward($module_name, $route_info['type'], $action_name,
$route_info['regexp'], $route_info['config'], $route_info['global_route']);
if (!$output->toBool())
{
return $output;
}
}
}
return new BaseObject();
}
/**
* Check if all secure actions are registered. If not, register them.
*
* @param string $module_name
* @return object
*/
public function registerSecureActions(string $module_name)
{
$action_security = ModuleModel::getActionSecurity();
$module_action_info = ModuleModel::getModuleActionXml($module_name);
foreach ($module_action_info->action ?: [] as $action_name => $action_info)
{
if ($action_info->use_ssl === 'true' && !isset($action_security[$action_name]))
{
$output = $this->insertActionSecurity($action_name);
}
}
return new BaseObject();
}
}
/* End of file module.controller.php */
/* Location: ./modules/module/module.controller.php */

View file

@ -211,7 +211,7 @@ class moduleModel extends module
*/
public static function getModuleInfoByMid($mid, $site_srl = 0, $columnList = array())
{
if(!$mid || ($mid && !preg_match("/^[a-z][a-z0-9_]+$/i", $mid)))
if(!$mid || ($mid && !preg_match("/^[a-z][a-z0-9_-]+$/i", $mid)))
{
return;
}
@ -567,7 +567,7 @@ class moduleModel extends module
/**
* @brief Get forward value by the value of act
*/
public static function getActionForward($act)
public static function getActionForward($act = null)
{
$action_forward = Rhymix\Framework\Cache::get('action_forward');
if($action_forward === null)
@ -582,12 +582,18 @@ class moduleModel extends module
$action_forward = array();
foreach($output->data as $item)
{
if ($item->route_regexp) $item->route_regexp = unserialize($item->route_regexp);
if ($item->route_config) $item->route_config = unserialize($item->route_config);
$action_forward[$item->act] = $item;
}
Rhymix\Framework\Cache::set('action_forward', $action_forward, 0, true);
}
if(!isset($act))
{
return $action_forward;
}
if(!isset($action_forward[$act]))
{
return;
@ -596,6 +602,38 @@ class moduleModel extends module
return $action_forward[$act];
}
/**
* @brief Get SSL action setting
*/
public static function getActionSecurity($act = null)
{
$action_security = Rhymix\Framework\Cache::get('action_security');
if($action_security === null)
{
$args = new stdClass();
$output = executeQueryArray('module.getActionSecurity', $args);
if(!$output->toBool())
{
return;
}
$action_security = array();
foreach($output->data as $item)
{
$action_security[$item->act] = true;
}
Rhymix\Framework\Cache::set('action_security', $action_security, 0, true);
}
if(!isset($act))
{
return $action_security;
}
return isset($action_security[$act]) ? true : false;
}
/**
* @brief Get trigger functions
*/
@ -686,321 +724,50 @@ class moduleModel extends module
*/
public static function getModuleInfoXml($module)
{
// Get a path of the requested module. Return if not exists.
// Check the path and XML file name.
$module_path = ModuleHandler::getModulePath($module);
if(!$module_path) return;
// Read the xml file for module skin information
$xml_file = sprintf("%s/conf/info.xml", $module_path);
if(!file_exists($xml_file)) return;
$oXmlParser = new XmlParser();
$tmp_xml_obj = $oXmlParser->loadXmlFile($xml_file);
$xml_obj = $tmp_xml_obj->module;
if(!$xml_obj) return;
// Module Information
$module_info = new stdClass();
if($xml_obj->version && $xml_obj->attrs->version == '0.2')
if (!$module_path) return;
$xml_file = $module_path . 'conf/info.xml';
if (!file_exists($xml_file)) return;
// Load the XML file and cache the definition.
$mtime1 = filemtime($xml_file);
$mtime2 = file_exists($module_path . 'conf/module.xml') ? filemtime($module_path . 'conf/module.xml') : 0;
$cache_key = sprintf('site_and_module:module_info_xml:%s:%d:%d', $module, $mtime1, $mtime2);
$info = Rhymix\Framework\Cache::get($cache_key);
if($info === null)
{
// module format 0.2
$module_info->title = $xml_obj->title->body;
$module_info->description = $xml_obj->description->body;
$module_info->version = $xml_obj->version->body;
$module_info->homepage = $xml_obj->link->body;
$module_info->category = $xml_obj->category->body;
if(!$module_info->category) $module_info->category = 'service';
$date_obj = (object)array('y' => 0, 'm' => 0, 'd' => 0);
sscanf($xml_obj->date->body, '%d-%d-%d', $date_obj->y, $date_obj->m, $date_obj->d);
$module_info->date = sprintf('%04d%02d%02d', $date_obj->y, $date_obj->m, $date_obj->d);
$module_info->license = $xml_obj->license->body;
$module_info->license_link = $xml_obj->license->attrs->link;
if(!is_array($xml_obj->author)) $author_list[] = $xml_obj->author;
else $author_list = $xml_obj->author;
foreach($author_list as $author)
{
$author_obj = new stdClass();
$author_obj->name = $author->name->body;
$author_obj->email_address = $author->attrs->email_address;
$author_obj->homepage = $author->attrs->link;
$module_info->author[] = $author_obj;
}
$info = Rhymix\Framework\Parsers\ModuleInfoParser::loadXML($xml_file);
Rhymix\Framework\Cache::set($cache_key, $info, 0, true);
}
else
{
// module format 0.1
$module_info->title = $xml_obj->title->body;
$module_info->description = $xml_obj->author->description->body;
$module_info->version = $xml_obj->attrs->version;
$module_info->category = $xml_obj->attrs->category;
if(!$module_info->category) $module_info->category = 'service';
$date_obj = (object)array('y' => 0, 'm' => 0, 'd' => 0);
sscanf($xml_obj->author->attrs->date, '%d. %d. %d', $date_obj->y, $date_obj->m, $date_obj->d);
$module_info->date = sprintf('%04d%02d%02d', $date_obj->y, $date_obj->m, $date_obj->d);
$author_obj = new stdClass();
$author_obj->name = $xml_obj->author->name->body;
$author_obj->email_address = $xml_obj->author->attrs->email_address;
$author_obj->homepage = $xml_obj->author->attrs->link;
$module_info->author[] = $author_obj;
}
// Add admin_index by using action information
$action_info = self::getModuleActionXml($module);
$module_info->admin_index_act = $action_info->admin_index_act;
$module_info->default_index_act = $action_info->default_index_act;
$module_info->setup_index_act = $action_info->setup_index_act;
$module_info->simple_setup_index_act = $action_info->simple_setup_index_act;
return $module_info;
return $info;
}
/**
* @brief Return permisson and action data by conf/module.xml in the module
* Cache it because it takes too long to parse module.xml file
* When caching, add codes so to include it directly
* This is apparently good for performance, but not sure about its side-effects
* @brief Return permisson and action data by conf/module.xml
*/
public static function getModuleActionXml($module)
{
// Get a path of the requested module. Return if not exists.
$class_path = ModuleHandler::getModulePath($module);
if(!$class_path) return;
// Check if module.xml exists in the path. Return if not exist
$xml_file = sprintf("%sconf/module.xml", $class_path);
if(!file_exists($xml_file)) return;
// Check if cached file exists
$cache_file = sprintf(_XE_PATH_ . "files/cache/module_info/%s.%s.%s.php", $module, Context::getLangType(), __XE_VERSION__);
// Update if no cache file exists or it is older than xml file
if(!file_exists($cache_file) || filemtime($cache_file) < filemtime($xml_file) || $re_cache)
// Check the path and XML file name.
$module_path = ModuleHandler::getModulePath($module);
if (!$module_path) return;
$xml_file = $module_path . 'conf/module.xml';
if (!file_exists($xml_file)) return;
// Load the XML file and cache the definition.
$mtime = filemtime($xml_file);
$cache_key = sprintf('site_and_module:module_action_xml:%s:%d', $module, $mtime);
$info = Rhymix\Framework\Cache::get($cache_key);
if($info === null)
{
$info = new stdClass();
$buff = array(); // /< Set buff variable to use in the cache file
$buff[] = '<?php if(!defined("__XE__")) exit();';
$buff[] = '$info = new stdClass;';
$buff['default_index_act'] = '$info->default_index_act = \'%s\';';
$buff['setup_index_act'] = '$info->setup_index_act=\'%s\';';
$buff['simple_setup_index_act'] = '$info->simple_setup_index_act=\'%s\';';
$buff['admin_index_act'] = '$info->admin_index_act = \'%s\';';
$xml_obj = XmlParser::loadXmlFile($xml_file); // /< Read xml file and convert it to xml object
if(!countobj($xml_obj->module)) return; // /< Error occurs if module tag doesn't included in the xml
$grants = $xml_obj->module->grants->grant; // /< Permission information
$permissions = $xml_obj->module->permissions->permission; // /< Acting permission
$menus = $xml_obj->module->menus->menu;
$actions = $xml_obj->module->actions->action; // /< Action list (required)
$default_index = $admin_index = '';
// Arrange permission information
if($grants)
{
if(is_array($grants)) $grant_list = $grants;
else $grant_list[] = $grants;
$info->grant = new stdClass();
$buff[] = '$info->grant = new stdClass;';
foreach($grant_list as $grant)
{
$name = $grant->attrs->name;
$default = $grant->attrs->default?$grant->attrs->default:'guest';
$title = $grant->title->body;
$info->grant->{$name} = new stdClass();
$info->grant->{$name}->title = $title;
$info->grant->{$name}->default = $default;
$buff[] = sprintf('$info->grant->%s = new stdClass;', $name);
$buff[] = sprintf('$info->grant->%s->title=\'%s\';', $name, $title);
$buff[] = sprintf('$info->grant->%s->default=\'%s\';', $name, $default);
}
}
// Permissions to grant
if($permissions)
{
if(is_array($permissions)) $permission_list = $permissions;
else $permission_list[] = $permissions;
$buff[] = '$info->permission = new stdClass;';
$buff[] = '$info->permission_check = new stdClass;';
$info->permission = new stdClass;
$info->permission_check = new stdClass;
foreach($permission_list as $permission)
{
$action = $permission->attrs->action;
$target = $permission->attrs->target;
$info->permission->$action = $target;
$buff[] = sprintf('$info->permission->%s = \'%s\';', $action, $target);
$info->permission_check->$action = new stdClass;
$info->permission_check->$action->key = $permission->attrs->check_var ?: '';
$info->permission_check->$action->type = $permission->attrs->check_type ?: '';
$buff[] = sprintf('$info->permission_check->%s = new stdClass;', $action);
$buff[] = sprintf('$info->permission_check->%s->key = \'%s\';', $action, $info->permission_check->$action->key);
$buff[] = sprintf('$info->permission_check->%s->type = \'%s\';', $action, $info->permission_check->$action->type);
}
}
// for admin menus
if($menus)
{
if(is_array($menus)) $menu_list = $menus;
else $menu_list[] = $menus;
$buff[] = '$info->menu = new stdClass;';
$info->menu = new stdClass();
foreach($menu_list as $menu)
{
$menu_name = $menu->attrs->name;
$menu_title = is_array($menu->title) ? $menu->title[0]->body : $menu->title->body;
$menu_type = $menu->attrs->type;
$info->menu->{$menu_name} = new stdClass();
$info->menu->{$menu_name}->title = $menu_title;
$info->menu->{$menu_name}->acts = array();
$info->menu->{$menu_name}->type = $menu_type;
$buff[] = sprintf('$info->menu->%s = new stdClass;', $menu_name);
$buff[] = sprintf('$info->menu->%s->title=\'%s\';', $menu_name, $menu_title);
$buff[] = sprintf('$info->menu->%s->type=\'%s\';', $menu_name, $menu_type);
}
}
// actions
if($actions)
{
if(is_array($actions)) $action_list = $actions;
else $action_list[] = $actions;
if(!isset($info->permission))
{
$buff[] = '$info->permission = new stdClass;';
$buff[] = '$info->permission_check = new stdClass;';
$info->permission = new stdClass;
$info->permission_check = new stdClass;
}
$buff[] = '$info->action = new stdClass;';
$info->action = new stdClass();
foreach($action_list as $action)
{
$name = $action->attrs->name;
// <action permission="...">
if($action->attrs->permission)
{
$info->permission->$name = $action->attrs->permission;
$buff[] = sprintf('$info->permission->%s = \'%s\';', $name, $info->permission->$name);
$info->permission_check->$name = new stdClass;
$info->permission_check->$name->key = $action->attrs->check_var ?: '';
$info->permission_check->$name->type = $action->attrs->check_type ?: '';
$buff[] = sprintf('$info->permission_check->%s = new stdClass;', $name);
$buff[] = sprintf('$info->permission_check->%s->key = \'%s\';', $name, $info->permission_check->$name->key);
$buff[] = sprintf('$info->permission_check->%s->type = \'%s\';', $name, $info->permission_check->$name->type);
}
$type = $action->attrs->type;
$grant = $action->attrs->grant?$action->attrs->grant:'guest';
$standalone = $action->attrs->standalone=='false'?'false':'true';
$ruleset = $action->attrs->ruleset?$action->attrs->ruleset:'';
$method = $action->attrs->method?$action->attrs->method:'';
$check_csrf = $action->attrs->check_csrf=='false'?'false':'true';
$meta_noindex = $action->attrs->{'meta-noindex'} === 'true' ? 'true' : 'false';
$index = $action->attrs->index;
$admin_index = $action->attrs->admin_index;
$setup_index = $action->attrs->setup_index;
$simple_setup_index = $action->attrs->simple_setup_index;
$menu_index = $action->attrs->menu_index;
$info->action->{$name} = new stdClass();
$info->action->{$name}->type = $type;
$info->action->{$name}->grant = $grant;
$info->action->{$name}->standalone = $standalone;
$info->action->{$name}->ruleset = $ruleset;
$info->action->{$name}->method = $method;
$info->action->{$name}->check_csrf = $check_csrf;
$info->action->{$name}->meta_noindex = $meta_noindex;
if($action->attrs->menu_name)
{
$info->menu->{$action->attrs->menu_name} = new stdClass();
if($menu_index == 'true')
{
$info->menu->{$action->attrs->menu_name}->index = $name;
$buff[] = sprintf('$info->menu->%s->index=\'%s\';', $action->attrs->menu_name, $name);
}
if(is_array($info->menu->{$action->attrs->menu_name}->acts))
{
$info->menu->{$action->attrs->menu_name}->acts[] = $name;
}
$buff[] = sprintf('$info->menu->%s->acts[]=\'%s\';', $action->attrs->menu_name, $name);
$i++;
}
$buff[] = sprintf('$info->action->%s = new stdClass;', $name);
$buff[] = sprintf('$info->action->%s->type=\'%s\';', $name, $type);
$buff[] = sprintf('$info->action->%s->grant=\'%s\';', $name, $grant);
$buff[] = sprintf('$info->action->%s->standalone=\'%s\';', $name, $standalone);
$buff[] = sprintf('$info->action->%s->ruleset=\'%s\';', $name, $ruleset);
$buff[] = sprintf('$info->action->%s->method=\'%s\';', $name, $method);
$buff[] = sprintf('$info->action->%s->check_csrf=\'%s\';', $name, $check_csrf);
$buff[] = sprintf('$info->action->%s->meta_noindex=\'%s\';', $name, $meta_noindex);
if($index=='true')
{
$default_index_act = $name;
$info->default_index_act = $name;
}
if($admin_index=='true')
{
$admin_index_act = $name;
$info->admin_index_act = $name;
}
if($setup_index=='true')
{
$setup_index_act = $name;
$info->setup_index_act = $name;
}
if($simple_setup_index=='true')
{
$simple_setup_index_act = $name;
$info->simple_setup_index_act = $name;
}
}
}
$buff['default_index_act'] = sprintf($buff['default_index_act'], $default_index_act);
$buff['setup_index_act'] = sprintf($buff['setup_index_act'], $setup_index_act);
$buff['simple_setup_index_act'] = sprintf($buff['simple_setup_index_act'], $simple_setup_index_act);
$buff['admin_index_act'] = sprintf($buff['admin_index_act'], $admin_index_act);
$buff[] = 'return $info;';
$buff = implode(PHP_EOL, $buff);
FileHandler::writeFile($cache_file, $buff);
return $info;
$info = Rhymix\Framework\Parsers\ModuleActionParser::loadXML($xml_file);
Rhymix\Framework\Cache::set($cache_key, $info, 0, true);
}
if(file_exists($cache_file)) return include($cache_file);
return $info;
}
/**
* Get a skin list for js API.
* return void
@ -1609,12 +1376,15 @@ class moduleModel extends module
$searched_count = count($searched_list);
if(!$searched_count) return;
// Get action forward
$action_forward = self::getActionForward();
// Get action security
$action_security = self::getActionSecurity();
for($i=0;$i<$searched_count;$i++)
foreach ($searched_list as $module_name)
{
// module name
$module_name = $searched_list[$i];
$path = ModuleHandler::getModulePath($module_name);
if(!is_dir(FileHandler::getRealPath($path))) continue;
@ -1651,16 +1421,59 @@ class moduleModel extends module
{
$info->need_install = false;
}
// Check if it is upgraded to module.class.php on each module
$oDummy = null;
$oDummy = getModule($module_name, 'class');
if($oDummy && method_exists($oDummy, "checkUpdate"))
{
$info->need_update = $oDummy->checkUpdate();
}
else
unset($oDummy);
// Check if all action-forwardable routes are registered
$module_action_info = self::getModuleActionXml($module_name);
$forwardable_routes = array();
foreach ($module_action_info->action ?: [] as $action_name => $action_info)
{
continue;
if (count($action_info->route) && $action_info->standalone !== 'false')
{
$forwardable_routes[$action_name] = array(
'regexp' => array(),
'config' => $action_info->route,
);
}
}
foreach ($module_action_info->route->GET ?: [] as $regexp => $action_name)
{
if (isset($forwardable_routes[$action_name]))
{
$forwardable_routes[$action_name]['regexp'][] = ['GET', $regexp];
}
}
foreach ($module_action_info->route->POST ?: [] as $regexp => $action_name)
{
if (isset($forwardable_routes[$action_name]))
{
$forwardable_routes[$action_name]['regexp'][] = ['POST', $regexp];
}
}
foreach ($forwardable_routes as $action_name => $route_info)
{
if (!isset($action_forward[$action_name]) ||
$action_forward[$action_name]->route_regexp !== $route_info['regexp'] ||
$action_forward[$action_name]->route_config !== $route_info['config'])
{
$info->need_update = true;
}
}
// Check if all secure actions are registered
foreach ($module_action_info->action ?: [] as $action_name => $action_info)
{
if ($action_info->use_ssl === 'true' && !isset($action_security[$action_name]))
{
$info->need_update = true;
}
}
}
$list[] = $info;

View file

@ -0,0 +1,8 @@
<query id="deleteActionSecurity" action="delete">
<tables>
<table name="action_security" />
</tables>
<conditions>
<condition operation="equal" column="act" var="act" notnull="notnull" />
</conditions>
</query>

View file

@ -0,0 +1,11 @@
<query id="getActionSecurity" action="select">
<tables>
<table name="action_security" />
</tables>
<columns>
<column name="*" />
</columns>
<conditions>
<condition operation="equal" column="act" var="act" />
</conditions>
</query>

View file

@ -6,5 +6,8 @@
<column name="act" var="act" notnull="notnull" />
<column name="module" var="module" notnull="notnull" />
<column name="type" var="type" notnull="notnull" />
<column name="route_regexp" var="route_regexp" />
<column name="route_config" var="route_config" />
<column name="global_route" var="global_route" default="N" />
</columns>
</query>

View file

@ -0,0 +1,8 @@
<query id="insertActionSecurity" action="insert">
<tables>
<table name="action_security" />
</tables>
<columns>
<column name="act" var="act" notnull="notnull" />
</columns>
</query>

View file

@ -1,5 +1,8 @@
<table name="action_forward">
<column name="act" type="varchar" size="80" notnull="notnull" unique="idx_foward" />
<column name="act" type="varchar" size="80" notnull="notnull" primary_key="primary_key" />
<column name="module" type="varchar" size="60" notnull="notnull" />
<column name="type" type="varchar" size="15" notnull="notnull" />
<column name="route_regexp" type="text" />
<column name="route_config" type="text" />
<column name="global_route" type="char" size="1" notnull="notnull" default="N" />
</table>

View file

@ -0,0 +1,3 @@
<table name="action_security">
<column name="act" type="varchar" size="80" notnull="notnull" primary_key="primary_key" />
</table>