Merge branch 'rhymix:master' into master

This commit is contained in:
Lastorder 2025-09-06 15:48:53 +09:00 committed by GitHub
commit 2fd8df9de6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 384 additions and 162 deletions

View file

@ -242,7 +242,7 @@ class Context
else else
{ {
$site_module_info = new stdClass; $site_module_info = new stdClass;
$site_module_info->domain = $_SERVER['HTTP_HOST']; $site_module_info->domain = Rhymix\Framework\URL::getCurrentDomain();
$site_module_info->security = RX_SSL ? 'always' : 'none'; $site_module_info->security = RX_SSL ? 'always' : 'none';
$site_module_info->settings = new stdClass; $site_module_info->settings = new stdClass;
$site_module_info->is_default_replaced = true; $site_module_info->is_default_replaced = true;

View file

@ -147,7 +147,11 @@ class ModuleHandler extends Handler
return true; return true;
case 'display': case 'display':
// pass $site_module_info->domain_srl = -1;
$site_module_info->domain = Rhymix\Framework\URL::getCurrentDomain();
$site_module_info->is_default_domain = 'N';
$site_module_info->is_default_replaced = true;
Context::set('site_module_info', $site_module_info);
} }
} }
} }
@ -182,8 +186,11 @@ class ModuleHandler extends Handler
} }
} }
// Initialize module info.
$module_info = null;
// Get module info from document_srl. // Get module info from document_srl.
if($this->document_srl) if($this->document_srl && !preg_match('/Admin/', $this->act))
{ {
$module_info = $this->_checkDocumentSrl(); $module_info = $this->_checkDocumentSrl();
if ($module_info === false) if ($module_info === false)
@ -191,23 +198,21 @@ class ModuleHandler extends Handler
return false; return false;
} }
} }
else
{
$module_info = null;
}
// Get module info from mid. // Get module info from mid.
if(!$module_info && $this->mid) if(!$module_info && $this->mid)
{ {
$module_info = ModuleModel::getModuleInfoByMid($this->mid); $module_info = ModuleModel::getModuleInfoByMid($this->mid);
if($module_info && isset($module_info->domain_srl) && $module_info->domain_srl > -1) }
// If the module does not belong to the current domain, throw a 404.
if($module_info && isset($module_info->domain_srl) && $module_info->domain_srl > -1)
{
if($module_info->domain_srl != $site_module_info->domain_srl)
{ {
if($module_info->domain_srl != $site_module_info->domain_srl) $this->error = 'msg_module_is_not_exists';
{ $this->httpStatusCode = 404;
$this->error = 'msg_module_is_not_exists'; return true;
$this->httpStatusCode = 404;
return true;
}
} }
} }
@ -783,6 +788,14 @@ class ModuleHandler extends Handler
} }
} }
// Redirect if a member action is requested with an unnecessary document_srl. (For backward compatibility)
if(preg_match('/^disp(Member|Communication)/', $this->act))
{
Context::setCacheControl(0);
header('Location: ' . getNotEncodedUrl('document_srl', null), true, 301);
return false;
}
// Remove module info if a different module has already been selected for the current request. // Remove module info if a different module has already been selected for the current request.
if($this->module && $module_info->module !== $this->module) if($this->module && $module_info->module !== $this->module)
{ {

View file

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

View file

@ -175,9 +175,10 @@ class DBQueryParser extends BaseParser
foreach ($xml->groups->children() as $tag) foreach ($xml->groups->children() as $tag)
{ {
$name = $tag->getName(); $name = $tag->getName();
$ifvar = trim($tag['if'] ?? '') ?: null;
if ($name === 'group') if ($name === 'group')
{ {
$query->groupby->columns[] = trim($tag['column'] ?? ''); $query->groupby->columns[] = [trim($tag['column'] ?? ''), $ifvar];
} }
elseif ($name === 'having') elseif ($name === 'having')
{ {

View file

@ -222,6 +222,14 @@ class Query extends VariableBase
$columns = array(); $columns = array();
foreach ($this->groupby->columns as $column_name) foreach ($this->groupby->columns as $column_name)
{ {
if (is_array($column_name))
{
list($column_name, $ifvar) = $column_name;
if ($ifvar && empty($this->_args[$ifvar]))
{
continue;
}
}
if (self::isValidColumnName($column_name)) if (self::isValidColumnName($column_name))
{ {
$columns[] = self::quoteName($column_name); $columns[] = self::quoteName($column_name);

View file

@ -278,7 +278,7 @@ class TemplateParser_v1
$skip = sprintf('(?!%s)', implode('|', ['marquee'])); $skip = sprintf('(?!%s)', implode('|', ['marquee']));
$split_regex = "@(</?{$skip}[a-zA-Z](?>[^<>{}\"]+|<!--.*?-->.*?<!--.*?end-->|{[^}]*}|\"(?>'.*?'|.)*?\"|.)*?>)@s"; $split_regex = "@(</?{$skip}[a-zA-Z](?>[^<>{}\"]+|<!--.*?-->.*?<!--.*?end-->|{[^}]*}|\"(?>'.*?'|.)*?\"|.)*?>)@s";
$nodes = preg_split($split_regex, $content, -1, PREG_SPLIT_DELIM_CAPTURE); $nodes = preg_split($split_regex, $content, -1, PREG_SPLIT_DELIM_CAPTURE) ?: [];
for($idx = 1, $node_len = count($nodes); $idx < $node_len; $idx+=2) for($idx = 1, $node_len = count($nodes); $idx < $node_len; $idx+=2)
{ {

View file

@ -106,7 +106,7 @@ class Swift_Encoder_QpEncoder implements Swift_Encoder
* @param Swift_CharacterStream $charStream to use for reading characters * @param Swift_CharacterStream $charStream to use for reading characters
* @param Swift_StreamFilter $filter if input should be canonicalized * @param Swift_StreamFilter $filter if input should be canonicalized
*/ */
public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null) public function __construct(Swift_CharacterStream $charStream, ?Swift_StreamFilter $filter = null)
{ {
$this->charStream = $charStream; $this->charStream = $charStream;
if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) { if (!isset(self::$safeMapShare[$this->getSafeMapShareId()])) {

View file

@ -56,7 +56,7 @@ interface Swift_KeyCache
* *
* @return Swift_InputByteStream * @return Swift_InputByteStream
*/ */
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $is = null); public function getInputByteStream($nsKey, $itemKey, ?Swift_InputByteStream $is = null);
/** /**
* Get data back out of the cache as a string. * Get data back out of the cache as a string.

View file

@ -105,7 +105,7 @@ class Swift_KeyCache_ArrayKeyCache implements Swift_KeyCache
* *
* @return Swift_InputByteStream * @return Swift_InputByteStream
*/ */
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) public function getInputByteStream($nsKey, $itemKey, ?Swift_InputByteStream $writeThrough = null)
{ {
$is = clone $this->stream; $is = clone $this->stream;
$is->setKeyCache($this); $is->setKeyCache($this);

View file

@ -128,7 +128,7 @@ class Swift_KeyCache_DiskKeyCache implements Swift_KeyCache
* *
* @return Swift_InputByteStream * @return Swift_InputByteStream
*/ */
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) public function getInputByteStream($nsKey, $itemKey, ?Swift_InputByteStream $writeThrough = null)
{ {
$is = clone $this->stream; $is = clone $this->stream;
$is->setKeyCache($this); $is->setKeyCache($this);

View file

@ -52,7 +52,7 @@ class Swift_KeyCache_NullKeyCache implements Swift_KeyCache
* *
* @return Swift_InputByteStream * @return Swift_InputByteStream
*/ */
public function getInputByteStream($nsKey, $itemKey, Swift_InputByteStream $writeThrough = null) public function getInputByteStream($nsKey, $itemKey, ?Swift_InputByteStream $writeThrough = null)
{ {
} }

View file

@ -49,7 +49,7 @@ class Swift_KeyCache_SimpleKeyCacheInputStream implements Swift_KeyCache_KeyCach
* @param string $bytes * @param string $bytes
* @param Swift_InputByteStream $is optional * @param Swift_InputByteStream $is optional
*/ */
public function write($bytes, Swift_InputByteStream $is = null) public function write($bytes, ?Swift_InputByteStream $is = null)
{ {
$this->keyCache->setString( $this->keyCache->setString(
$this->nsKey, $this->itemKey, $bytes, Swift_KeyCache::MODE_APPEND $this->nsKey, $this->itemKey, $bytes, Swift_KeyCache::MODE_APPEND

View file

@ -24,7 +24,7 @@ class Swift_Mime_ContentEncoder_QpContentEncoder extends Swift_Encoder_QpEncoder
* @param Swift_StreamFilter $filter if canonicalization should occur * @param Swift_StreamFilter $filter if canonicalization should occur
* @param bool $dotEscape if dot stuffing workaround must be enabled * @param bool $dotEscape if dot stuffing workaround must be enabled
*/ */
public function __construct(Swift_CharacterStream $charStream, Swift_StreamFilter $filter = null, $dotEscape = false) public function __construct(Swift_CharacterStream $charStream, ?Swift_StreamFilter $filter = null, $dotEscape = false)
{ {
$this->dotEscape = $dotEscape; $this->dotEscape = $dotEscape;
parent::__construct($charStream, $filter); parent::__construct($charStream, $filter);

View file

@ -200,7 +200,7 @@ abstract class Swift_Mime_Headers_AbstractHeader implements Swift_Mime_Header
* *
* @return string * @return string
*/ */
protected function createPhrase(Swift_Mime_Header $header, $string, $charset, Swift_Mime_HeaderEncoder $encoder = null, $shorten = false) protected function createPhrase(Swift_Mime_Header $header, $string, $charset, ?Swift_Mime_HeaderEncoder $encoder = null, $shorten = false)
{ {
// Treat token as exactly what was given // Treat token as exactly what was given
$phraseStr = $string; $phraseStr = $string;

View file

@ -42,7 +42,7 @@ class Swift_Mime_Headers_IdentificationHeader extends Swift_Mime_Headers_Abstrac
* *
* @param string $name * @param string $name
*/ */
public function __construct($name, EmailValidator $emailValidator, Swift_AddressEncoder $addressEncoder = null) public function __construct($name, EmailValidator $emailValidator, ?Swift_AddressEncoder $addressEncoder = null)
{ {
$this->setFieldName($name); $this->setFieldName($name);
$this->emailValidator = $emailValidator; $this->emailValidator = $emailValidator;

View file

@ -39,7 +39,7 @@ class Swift_Mime_Headers_MailboxHeader extends Swift_Mime_Headers_AbstractHeader
* *
* @param string $name of Header * @param string $name of Header
*/ */
public function __construct($name, Swift_Mime_HeaderEncoder $encoder, EmailValidator $emailValidator, Swift_AddressEncoder $addressEncoder = null) public function __construct($name, Swift_Mime_HeaderEncoder $encoder, EmailValidator $emailValidator, ?Swift_AddressEncoder $addressEncoder = null)
{ {
$this->setFieldName($name); $this->setFieldName($name);
$this->setEncoder($encoder); $this->setEncoder($encoder);

View file

@ -41,7 +41,7 @@ class Swift_Mime_Headers_ParameterizedHeader extends Swift_Mime_Headers_Unstruct
* *
* @param string $name * @param string $name
*/ */
public function __construct($name, Swift_Mime_HeaderEncoder $encoder, Swift_Encoder $paramEncoder = null) public function __construct($name, Swift_Mime_HeaderEncoder $encoder, ?Swift_Encoder $paramEncoder = null)
{ {
parent::__construct($name, $encoder); parent::__construct($name, $encoder);
$this->paramEncoder = $paramEncoder; $this->paramEncoder = $paramEncoder;

View file

@ -39,7 +39,7 @@ class Swift_Mime_Headers_PathHeader extends Swift_Mime_Headers_AbstractHeader
* *
* @param string $name * @param string $name
*/ */
public function __construct($name, EmailValidator $emailValidator, Swift_AddressEncoder $addressEncoder = null) public function __construct($name, EmailValidator $emailValidator, ?Swift_AddressEncoder $addressEncoder = null)
{ {
$this->setFieldName($name); $this->setFieldName($name);
$this->emailValidator = $emailValidator; $this->emailValidator = $emailValidator;

View file

@ -37,7 +37,7 @@ class Swift_Mime_SimpleHeaderFactory implements Swift_Mime_CharsetObserver
* *
* @param string|null $charset * @param string|null $charset
*/ */
public function __construct(Swift_Mime_HeaderEncoder $encoder, Swift_Encoder $paramEncoder, EmailValidator $emailValidator, $charset = null, Swift_AddressEncoder $addressEncoder = null) public function __construct(Swift_Mime_HeaderEncoder $encoder, Swift_Encoder $paramEncoder, EmailValidator $emailValidator, $charset = null, ?Swift_AddressEncoder $addressEncoder = null)
{ {
$this->encoder = $encoder; $this->encoder = $encoder;
$this->paramEncoder = $paramEncoder; $this->paramEncoder = $paramEncoder;
@ -72,7 +72,7 @@ class Swift_Mime_SimpleHeaderFactory implements Swift_Mime_CharsetObserver
* *
* @return Swift_Mime_Header * @return Swift_Mime_Header
*/ */
public function createDateHeader($name, DateTimeInterface $dateTime = null) public function createDateHeader($name, ?DateTimeInterface $dateTime = null)
{ {
$header = new Swift_Mime_Headers_DateHeader($name); $header = new Swift_Mime_Headers_DateHeader($name);
if (isset($dateTime)) { if (isset($dateTime)) {

View file

@ -76,7 +76,7 @@ class Swift_Mime_SimpleHeaderSet implements Swift_Mime_CharsetObserver
* *
* @param string $name * @param string $name
*/ */
public function addDateHeader($name, DateTimeInterface $dateTime = null) public function addDateHeader($name, ?DateTimeInterface $dateTime = null)
{ {
$this->storeHeader($name, $this->factory->createDateHeader($name, $dateTime)); $this->storeHeader($name, $this->factory->createDateHeader($name, $dateTime));
} }

View file

@ -50,7 +50,7 @@ class Swift_Plugins_AntiFloodPlugin implements Swift_Events_SendListener, Swift_
* @param int $sleep time * @param int $sleep time
* @param Swift_Plugins_Sleeper $sleeper (not needed really) * @param Swift_Plugins_Sleeper $sleeper (not needed really)
*/ */
public function __construct($threshold = 99, $sleep = 0, Swift_Plugins_Sleeper $sleeper = null) public function __construct($threshold = 99, $sleep = 0, ?Swift_Plugins_Sleeper $sleeper = null)
{ {
$this->setThreshold($threshold); $this->setThreshold($threshold);
$this->setSleepTime($sleep); $this->setSleepTime($sleep);

View file

@ -76,7 +76,7 @@ class Swift_Plugins_ThrottlerPlugin extends Swift_Plugins_BandwidthMonitorPlugin
* @param Swift_Plugins_Sleeper $sleeper (only needed in testing) * @param Swift_Plugins_Sleeper $sleeper (only needed in testing)
* @param Swift_Plugins_Timer $timer (only needed in testing) * @param Swift_Plugins_Timer $timer (only needed in testing)
*/ */
public function __construct($rate, $mode = self::BYTES_PER_MINUTE, Swift_Plugins_Sleeper $sleeper = null, Swift_Plugins_Timer $timer = null) public function __construct($rate, $mode = self::BYTES_PER_MINUTE, ?Swift_Plugins_Sleeper $sleeper = null, ?Swift_Plugins_Timer $timer = null)
{ {
$this->rate = $rate; $this->rate = $rate;
$this->mode = $mode; $this->mode = $mode;

View file

@ -46,7 +46,7 @@ abstract class Swift_Transport_AbstractSmtpTransport implements Swift_Transport
* *
* @param string $localDomain * @param string $localDomain
*/ */
public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', ?Swift_AddressEncoder $addressEncoder = null)
{ {
$this->buffer = $buf; $this->buffer = $buf;
$this->eventDispatcher = $dispatcher; $this->eventDispatcher = $dispatcher;

View file

@ -51,7 +51,7 @@ class Swift_Transport_EsmtpTransport extends Swift_Transport_AbstractSmtpTranspo
* @param Swift_Transport_EsmtpHandler[] $extensionHandlers * @param Swift_Transport_EsmtpHandler[] $extensionHandlers
* @param string $localDomain * @param string $localDomain
*/ */
public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) public function __construct(Swift_Transport_IoBuffer $buf, array $extensionHandlers, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', ?Swift_AddressEncoder $addressEncoder = null)
{ {
parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder); parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder);
$this->setExtensionHandlers($extensionHandlers); $this->setExtensionHandlers($extensionHandlers);

View file

@ -36,7 +36,7 @@ class Swift_Transport_SendmailTransport extends Swift_Transport_AbstractSmtpTran
* *
* @param string $localDomain * @param string $localDomain
*/ */
public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', Swift_AddressEncoder $addressEncoder = null) public function __construct(Swift_Transport_IoBuffer $buf, Swift_Events_EventDispatcher $dispatcher, $localDomain = '127.0.0.1', ?Swift_AddressEncoder $addressEncoder = null)
{ {
parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder); parent::__construct($buf, $dispatcher, $localDomain, $addressEncoder);
} }

View file

@ -24,7 +24,7 @@ class Swift_Transport_SpoolTransport implements Swift_Transport
/** /**
* Constructor. * Constructor.
*/ */
public function __construct(Swift_Events_EventDispatcher $eventDispatcher, Swift_Spool $spool = null) public function __construct(Swift_Events_EventDispatcher $eventDispatcher, ?Swift_Spool $spool = null)
{ {
$this->eventDispatcher = $eventDispatcher; $this->eventDispatcher = $eventDispatcher;
$this->spool = $spool; $this->spool = $spool;

View file

@ -88,6 +88,7 @@ class BoardAdminController extends Board {
$args->meta_description = trim(utf8_normalize_spaces($args->meta_description)); $args->meta_description = trim(utf8_normalize_spaces($args->meta_description));
$args->header_text = Rhymix\Modules\Admin\Models\Utility::cleanHeaderAndFooterScripts($args->header_text ?? ''); $args->header_text = Rhymix\Modules\Admin\Models\Utility::cleanHeaderAndFooterScripts($args->header_text ?? '');
$args->footer_text = Rhymix\Modules\Admin\Models\Utility::cleanHeaderAndFooterScripts($args->footer_text ?? ''); $args->footer_text = Rhymix\Modules\Admin\Models\Utility::cleanHeaderAndFooterScripts($args->footer_text ?? '');
$args->admin_mail = implode(', ', array_map('trim', explode(',', $args->admin_mail ?? '')));
// if there is an existed module // if there is an existed module
if ($args->module_srl && $module_info->module_srl != $args->module_srl) if ($args->module_srl && $module_info->module_srl != $args->module_srl)

View file

@ -258,7 +258,7 @@ class BoardController extends Board
$oDocument->setGrantForSession(); $oDocument->setGrantForSession();
// send an email to admin user // send an email to admin user
if ($this->module_info->admin_mail && config('mail.default_from')) if (isset($this->module_info->admin_mail) && $this->module_info->admin_mail && config('mail.default_from'))
{ {
$browser_title = Context::replaceUserLang($this->module_info->browser_title); $browser_title = Context::replaceUserLang($this->module_info->browser_title);
$mail_title = sprintf(lang('msg_document_notify_mail'), $browser_title, cut_str($obj->title, 20, '...')); $mail_title = sprintf(lang('msg_document_notify_mail'), $browser_title, cut_str($obj->title, 20, '...'));

View file

@ -18,7 +18,7 @@ $lang->consultation = 'Consultation';
$lang->use_consultation = 'Use as Consultation Board'; $lang->use_consultation = 'Use as Consultation Board';
$lang->secret = 'Secret'; $lang->secret = 'Secret';
$lang->thisissecret = 'This is a secret post.'; $lang->thisissecret = 'This is a secret post.';
$lang->admin_mail = 'Administrator\'s Mail'; $lang->admin_mail = 'Administrator Mail';
$lang->update_log = 'Update Log'; $lang->update_log = 'Update Log';
$lang->last_updater = 'Latest Update by'; $lang->last_updater = 'Latest Update by';
$lang->cmd_board_list = 'Boards List'; $lang->cmd_board_list = 'Boards List';
@ -40,7 +40,7 @@ $lang->about_anonymous_name = 'You can customize the anonymous name that will be
$lang->about_board = 'This module is for creating and managing boards.'; $lang->about_board = 'This module is for creating and managing boards.';
$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_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_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_admin_mail = 'Send an e-mail when a new post or comment is submitted. Separate multiple recipients with a comma.';
$lang->about_list_config = 'If using list-style skin, you may arrange items to display. However, this feature might not be availble for non-official skins. If you double-click target items and display items, then you can add / remove them'; $lang->about_list_config = 'If using list-style skin, you may arrange items to display. However, this feature might not be availble for non-official skins. If you double-click target items and display items, then you can add / remove them';
$lang->about_use_status = 'Please select status that can be selected when you write a post.'; $lang->about_use_status = 'Please select status that can be selected when you write a post.';
$lang->about_protect_comment = 'Prevent updating or deleting a comment if it has children.'; $lang->about_protect_comment = 'Prevent updating or deleting a comment if it has children.';

View file

@ -40,7 +40,7 @@ $lang->about_anonymous_name = '익명 기능을 사용할 때 표시할 익명
$lang->about_board = '게시판을 생성하고 관리할 수 있습니다.'; $lang->about_board = '게시판을 생성하고 관리할 수 있습니다.';
$lang->about_consultation = '관리 권한이 없는 회원은 자신이 쓴 글만 보이도록 합니다.<br>상담 기능 사용시 비회원 글쓰기는 금지됩니다.'; $lang->about_consultation = '관리 권한이 없는 회원은 자신이 쓴 글만 보이도록 합니다.<br>상담 기능 사용시 비회원 글쓰기는 금지됩니다.';
$lang->about_secret = '게시판 및 댓글의 비밀글 기능을 사용할 수 있도록 합니다.'; $lang->about_secret = '게시판 및 댓글의 비밀글 기능을 사용할 수 있도록 합니다.';
$lang->about_admin_mail = '글이나 댓글이 등록될때 등록된 메일주소로 메일이 발송됩니다. 콤마(,)로 연결시 다수의 메일주소로 발송할 수 있습니다.'; $lang->about_admin_mail = '새 글이나 댓글이 등록되면 지정된 메일 주소로 알림을 받습니다. 여러 메일 주소를 지정하려면 쉼표(,)로 구분하세요.';
$lang->about_list_config = '게시판의 목록형식 사용시 원하는 항목들로 배치를 할 수 있습니다. 단 스킨에서 지원하지 않는 경우 불가능합니다. 대상항목/ 표시항목의 항목을 더블클릭하면 추가/ 제거가 됩니다.'; $lang->about_list_config = '게시판의 목록형식 사용시 원하는 항목들로 배치를 할 수 있습니다. 단 스킨에서 지원하지 않는 경우 불가능합니다. 대상항목/ 표시항목의 항목을 더블클릭하면 추가/ 제거가 됩니다.';
$lang->about_use_status = '글 작성 시 선택할 수 있는 상태를 지정해주세요.'; $lang->about_use_status = '글 작성 시 선택할 수 있는 상태를 지정해주세요.';
$lang->about_protect_comment = '댓글의 댓글이 있을경우 해당댓글을 삭제 및 수정을 할 수 없도록 합니다.'; $lang->about_protect_comment = '댓글의 댓글이 있을경우 해당댓글을 삭제 및 수정을 할 수 없도록 합니다.';

View file

@ -68,8 +68,6 @@
<option value="0">{$lang->notuse}</option> <option value="0">{$lang->notuse}</option>
<option loop="$layout_list => $key, $val" value="{$val->layout_srl}" selected="selected"|cond="$module_info->layout_srl == $val->layout_srl">{$val->title} ({$val->layout})</option> <option loop="$layout_list => $key, $val" value="{$val->layout_srl}" selected="selected"|cond="$module_info->layout_srl == $val->layout_srl">{$val->title} ({$val->layout})</option>
</select> </select>
<a href="#layout_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a>
<p id="layout_help" class="x_help-block x_hide">{$lang->about_layout}</p>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
@ -423,8 +421,7 @@
<label class="x_control-label" for="admin_mail">{$lang->admin_mail}</label> <label class="x_control-label" for="admin_mail">{$lang->admin_mail}</label>
<div class="x_controls"> <div class="x_controls">
<input type="text" name="admin_mail" id="admin_mail" value="{$module_info->admin_mail}" /> <input type="text" name="admin_mail" id="admin_mail" value="{$module_info->admin_mail}" />
<a href="#admin_mail_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a> <p class="x_help-block">{$lang->about_admin_mail}</p>
<p id="admin_mail_help" class="x_help-block x_hide">{$lang->about_admin_mail}</p>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
@ -434,16 +431,13 @@
<option value="0">{$lang->notuse}</option> <option value="0">{$lang->notuse}</option>
<option loop="$module_category => $key, $val" value="{$key}" selected="selected"|cond="$module_info->module_category_srl == $key">{$val->title}</option> <option loop="$module_category => $key, $val" value="{$key}" selected="selected"|cond="$module_info->module_category_srl == $key">{$val->title}</option>
</select> </select>
<a href="#module_category_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a> <p class="x_help-block">{$lang->about_module_category}</p>
<p id="module_category_help" class="x_help-block x_hide">{$lang->about_module_category}</p>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label class="x_control-label" for="description">{$lang->description}</label> <label class="x_control-label" for="description">{$lang->description}</label>
<div class="x_controls"> <div class="x_controls">
<textarea name="description" id="description" rows="4" cols="42" placeholder="{$lang->about_description}" style="vertical-align:top">{$module_info->description}</textarea> <textarea name="description" id="description" rows="4" cols="42" placeholder="{$lang->about_description}" style="vertical-align:top">{$module_info->description}</textarea>
<a href="#description_help" class="x_icon-question-sign" data-toggle>{$lang->help}</a>
<p id="description_help" class="x_help-block x_hide">{$lang->about_description}</p>
</div> </div>
</div> </div>
</section> </section>

View file

@ -3,6 +3,7 @@
<table name="modules" /> <table name="modules" />
</tables> </tables>
<columns> <columns>
<column name="domain_srl" />
<column name="module_srl" /> <column name="module_srl" />
<column name="mid" /> <column name="mid" />
<column name="browser_title" /> <column name="browser_title" />

View file

@ -49,10 +49,16 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<tr loop="$comment_list => $no, $val"> <tr loop="$comment_list => $no, $val">
{@ $comment = $val->getContentText(200)} {@ $comment = $val->getContentText(200)}
<td> <td>
<block cond="isset($module_list[$val->module_srl])"> {@ $comment_url = getUrl(['mid' => $module_list[$val->module_srl]->mid ?? null, 'document_srl' => $val->document_srl, 'comment_srl' => $val->comment_srl]) . '#comment_' . $val->comment_srl}
<a href="{getUrl('', 'mid', $module_list[$val->module_srl]->mid)}" target="_blank">{$module_list[$val->module_srl]->browser_title}</a> - <!--@if(isset($module_list[$val->module_srl]))-->
</block> <!--@if($module_list[$val->module_srl]->domain_srl == -1 || $module_list[$val->module_srl]->domain_srl == $site_module_info->domain_srl)-->
<a href="{getUrl('','document_srl',$val->document_srl,'comment_srl',$val->comment_srl)}#comment_{$val->comment_srl}" target="_blank"><!--@if(strlen($comment))-->{$comment}<!--@else--><em>{$lang->no_text_comment}</em><!--@end--></a> <a href="{getUrl('', 'mid', $module_list[$val->module_srl]->mid)}" target="_blank">{$module_list[$val->module_srl]->browser_title}</a> -
<!--@else-->
{@ $module_url = ModuleModel::getDomainByModuleSrl($val->module_srl); $comment_url = $module_url . $comment_url; }
<a href="{$module_url}{getUrl('', 'mid', $module_list[$val->module_srl]->mid)}" target="_blank">{$module_list[$val->module_srl]->browser_title}</a> -
<!--@endif-->
<!--@endif-->
<a href="{$comment_url}" target="_blank"><!--@if(strlen($comment))-->{$comment}<!--@else--><em>{$lang->no_text_comment}</em><!--@end--></a>
</td> </td>
<td class="nowr"> <td class="nowr">
<span cond="$val->get('member_srl') <= 0">{$val->getNickName()}</span> <span cond="$val->get('member_srl') <= 0">{$val->getNickName()}</span>

View file

@ -31,6 +31,20 @@ class counter extends ModuleObject
return true; return true;
} }
// Index optimization
if (!$oDB->isIndexExists('counter_log', 'idx_regdate_ipaddress'))
{
return true;
}
if ($oDB->isIndexExists('counter_log', 'idx_site_counter_log'))
{
return true;
}
if ($oDB->isIndexExists('counter_log', 'idx_counter_log'))
{
return true;
}
return false; return false;
} }
@ -46,6 +60,20 @@ class counter extends ModuleObject
{ {
$oDB->dropTable('counter_site_status'); $oDB->dropTable('counter_site_status');
} }
// Index optimization
if (!$oDB->isIndexExists('counter_log', 'idx_regdate_ipaddress'))
{
$oDB->addIndex('counter_log', 'idx_regdate_ipaddress', ['regdate(8)', 'ipaddress']);
}
if ($oDB->isIndexExists('counter_log', 'idx_site_counter_log'))
{
$oDB->dropIndex('counter_log', 'idx_site_counter_log');
}
if ($oDB->isIndexExists('counter_log', 'idx_counter_log'))
{
$oDB->dropIndex('counter_log', 'idx_counter_log');
}
} }
/** /**

View file

@ -1,6 +1,8 @@
<table name="counter_log"> <table name="counter_log">
<column name="site_srl" type="number" size="11" notnull="notnull" default="0" index="idx_site_counter_log" /> <column name="id" type="bigint" notnull="notnull" primary_key="primary_key" auto_increment="auto_increment" />
<column name="ipaddress" type="varchar" size="60" notnull="notnull" index="idx_site_counter_log" /> <column name="site_srl" type="bigint" notnull="notnull" default="0" />
<column name="regdate" type="date" index="idx_counter_log" /> <column name="regdate" type="date" notnull="notnull" />
<column name="ipaddress" type="varchar" size="60" notnull="notnull" />
<column name="user_agent" type="varchar" size="250" /> <column name="user_agent" type="varchar" size="250" />
<index name="idx_regdate_ipaddress" columns="regdate(8),ipaddress" />
</table> </table>

View file

@ -1,5 +1,5 @@
<table name="counter_status"> <table name="counter_status">
<column name="regdate" type="number" size="11" notnull="notnull" primary_key="primary_key" /> <column name="regdate" type="int" notnull="notnull" primary_key="primary_key" />
<column name="unique_visitor" type="number" size="11" default="0" /> <column name="unique_visitor" type="bigint" notnull="notnull" default="0" />
<column name="pageview" type="number" size="11" default="0" /> <column name="pageview" type="bigint" notnull="notnull" default="0" />
</table> </table>

View file

@ -3408,8 +3408,12 @@ class DocumentController extends Document
$obj->target_module_srl = intval(Context::get('module_srl') ?: Context::get('target_module_srl')); $obj->target_module_srl = intval(Context::get('module_srl') ?: Context::get('target_module_srl'));
$obj->target_category_srl = intval(Context::get('target_category_srl')); $obj->target_category_srl = intval(Context::get('target_category_srl'));
$obj->manager_message = Context::get('message_content') ? nl2br(escape(strip_tags(Context::get('message_content')))) : ''; $obj->manager_message = Context::get('message_content') ? nl2br(escape(strip_tags(Context::get('message_content')))) : '';
$obj->send_message = $obj->manager_message || Context::get('send_default_message') == 'Y'; $obj->send_message = Context::get('send_message') ?? 'default';
$obj->return_message = ''; $obj->return_message = '';
if (Context::get('send_default_message') === 'Y')
{
$obj->send_message = 'default';
}
// Check permission of target module // Check permission of target module
if($obj->target_module_srl) if($obj->target_module_srl)
@ -3540,40 +3544,42 @@ class DocumentController extends Document
// Send a message // Send a message
$actions = lang('default_message_verbs'); $actions = lang('default_message_verbs');
if(isset($actions[$obj->type]) && $obj->send_message) if(isset($actions[$obj->type]) && $obj->send_message !== 'none')
{ {
// Set message // Set message
$title = sprintf(lang('default_message_format'), $actions[$obj->type]); $title = sprintf(lang('default_message_format'), $actions[$obj->type]);
$content = <<< Content $content = <<<EOT
<div style="padding:10px 0;"><strong>{$title}</strong></div> <div style="padding:10px 0;"><strong>{$title}</strong></div>
<p>{$obj->manager_message}</p> <p>{$obj->manager_message}</p>
<hr> <hr>
<ul>%1\$s</ul> <ul>%1\$s</ul>
Content; EOT;
$document_item = '<li><a href="%1$s">%2$s</a></li>';
// Set recipient // Set recipient
$recipients = array(); $recipients = array();
foreach ($obj->document_list as $document_srl => $oDocument) foreach ($obj->document_list as $document_srl => $oDocument)
{ {
if(!($member_srl = abs($oDocument->get('member_srl'))) || $logged_info->member_srl == $member_srl) $member_srl = abs($oDocument->get('member_srl'));
if(!$member_srl || $logged_info->member_srl == $member_srl)
{ {
continue; continue;
} }
if(!isset($recipients[$member_srl])) if(!isset($recipients[$member_srl]))
{ {
$recipients[$member_srl] = array(); $recipients[$member_srl] = array();
} }
$recipients[$member_srl][] = vsprintf('<li><a href="%1$s">%2$s</a></li>', [
$recipients[$member_srl][] = sprintf($document_item, $oDocument->getPermanentUrl(), $oDocument->getTitleText()); escape($oDocument->getPermanentUrl()),
$oDocument->getTitleText(),
]);
} }
// Send // Send
$oCommunicationController = CommunicationController::getInstance(); $oCommunicationController = CommunicationController::getInstance();
foreach ($recipients as $member_srl => $items) foreach ($recipients as $member_srl => $items)
{ {
$oCommunicationController->sendMessage($this->user->member_srl, $member_srl, $title, sprintf($content, implode('', $items)), true, null, false); $content = sprintf($content, implode('', $items));
$oCommunicationController->sendMessage($this->user->member_srl, $member_srl, $title, $content, true, null, false);
} }
} }

View file

@ -104,7 +104,9 @@ $lang->select_module_id = 'Select a module ID.';
$lang->select_category = 'Select a category.'; $lang->select_category = 'Select a category.';
$lang->category_description = 'Category Description'; $lang->category_description = 'Category Description';
$lang->no_title_document = 'No title in this document.'; $lang->no_title_document = 'No title in this document.';
$lang->send_default_message = 'Send the default message'; $lang->send_default_message = 'Send default message';
$lang->send_custom_message = 'Send message with content below';
$lang->send_no_message = 'Don\'t send message';
$lang->msg_admin_document_no_move_to_trash = 'You are not allowed to move the superadmin\'s article to the trash bin.'; $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_format = '%1$s the document by manager.';
$lang->default_message_verbs['move'] = 'moved'; $lang->default_message_verbs['move'] = 'moved';

View file

@ -96,7 +96,9 @@ $lang->select_category = '분류를 선택하세요.';
$lang->category_description = '분류 설명'; $lang->category_description = '분류 설명';
$lang->no_title_document = '제목이 없는 문서입니다.'; $lang->no_title_document = '제목이 없는 문서입니다.';
$lang->msg_admin_document_no_move_to_trash = '최고 관리자의 게시물을 휴지통으로 이동시킬 권한이 없습니다.'; $lang->msg_admin_document_no_move_to_trash = '최고 관리자의 게시물을 휴지통으로 이동시킬 권한이 없습니다.';
$lang->send_default_message = '기본 내용으로만 쪽지 보내기'; $lang->send_default_message = '기본 내용으로 쪽지 보내기';
$lang->send_custom_message = '아래 내용으로 쪽지 보내기';
$lang->send_no_message = '쪽지 보내지 않음';
$lang->default_message_format = '관리자에 의해 게시물이 %1$s되었습니다.'; $lang->default_message_format = '관리자에 의해 게시물이 %1$s되었습니다.';
$lang->default_message_verbs['move'] = '다른 게시판으로 이동'; $lang->default_message_verbs['move'] = '다른 게시판으로 이동';
$lang->default_message_verbs['copy'] = '다른 게시판에 복사'; $lang->default_message_verbs['copy'] = '다른 게시판에 복사';

View file

@ -3,6 +3,7 @@
<table name="modules" /> <table name="modules" />
</tables> </tables>
<columns> <columns>
<column name="domain_srl" />
<column name="module_srl" /> <column name="module_srl" />
<column name="mid" /> <column name="mid" />
<column name="browser_title" /> <column name="browser_title" />

View file

@ -1,8 +1,9 @@
<!--%import("filter/manage_checked_document.xml")--> <!--%import("filter/manage_checked_document.xml")-->
<load target="js/document_admin.js" /> <load target="js/document_admin.js" />
{@Context::addMetaTag('viewport', 'width=device-width', FALSE);} {@Context::addMetaTag('viewport', 'width=device-width', FALSE);}
<form action="./" method="get" id="fo_management"> <form action="./" method="post" id="fo_management">
<input type="hidden" name="module" value="document" /> <input type="hidden" name="module" value="document" />
<input type="hidden" name="act" value="procDocumentManageCheckedDocument" />
<input type="hidden" name="type" value="" /> <input type="hidden" name="type" value="" />
<div class="x_modal-header"> <div class="x_modal-header">
<h1>{$lang->cmd_manage_document}</h1> <h1>{$lang->cmd_manage_document}</h1>
@ -40,9 +41,21 @@
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label class="x_control-label" for="message_content">{$lang->cmd_send_message}</label> <label class="x_control-label" for="message_content">{$lang->cmd_send_message}</label>
<div class="x_controls" style="margin-right:14px"> <div class="x_controls" id="message_options">
<textarea name="message_content" id="message_content" rows="4" cols="42" style="width:100%"></textarea> <label for="send_default_message" class="x_inline">
<label for="send_default_message" class="x_inline"><input type="checkbox" name="send_default_message" id="send_default_message" value="Y" checked="checked" /> {$lang->send_default_message}</label> <input type="radio" name="send_message" id="send_default_message" value="default" checked="checked" />
{$lang->send_default_message}
</label>
<label for="send_custom_message" class="x_inline">
<input type="radio" name="send_message" id="send_custom_message" value="custom" />
{$lang->send_custom_message}
</label>
<label for="send_no_message" class="x_inline">
<input type="radio" name="send_message" id="send_no_message" value="none" />
{$lang->send_no_message}
</label>
<br />
<textarea name="message_content" id="message_content" rows="4" cols="42" class="x_full-width"></textarea>
</div> </div>
</div> </div>
</div> </div>
@ -60,20 +73,19 @@
</form> </form>
<script> <script>
jQuery(function($){ jQuery(function($){
var message_content_area = $('#message_content'); const message_options = $('#message_options');
if($('#send_default_message').is(':checked')) const message_content_area = $('#message_content');
{ message_content_area.prop('disabled', true);
message_content_area.prop("disabled", true); message_options.on('change', 'input[name="send_message"]', function(){
} if($('#send_custom_message').is(':checked')) {
$('#send_default_message').change(function(){
if($(this).is(':checked')){
message_content_area.prop("disabled", true);
} else {
message_content_area.prop("disabled", false); message_content_area.prop("disabled", false);
} else {
message_content_area.prop("disabled", true);
} }
}); });
<!--@if($module_srl > 0)--> const module_srl = {intval($module_srl)};
doGetCategoryFromModule({$module_srl}); if (module_srl > 0) {
<!--@end--> doGetCategoryFromModule(module_srl);
}
}); });
</script> </script>

View file

@ -50,11 +50,18 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<tr loop="$document_list => $no, $oDocument"> <tr loop="$document_list => $no, $oDocument">
<td class="title"> <td class="title">
<a href="{$oDocument->getPermanentUrl()}" target="_blank"><!--@if(trim($oDocument->getTitleText()) !== '')-->{escape($oDocument->getTitleText(), false)}<!--@else--><em>{$lang->no_title_document}</em><!--@end--></a> <!--@if(isset($module_list[$oDocument->get('module_srl')]))-->
<!--@if($module_list[$oDocument->get('module_srl')]->domain_srl == -1 || $module_list[$oDocument->get('module_srl')]->domain_srl == $site_module_info->domain_srl)-->
<span cond="isset($module_list[$oDocument->get('module_srl')])"> <a href="{$oDocument->getPermanentUrl()}" target="_blank"><!--@if(trim($oDocument->getTitleText()) !== '')-->{escape($oDocument->getTitleText(), false)}<!--@else--><em>{$lang->no_title_document}</em><!--@end--></a>
- <a href="{getUrl('', 'mid', $module_list[$oDocument->get('module_srl')]->mid)}" target="_blank">{$module_list[$oDocument->get('module_srl')]->browser_title}</a> - <a href="{getUrl('', 'mid', $module_list[$oDocument->get('module_srl')]->mid)}" target="_blank">{$module_list[$oDocument->get('module_srl')]->browser_title}</a>
</span></td> <!--@else-->
<a href="{ModuleModel::getDomainByModuleSrl($oDocument->get('module_srl'))}{getUrl('', 'mid', $module_list[$oDocument->get('module_srl')]->mid, 'document_srl', $oDocument->document_srl)}" target="_blank"><!--@if(trim($oDocument->getTitleText()) !== '')-->{escape($oDocument->getTitleText(), false)}<!--@else--><em>{$lang->no_title_document}</em><!--@end--></a>
- <a href="{ModuleModel::getDomainByModuleSrl($oDocument->get('module_srl'))}{getUrl('', 'mid', $module_list[$oDocument->get('module_srl')]->mid)}" target="_blank">{$module_list[$oDocument->get('module_srl')]->browser_title}</a>
<!--@endif-->
<!--@else-->
<a href="{$oDocument->getPermanentUrl()}" target="_blank"><!--@if(trim($oDocument->getTitleText()) !== '')-->{escape($oDocument->getTitleText(), false)}<!--@else--><em>{$lang->no_title_document}</em><!--@end--></a>
<!--@endif-->
</td>
<td class="nowr"> <td class="nowr">
<span cond="$oDocument->get('member_srl') <= 0">{$oDocument->getNickName()}</span> <span cond="$oDocument->get('member_srl') <= 0">{$oDocument->getNickName()}</span>
<a href="#popup_menu_area" class="member_{abs($oDocument->get('member_srl'))}" cond="$oDocument->get('member_srl') < 0">({$member_nick_name[abs($oDocument->get('member_srl'))]})</a> <a href="#popup_menu_area" class="member_{abs($oDocument->get('member_srl'))}" cond="$oDocument->get('member_srl') < 0">({$member_nick_name[abs($oDocument->get('member_srl'))]})</a>

View file

@ -3,6 +3,7 @@
<table name="modules" /> <table name="modules" />
</tables> </tables>
<columns> <columns>
<column name="domain_srl" />
<column name="module_srl" /> <column name="module_srl" />
<column name="mid" /> <column name="mid" />
<column name="browser_title" /> <column name="browser_title" />

View file

@ -84,11 +84,18 @@ xe.lang.msg_empty_search_keyword = '{$lang->msg_empty_search_keyword}';
<!--@if(preg_match('/^(?:ev:)?doc$/', $val->upload_target_type) && $document_list[$document_srl] && $document_list[$document_srl]->get('module_srl') == $document_list[$document_srl]->get('member_srl'))-->[{$lang->cmd_temp_save}] <!--@end--> <!--@if(preg_match('/^(?:ev:)?doc$/', $val->upload_target_type) && $document_list[$document_srl] && $document_list[$document_srl]->get('module_srl') == $document_list[$document_srl]->get('member_srl'))-->[{$lang->cmd_temp_save}] <!--@end-->
<!--@if(preg_match('/^(?:ev:)?doc$/', $val->upload_target_type) && $document_list[$document_srl] && $document_list[$document_srl]->get('module_srl') == 0)-->[{$lang->cmd_trash}] <!--@end--> <!--@if(preg_match('/^(?:ev:)?doc$/', $val->upload_target_type) && $document_list[$document_srl] && $document_list[$document_srl]->get('module_srl') == 0)-->[{$lang->cmd_trash}] <!--@end-->
<!--@if($val->module_srl && isset($module_list[$val->module_srl]))-->
<a href="{getUrl('', 'mid', $module_list[$val->module_srl]->mid)}" target="_blank">{$module_list[$val->module_srl]->browser_title}</a> <!--@if(isset($module_list[$val->module_srl]))-->
<!--@end--> <!--@if($module_list[$val->module_srl]->domain_srl == -1 || $module_list[$val->module_srl]->domain_srl == $site_module_info->domain_srl)-->
<a href="{getUrl('', 'mid', $module_list[$val->module_srl]->mid)}" target="_blank">{$module_list[$val->module_srl]->browser_title}</a> -
<!--@else-->
{@ $module_url = ModuleModel::getDomainByModuleSrl($val->module_srl); $move_uri = $module_url . $move_uri; }
<a href="{$module_url}{getUrl('', 'mid', $module_list[$val->module_srl]->mid)}" target="_blank">{$module_list[$val->module_srl]->browser_title}</a> -
<!--@endif-->
<!--@endif-->
<!--@if($document_list[$document_srl] && preg_match('/^(?:ev:)?(?:doc|com)$/', $val->upload_target_type))--> <!--@if($document_list[$document_srl] && preg_match('/^(?:ev:)?(?:doc|com)$/', $val->upload_target_type))-->
- <!--@if($document_list[$document_srl]->get('module_srl') != $document_list[$document_srl]->get('member_srl'))--><a href="{$move_uri}" target="_blank">{$document_list[$document_srl]->getTitle()}</a><!--@else-->{$document_list[$document_srl]->getTitle()}<!--@end--> <!--@if($document_list[$document_srl]->get('module_srl') != $document_list[$document_srl]->get('member_srl'))--><a href="{$move_uri}" target="_blank">{$document_list[$document_srl]->getTitle()}</a><!--@else-->{$document_list[$document_srl]->getTitle()}<!--@end-->
<!--@end--> <!--@end-->
<!--@end--> <!--@end-->
</th> </th>

View file

@ -2374,7 +2374,7 @@ jQuery(function($){
case 'member': case 'member':
case 'not_member': case 'not_member':
case 'site': case 'site':
$node.find('._group_loggedin').prop('selected', true); //$node.find('._group_loggedin').prop('selected', true);
break; break;
case 'manager': case 'manager':
case 'root': case 'root':

View file

@ -80,8 +80,7 @@ $lang->msg_extra_name_exists = 'Already registered field ID. Please input anothe
$lang->about_browser_title = 'It will be shown in the browser title. It will be also used in a RSS/Trackback.'; $lang->about_browser_title = 'It will be shown in the browser title. It will be also used in a RSS/Trackback.';
$lang->about_mid = 'The module name must begin with a Latin alphabet, and only consist of Latin alphabets, numerals, and underscores.'; $lang->about_mid = 'The module name must begin with a Latin alphabet, and only consist of Latin alphabets, numerals, and underscores.';
$lang->about_default = 'If checked, this module will be shown when users access the site without mid value (mid=NoValue).'; $lang->about_default = 'If checked, this module will be shown when users access the site without mid value (mid=NoValue).';
$lang->about_module_category = 'It enables you to manage it through a module category. $lang->about_module_category = 'Module categories can be edited in <a href="./?module=admin&amp;act=dispModuleAdminCategory" target="_blank">Module category</a>.';
The URL for the module manager is <a href="./?module=admin&amp;act=dispModuleAdminCategory">Module category </a>.';
$lang->about_description = 'This description is only for a manager.'; $lang->about_description = 'This description is only for a manager.';
$lang->about_header_text = 'The contents will be shown on the top of the module. (html tags available)'; $lang->about_header_text = 'The contents will be shown on the top of the module. (html tags available)';
$lang->about_footer_text = 'The contents will be shown on the bottom of the module. (html tags available)'; $lang->about_footer_text = 'The contents will be shown on the bottom of the module. (html tags available)';

View file

@ -80,7 +80,7 @@ $lang->msg_extra_name_exists = '이미 존재하는 확장 변수 ID입니다.
$lang->about_browser_title = '브라우저 제목에 나타나는 값입니다. RSS/Trackback에서도 사용됩니다.'; $lang->about_browser_title = '브라우저 제목에 나타나는 값입니다. RSS/Trackback에서도 사용됩니다.';
$lang->about_mid = 'URL상의 모듈 이름은 영문, 숫자, _ 만으로 이루어져야 하며, 첫 글자는 반드시 영문 알파벳이어야 합니다.'; $lang->about_mid = 'URL상의 모듈 이름은 영문, 숫자, _ 만으로 이루어져야 하며, 첫 글자는 반드시 영문 알파벳이어야 합니다.';
$lang->about_default = '선택하면 사이트에 mid값 없이 접속하였을 경우 기본으로 보여줍니다.'; $lang->about_default = '선택하면 사이트에 mid값 없이 접속하였을 경우 기본으로 보여줍니다.';
$lang->about_module_category = '분류를 통한 관리를 할 수 있도록 합니다. 모듈 분류 관리는 <a href="./?module=admin&amp;act=dispModuleAdminCategory">모듈분류</a>에서 할 수 있습니다.'; $lang->about_module_category = '모듈 분류 관리는 <a href="./?module=admin&amp;act=dispModuleAdminCategory" target="_blank">모듈 분류</a>에서 할 수 있습니다.';
$lang->about_description = '관리용으로 사용되는 설명입니다.'; $lang->about_description = '관리용으로 사용되는 설명입니다.';
$lang->about_header_text = '콘텐츠 상단에 표시되는 내용입니다. (HTML 태그 사용 가능)'; $lang->about_header_text = '콘텐츠 상단에 표시되는 내용입니다. (HTML 태그 사용 가능)';
$lang->about_footer_text = '콘텐츠 하단에 표시되는 내용입니다. (HTML 태그 사용 가능)'; $lang->about_footer_text = '콘텐츠 하단에 표시되는 내용입니다. (HTML 태그 사용 가능)';

View file

@ -656,8 +656,8 @@ class ModuleController extends Module
{ {
unset($args); unset($args);
$args = new stdClass; $args = new stdClass;
$args->menu_srl = $output->data->menu_srl; $args->menu_srl = $output->data->menu_srl ?: 0;
$args->menu_item_srl = $output->data->menu_item_srl; $args->menu_item_srl = $output->data->menu_item_srl ?: 0;
$args->is_force = 'N'; $args->is_force = 'N';
$oMenuAdminController = getAdminController('menu'); $oMenuAdminController = getAdminController('menu');

View file

@ -12,6 +12,7 @@ class ModuleModel extends Module
*/ */
public static $_mid_map = []; public static $_mid_map = [];
public static $_module_srl_map = []; public static $_module_srl_map = [];
public static $_domain_map = [];
/** /**
* @brief Initialization * @brief Initialization
@ -708,13 +709,13 @@ class ModuleModel extends Module
$mid = Rhymix\Framework\Cache::get('site_and_module:module_srl_mid:' . $module_srl); $mid = Rhymix\Framework\Cache::get('site_and_module:module_srl_mid:' . $module_srl);
if (isset($mid)) if (isset($mid))
{ {
return $mid; return self::$_module_srl_map[$module_srl] = $mid;
} }
$args = new stdClass; $args = new stdClass;
$args->module_srls = $module_srl; $args->module_srls = $module_srl;
$output = executeQuery('module.getModuleInfoByModuleSrl', $args, ['mid']); $output = executeQuery('module.getModuleInfoByModuleSrl', $args, ['mid']);
if ($output->data) if (is_object($output->data))
{ {
$mid = self::$_module_srl_map[$module_srl] = $output->data->mid; $mid = self::$_module_srl_map[$module_srl] = $output->data->mid;
Rhymix\Framework\Cache::set('site_and_module:module_srl_mid:' . $module_srl, $mid, 0, true); Rhymix\Framework\Cache::set('site_and_module:module_srl_mid:' . $module_srl, $mid, 0, true);
@ -726,6 +727,60 @@ class ModuleModel extends Module
} }
} }
/**
* Return the domain (including scheme and port) by module_srl
*
* @param int $module_srl
* @return ?string
*/
public static function getDomainByModuleSrl(int $module_srl): ?string
{
$module_srl = intval($module_srl);
if (isset(self::$_domain_map[$module_srl]))
{
return self::$_domain_map[$module_srl];
}
$prefix = Rhymix\Framework\Cache::get('site_and_module:module_srl_prefix:' . $module_srl);
if (isset($prefix))
{
self::$_domain_map[$module_srl] = $prefix;
return $prefix;
}
$args = new stdClass;
$args->module_srls = $module_srl;
$args->include_domain_info = true;
$output = executeQuery('module.getModuleInfoByModuleSrl', $args);
if (is_object($output->data))
{
$info = self::$_module_srl_map[$module_srl] = $output->data;
if (!$info->domain_srl || $info->domain_srl == -1 || !isset($info->domain))
{
$prefix = '';
}
else
{
$prefix = $info->security === 'always' ? 'https://' : 'http://';
$prefix .= $info->domain;
if ($info->security === 'always' && $info->https_port)
{
$prefix .= ':' . $info->https_port;
}
if ($info->security !== 'always' && $info->http_port)
{
$prefix .= ':' . $info->http_port;
}
}
Rhymix\Framework\Cache::set('site_and_module:module_srl_prefix:' . $module_srl, $prefix, 0, true);
return $prefix;
}
else
{
return null;
}
}
/** /**
* @brief Get forward value by the value of act * @brief Get forward value by the value of act
*/ */

View file

@ -1,8 +1,20 @@
<query id="getModuleInfoByModuleSrl" action="select"> <query id="getModuleInfoByModuleSrl" action="select">
<tables> <tables>
<table name="modules" /> <table name="modules" />
<table name="domains" type="left join" if="include_domain_info">
<conditions>
<condition operation="equal" column="domains.domain_srl" var="modules.domain_srl" />
</conditions>
</table>
</tables> </tables>
<columns>
<column name="modules.*" />
<column name="domains.domain" if="include_domain_info" />
<column name="domains.security" if="include_domain_info" />
<column name="domains.http_port" if="include_domain_info" />
<column name="domains.https_port" if="include_domain_info" />
</columns>
<conditions> <conditions>
<condition operation="in" column="module_srl" var="module_srls" notnull="notnull" /> <condition operation="in" column="modules.module_srl" var="module_srls" notnull="notnull" />
</conditions> </conditions>
</query> </query>

View file

@ -231,32 +231,72 @@ class PointAdminController extends Point
function procPointAdminInsertPointModuleConfig() function procPointAdminInsertPointModuleConfig()
{ {
$module_srl = Context::get('target_module_srl'); $module_srl = Context::get('target_module_srl');
if(!$module_srl) throw new Rhymix\Framework\Exceptions\InvalidRequest; if (!$module_srl)
{
throw new Rhymix\Framework\Exceptions\InvalidRequest;
}
// In case of batch configuration of several modules // In case of batch configuration of several modules
if(preg_match('/^([0-9,]+)$/',$module_srl)) $module_srl = explode(',',$module_srl); if (preg_match('/^([0-9,]+)$/',$module_srl))
else $module_srl = array($module_srl); {
$module_srl = explode(',',$module_srl);
}
else
{
$module_srl = array($module_srl);
}
// Save configurations // Save configurations
$oModuleController = getController('module'); $oModuleController = getController('module');
for($i=0;$i<count($module_srl);$i++) for($i=0;$i<count($module_srl);$i++)
{ {
$srl = trim($module_srl[$i]); $srl = trim($module_srl[$i] ?? '');
if(!$srl) continue; if (!$srl)
unset($config); {
$config['insert_document'] = (int)Context::get('insert_document'); continue;
$config['insert_comment'] = (int)Context::get('insert_comment'); }
$config['upload_file'] = (int)Context::get('upload_file');
$config['download_file'] = (int)Context::get('download_file'); $config = [];
$config['read_document'] = (int)Context::get('read_document'); $numeric_keys = [
$config['voter'] = (int)Context::get('voter'); 'insert_document',
$config['blamer'] = (int)Context::get('blamer'); 'insert_comment',
$config['voter_comment'] = (int)Context::get('voter_comment'); 'upload_file',
$config['blamer_comment'] = (int)Context::get('blamer_comment'); 'download_file',
$config['download_file_author'] = (int)Context::get('download_file_author'); 'read_document',
$config['read_document_author'] = (int)Context::get('read_document_author'); 'voter',
$config['voted'] = (int)Context::get('voted'); 'blamer',
$config['blamed'] = (int)Context::get('blamed'); 'voter_comment',
$config['voted_comment'] = (int)Context::get('voted_comment'); 'blamer_comment',
$config['blamed_comment'] = (int)Context::get('blamed_comment'); 'download_file_author',
'read_document_author',
'voted',
'blamed',
'voted_comment',
'blamed_comment'
];
$boolean_keys = [
'insert_document_revert_on_delete',
'insert_comment_revert_on_delete',
'upload_file_revert_on_delete'
];
foreach ($numeric_keys as $key)
{
$value = trim(Context::get($key) ?? '');
if ($value !== '')
{
$config[$key] = (int)$value;
}
}
foreach ($boolean_keys as $key)
{
$value = trim(Context::get($key) ?? '');
if ($value !== '')
{
$config[$key] = ($value === 'Y');
}
}
$oModuleController->insertModulePartConfig('point', $srl, $config); $oModuleController->insertModulePartConfig('point', $srl, $config);
} }

View file

@ -211,8 +211,8 @@ class PointController extends Point
} }
// Return if disabled // Return if disabled
$config = $this->getConfig(); $revert = PointModel::getModulePointConfig($module_srl, 'insert_document_revert_on_delete');
if ($config->insert_document_revert_on_delete === false) if ($revert === false)
{ {
return; return;
} }
@ -319,8 +319,8 @@ class PointController extends Point
} }
// Return if disabled // Return if disabled
$config = $this->getConfig(); $revert = PointModel::getModulePointConfig($module_srl, 'insert_comment_revert_on_delete');
if ($config->insert_comment_revert_on_delete === false) if ($revert === false)
{ {
return; return;
} }
@ -333,6 +333,7 @@ class PointController extends Point
} }
// Abort if the document is older than a configured limit. // Abort if the document is older than a configured limit.
$config = $this->getConfig();
$time_limit = $config->insert_comment_limit ?: $config->no_point_date; $time_limit = $config->insert_comment_limit ?: $config->no_point_date;
if ($time_limit > 0 && ztime($oDocument->get('regdate')) < RX_TIME - ($time_limit * 86400)) if ($time_limit > 0 && ztime($oDocument->get('regdate')) < RX_TIME - ($time_limit * 86400))
{ {
@ -381,14 +382,12 @@ class PointController extends Point
} }
// Return if disabled // Return if disabled
$config = $this->getConfig(); $revert = PointModel::getModulePointConfig($module_srl, 'upload_file_revert_on_delete');
if ($config->upload_file_revert_on_delete === false) if ($revert === false)
{ {
return; return;
} }
// Get the points of the member
// Subtract points for the file. // Subtract points for the file.
$diff = PointModel::getModulePointConfig($module_srl, 'upload_file'); $diff = PointModel::getModulePointConfig($module_srl, 'upload_file');

View file

@ -271,7 +271,7 @@ class PointModel extends Point
* *
* @param int $module_srl * @param int $module_srl
* @param string $config_key * @param string $config_key
* @return int * @return int|bool
*/ */
public static function getModulePointConfig($module_srl, $config_key) public static function getModulePointConfig($module_srl, $config_key)
{ {
@ -306,10 +306,10 @@ class PointModel extends Point
else else
{ {
$default_config = self::getConfig(); $default_config = self::getConfig();
$point = $default_config->{$config_key}; $point = $default_config->{$config_key} ?? 0;
} }
return intval($point); return is_bool($point) ? $point : intval($point);
} }
} }
/* End of file point.model.php */ /* End of file point.model.php */

View file

@ -1,7 +1,6 @@
<load target="js/point_admin.js" /> <load target="js/point_admin.js" />
<section class="section"> <section class="section">
<h1>{$lang->point}</h1> <h1>{$lang->point}</h1>
<form action="./" method="post" id="fo_point" class="x_form-horizontal"> <form action="./" method="post" id="fo_point" class="x_form-horizontal">
<input type="hidden" name="module" value="point" /> <input type="hidden" name="module" value="point" />
<input type="hidden" name="act" value="procPointAdminInsertPointModuleConfig" /> <input type="hidden" name="act" value="procPointAdminInsertPointModuleConfig" />
@ -11,91 +10,109 @@
<div class="x_control-group"> <div class="x_control-group">
<label for="insert_document" class="x_control-label">{$lang->point_insert_document}</label> <label for="insert_document" class="x_control-label">{$lang->point_insert_document}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="insert_document" id="insert_document" value="{$module_config['insert_document'] ?? null}" /> {$module_config['point_name']} <input type="number" name="insert_document" id="insert_document" value="{$module_config['insert_document'] ?? ''}" /> {$module_config['point_name']}
&nbsp; {$lang->cmd_point_revert_on_delete}
<select name="insert_document_revert_on_delete">
<option value="" selected="selected"|cond="!isset($module_config['insert_document_revert_on_delete'])">{$lang->default_value}</option>
<option value="Y" selected="selected"|cond="($module_config['insert_document_revert_on_delete'] ?? null) === true">{$lang->cmd_yes}</option>
<option value="N" selected="selected"|cond="($module_config['insert_document_revert_on_delete'] ?? null) === false">{$lang->cmd_no}</option>
</select>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="insert_comment" class="x_control-label">{$lang->point_insert_comment}</label> <label for="insert_comment" class="x_control-label">{$lang->point_insert_comment}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="insert_comment" id="insert_comment" value="{$module_config['insert_comment'] ?? null}" /> {$module_config['point_name']} <input type="number" name="insert_comment" id="insert_comment" value="{$module_config['insert_comment'] ?? ''}" /> {$module_config['point_name']}
&nbsp; {$lang->cmd_point_revert_on_delete}
<select name="insert_comment_revert_on_delete">
<option value="" selected="selected"|cond="!isset($module_config['insert_comment_revert_on_delete'])">{$lang->default_value}</option>
<option value="Y" selected="selected"|cond="($module_config['insert_comment_revert_on_delete'] ?? null) === true">{$lang->cmd_yes}</option>
<option value="N" selected="selected"|cond="($module_config['insert_comment_revert_on_delete'] ?? null) === false">{$lang->cmd_no}</option>
</select>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="upload_file" class="x_control-label">{$lang->point_upload_file}</label> <label for="upload_file" class="x_control-label">{$lang->point_upload_file}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="upload_file" id="upload_file" value="{$module_config['upload_file'] ?? null}" /> {$module_config['point_name']} <input type="number" name="upload_file" id="upload_file" value="{$module_config['upload_file'] ?? ''}" /> {$module_config['point_name']}
&nbsp; {$lang->cmd_point_revert_on_delete}
<select name="upload_file_revert_on_delete">
<option value="" selected="selected"|cond="!isset($module_config['upload_file_revert_on_delete'])">{$lang->default_value}</option>
<option value="Y" selected="selected"|cond="($module_config['upload_file_revert_on_delete'] ?? null) === true">{$lang->cmd_yes}</option>
<option value="N" selected="selected"|cond="($module_config['upload_file_revert_on_delete'] ?? null) === false">{$lang->cmd_no}</option>
</select>
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="download_file" class="x_control-label">{$lang->point_download_file}</label> <label for="download_file" class="x_control-label">{$lang->point_download_file}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="download_file" id="download_file" value="{$module_config['download_file'] ?? null}" /> {$module_config['point_name']} <input type="number" name="download_file" id="download_file" value="{$module_config['download_file'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="read_document" class="x_control-label">{$lang->point_read_document}</label> <label for="read_document" class="x_control-label">{$lang->point_read_document}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="read_document" id="read_document" value="{$module_config['read_document'] ?? null}" /> {$module_config['point_name']} <input type="number" name="read_document" id="read_document" value="{$module_config['read_document'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="voter" class="x_control-label">{$lang->point_voter}</label> <label for="voter" class="x_control-label">{$lang->point_voter}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="voter" id="voter" value="{$module_config['voter'] ?? null}" /> {$module_config['point_name']} <input type="number" name="voter" id="voter" value="{$module_config['voter'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="blamer" class="x_control-label">{$lang->point_blamer}</label> <label for="blamer" class="x_control-label">{$lang->point_blamer}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="blamer" id="blamer" value="{$module_config['blamer'] ?? null}" /> {$module_config['point_name']} <input type="number" name="blamer" id="blamer" value="{$module_config['blamer'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="voter_comment" class="x_control-label">{$lang->point_voter_comment}</label> <label for="voter_comment" class="x_control-label">{$lang->point_voter_comment}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="voter_comment" id="voter_comment" value="{$module_config['voter_comment'] ?? null}" /> {$module_config['point_name']} <input type="number" name="voter_comment" id="voter_comment" value="{$module_config['voter_comment'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="blamer_comment" class="x_control-label">{$lang->point_blamer_comment}</label> <label for="blamer_comment" class="x_control-label">{$lang->point_blamer_comment}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="blamer_comment" id="blamer_comment" value="{$module_config['blamer_comment'] ?? null}" /> {$module_config['point_name']} <input type="number" name="blamer_comment" id="blamer_comment" value="{$module_config['blamer_comment'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="download_file_author" class="x_control-label">{$lang->point_download_file_author}</label> <label for="download_file_author" class="x_control-label">{$lang->point_download_file_author}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="download_file_author" id="download_file_author" value="{$module_config['download_file_author'] ?? null}" /> {$module_config['point_name']} <input type="number" name="download_file_author" id="download_file_author" value="{$module_config['download_file_author'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="read_document_author" class="x_control-label">{$lang->point_read_document_author}</label> <label for="read_document_author" class="x_control-label">{$lang->point_read_document_author}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="read_document_author" id="read_document_author" value="{$module_config['read_document_author'] ?? null}" /> {$module_config['point_name']} <input type="number" name="read_document_author" id="read_document_author" value="{$module_config['read_document_author'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="voted" class="x_control-label">{$lang->point_voted}</label> <label for="voted" class="x_control-label">{$lang->point_voted}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="voted" id="voted" value="{$module_config['voted'] ?? null}" /> {$module_config['point_name']} <input type="number" name="voted" id="voted" value="{$module_config['voted'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="blamed" class="x_control-label">{$lang->point_blamed}</label> <label for="blamed" class="x_control-label">{$lang->point_blamed}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="blamed" id="blamed" value="{$module_config['blamed'] ?? null}" /> {$module_config['point_name']} <input type="number" name="blamed" id="blamed" value="{$module_config['blamed'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="voted_comment" class="x_control-label">{$lang->point_voted_comment}</label> <label for="voted_comment" class="x_control-label">{$lang->point_voted_comment}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="voted_comment" id="voted_comment" value="{$module_config['voted_comment'] ?? null}" /> {$module_config['point_name']} <input type="number" name="voted_comment" id="voted_comment" value="{$module_config['voted_comment'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_control-group"> <div class="x_control-group">
<label for="blamed_comment" class="x_control-label">{$lang->point_blamed_comment}</label> <label for="blamed_comment" class="x_control-label">{$lang->point_blamed_comment}</label>
<div class="x_controls"> <div class="x_controls">
<input type="number" name="blamed_comment" id="blamed_comment" value="{$module_config['blamed_comment'] ?? null}" /> {$module_config['point_name']} <input type="number" name="blamed_comment" id="blamed_comment" value="{$module_config['blamed_comment'] ?? ''}" /> {$module_config['point_name']}
</div> </div>
</div> </div>
<div class="x_clearfix btnArea"> <div class="x_clearfix btnArea">

View file

@ -15,6 +15,7 @@
</conditions> </conditions>
<groups if="if_groupby"> <groups if="if_groupby">
<group column="member.member_srl" /> <group column="member.member_srl" />
<group column="member.nick_name" if="if_groupby_nick_name" />
<having> <having>
<condition operation="notequal" column="member.member_srl" var="exclude_member_srl" notnull="notnull" /> <condition operation="notequal" column="member.member_srl" var="exclude_member_srl" notnull="notnull" />
</having> </having>

View file

@ -178,7 +178,8 @@ class DBQueryParserTest extends \Codeception\Test\Unit
$this->assertEquals('AND', $query->conditions[1]->pipe); $this->assertEquals('AND', $query->conditions[1]->pipe);
$this->assertTrue($query->groupby instanceof Rhymix\Framework\Parsers\DBQuery\GroupBy); $this->assertTrue($query->groupby instanceof Rhymix\Framework\Parsers\DBQuery\GroupBy);
$this->assertEquals('member.member_srl', $query->groupby->columns[0]); $this->assertEquals(['member.member_srl', null], $query->groupby->columns[0]);
$this->assertEquals(['member.nick_name', 'if_groupby_nick_name'], $query->groupby->columns[1]);
$this->assertEquals(1, count($query->groupby->having)); $this->assertEquals(1, count($query->groupby->having));
$this->assertTrue($query->groupby->having[0] instanceof Rhymix\Framework\Parsers\DBQuery\Condition); $this->assertTrue($query->groupby->having[0] instanceof Rhymix\Framework\Parsers\DBQuery\Condition);
$this->assertEquals('member.member_srl', $query->groupby->having[0]->column); $this->assertEquals('member.member_srl', $query->groupby->having[0]->column);
@ -196,6 +197,12 @@ class DBQueryParserTest extends \Codeception\Test\Unit
'AND `documents`.`document_srl` IN (?, ?, ?) GROUP BY `member`.`member_srl` HAVING `member`.`member_srl` != ?', $sql); 'AND `documents`.`document_srl` IN (?, ?, ?) GROUP BY `member`.`member_srl` HAVING `member`.`member_srl` != ?', $sql);
$this->assertEquals(['12', '34', '56', '4'], $params); $this->assertEquals(['12', '34', '56', '4'], $params);
$args['if_groupby_nick_name'] = true;
$sql = $query->getQueryString('rx_', $args);
$this->assertEquals('SELECT `member`.`member_srl`, COUNT(*) AS `count` FROM `rx_documents` AS `documents`, `rx_member` AS `member` ' .
'WHERE `documents`.`member_srl` = `member`.`member_srl` AND `documents`.`member_srl` = `member`.`member_srl` ' .
'AND `documents`.`document_srl` IN (?, ?, ?) GROUP BY `member`.`member_srl`, `member`.`nick_name` HAVING `member`.`member_srl` != ?', $sql);
$args = array( $args = array(
'document_srl_list' => [12, 34, 56], 'exclude_member_srl' => 4, 'exclude_document_srl_list' => '78,90', 'document_srl_list' => [12, 34, 56], 'exclude_member_srl' => 4, 'exclude_document_srl_list' => '78,90',
'if_table' => true, 'if_column' => true, 'if_condition2' => true, 'if_table' => true, 'if_column' => true, 'if_condition2' => true,

View file

@ -1,6 +1,6 @@
<load target="./js/content_widget.js" cond="$widget_info->page_count || (is_countable($widget_info->tab) && count($widget_info->tab))" /> <load target="./js/content_widget.js" cond="$widget_info->page_count || (is_countable($widget_info->tab) && count($widget_info->tab))" />
<!--// Check layout. If it is Simple World, select layout primary colors as a primary color of this skin --> <!--// Check layout. If it is Simple World, select layout primary colors as a primary color of this skin -->
{@$layout_info = Context::get('layout_info')} {@$layout_info = Context::get('layout_info') ?? new stdClass();}
<block cond="$layout_info->extra_var->primary_color->type === 'select' || $layout_info->extra_var->customized_primary_color->type === 'colorpicker'"> <block cond="$layout_info->extra_var->primary_color->type === 'select' || $layout_info->extra_var->customized_primary_color->type === 'colorpicker'">
{@ {@
if(!$layout_info->primary_color) if(!$layout_info->primary_color)