mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-05 09:41:40 +09:00
Merge branch 'rhymix:master' into develop
This commit is contained in:
commit
6e84829da4
80 changed files with 656 additions and 440 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -2,11 +2,11 @@ name: PHP Lint & Codeception
|
|||
on: [ push, pull_request ]
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-24.04
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: [ '7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3' ]
|
||||
php: [ '7.4', '8.0', '8.1', '8.2', '8.3' ]
|
||||
|
||||
name: PHP ${{ matrix.php }}
|
||||
steps:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ Rhymix는 개발자와 사용자가 서로의 권리와 책임을 존중하는
|
|||
|
||||
### 설치 환경
|
||||
|
||||
Rhymix를 사용하려면 PHP 7.2.5 이상, MySQL 또는 MariaDB가 필요합니다.
|
||||
Rhymix를 사용하려면 PHP 7.4 이상, MySQL 또는 MariaDB가 필요합니다.
|
||||
자세한 설치 환경은 [매뉴얼](https://rhymix.org/manual/introduction/requirements)을 참고하십시오.
|
||||
|
||||
### 개발 참여
|
||||
|
|
@ -108,7 +108,7 @@ This requires the most convenience for the average user over any other CMS.
|
|||
|
||||
### Installation Environment
|
||||
|
||||
Rhymix requires PHP 7.2.5 or higher, and MySQL or MariaDB.
|
||||
Rhymix requires PHP 7.4 or higher, and MySQL or MariaDB.
|
||||
Please see the [online manual](https://rhymix.org/manual/introduction/requirements) for more information on server requirements.
|
||||
|
||||
### Participation in Development
|
||||
|
|
|
|||
|
|
@ -2879,14 +2879,10 @@ class Context
|
|||
{
|
||||
return isset(self::$_instance->meta_tags[$name]) ? self::$_instance->meta_tags[$name]['content'] : null;
|
||||
}
|
||||
|
||||
$ret = array();
|
||||
foreach(self::$_instance->meta_tags as $name => $content)
|
||||
else
|
||||
{
|
||||
$ret[] = array('name' => $name, 'is_http_equiv' => $content['is_http_equiv'], 'content' => escape($content['content'], false));
|
||||
return array_values(self::$_instance->meta_tags);
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2894,14 +2890,17 @@ class Context
|
|||
*
|
||||
* @param string $name name of meta tag
|
||||
* @param string $content content of meta tag
|
||||
* @param mixed $is_http_equiv value of http_equiv
|
||||
* @param bool $is_http_equiv
|
||||
* @param bool $is_before_title
|
||||
* @return void
|
||||
*/
|
||||
public static function addMetaTag($name, $content, $is_http_equiv = false)
|
||||
public static function addMetaTag($name, $content, $is_http_equiv = false, $is_before_title = true)
|
||||
{
|
||||
self::$_instance->meta_tags[$name] = array(
|
||||
'name' => $name,
|
||||
'content' => escape(self::replaceUserLang($content, true), false),
|
||||
'is_http_equiv' => (bool)$is_http_equiv,
|
||||
'content' => self::replaceUserLang($content, true),
|
||||
'is_before_title' => (bool)$is_before_title,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,7 @@ class HTMLDisplayHandler
|
|||
{
|
||||
|
||||
// handle separately if the layout is faceoff
|
||||
if($layout_info && $layout_info->type == 'faceoff')
|
||||
if($layout_info && isset($layout_info->type) && $layout_info->type == 'faceoff')
|
||||
{
|
||||
$oLayoutModel->doActivateFaceOff($layout_info);
|
||||
Context::set('layout_info', $layout_info);
|
||||
|
|
@ -196,6 +196,12 @@ class HTMLDisplayHandler
|
|||
Context::set('favicon_url', $favicon_url);
|
||||
Context::set('mobicon_url', $mobicon_url);
|
||||
|
||||
// Only print the X-UA-Compatible meta tag if somebody is still using IE
|
||||
if (preg_match('!Trident/7\.0!', $_SERVER['HTTP_USER_AGENT'] ?? ''))
|
||||
{
|
||||
Context::addMetaTag('X-UA-Compatible', 'IE=edge', true);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
|
|
@ -641,7 +647,7 @@ class HTMLDisplayHandler
|
|||
{
|
||||
if ($tag !== '')
|
||||
{
|
||||
Context::addOpenGraphData('og:article:tag', $tag, false);
|
||||
Context::addOpenGraphData('og:article:tag', $tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -683,21 +689,21 @@ class HTMLDisplayHandler
|
|||
function _addTwitterMetadata()
|
||||
{
|
||||
$card_type = $this->_image_type === 'document' ? 'summary_large_image' : 'summary';
|
||||
Context::addMetaTag('twitter:card', $card_type);
|
||||
Context::addMetaTag('twitter:card', $card_type, false, false);
|
||||
|
||||
foreach(Context::getOpenGraphData() as $val)
|
||||
{
|
||||
if ($val['property'] === 'og:title')
|
||||
{
|
||||
Context::addMetaTag('twitter:title', $val['content']);
|
||||
Context::addMetaTag('twitter:title', $val['content'], false, false);
|
||||
}
|
||||
if ($val['property'] === 'og:description')
|
||||
{
|
||||
Context::addMetaTag('twitter:description', $val['content']);
|
||||
Context::addMetaTag('twitter:description', $val['content'], false, false);
|
||||
}
|
||||
if ($val['property'] === 'og:image' && $this->_image_type === 'document')
|
||||
{
|
||||
Context::addMetaTag('twitter:image', $val['content']);
|
||||
Context::addMetaTag('twitter:image', $val['content'], false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -693,7 +693,8 @@ class ModuleHandler extends Handler
|
|||
}
|
||||
}
|
||||
|
||||
if ($kind === 'admin') {
|
||||
if ($kind === 'admin')
|
||||
{
|
||||
Context::addMetaTag('robots', 'noindex');
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -370,28 +370,36 @@ class ModuleObject extends BaseObject
|
|||
}
|
||||
}
|
||||
// If permission is 'manager', check 'is user have manager privilege(granted)'
|
||||
else if(preg_match('/^(manager|([a-z0-9\_]+)-managers)$/', $permission, $type))
|
||||
else if(preg_match('/^(manager(?::(.+))?|([a-z0-9\_]+)-managers)$/', $permission, $type))
|
||||
{
|
||||
if($grant->manager)
|
||||
// If permission is manager(:scope), check manager privilege and scope
|
||||
if ($grant->manager)
|
||||
{
|
||||
return true;
|
||||
if (empty($type[2]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
elseif ($grant->can($type[2]))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If permission is '*-managers', search modules to find manager privilege of the member
|
||||
if(Context::get('is_logged') && isset($type[2]))
|
||||
if(Context::get('is_logged') && isset($type[3]))
|
||||
{
|
||||
// Manager privilege of the member is found by search all modules, Pass
|
||||
if($type[2] == 'all' && ModuleModel::findManagerPrivilege($member_info) !== false)
|
||||
if($type[3] == 'all' && ModuleModel::findManagerPrivilege($member_info) !== false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Manager privilege of the member is found by search same module as this module, Pass
|
||||
elseif($type[2] == 'same' && ModuleModel::findManagerPrivilege($member_info, $this->module) !== false)
|
||||
elseif($type[3] == 'same' && ModuleModel::findManagerPrivilege($member_info, $this->module) !== false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
// Manager privilege of the member is found by search same module as the module, Pass
|
||||
elseif(ModuleModel::findManagerPrivilege($member_info, $type[2]) !== false)
|
||||
elseif(ModuleModel::findManagerPrivilege($member_info, $type[3]) !== false)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,10 +11,10 @@ if (defined('RX_VERSION'))
|
|||
/**
|
||||
* Check PHP version.
|
||||
*/
|
||||
if (PHP_VERSION_ID < 70205)
|
||||
if (PHP_VERSION_ID < 70400)
|
||||
{
|
||||
header('HTTP/1.1 500 Internal Server Error');
|
||||
echo 'Rhymix requires PHP 7.2.5 or higher.';
|
||||
echo 'Rhymix requires PHP 7.4 or higher.';
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
/**
|
||||
* RX_VERSION is the version number of the Rhymix CMS.
|
||||
*/
|
||||
define('RX_VERSION', '2.1.18');
|
||||
define('RX_VERSION', '2.1.19');
|
||||
|
||||
/**
|
||||
* RX_MICROTIME is the startup time of the current script, in microseconds since the Unix epoch.
|
||||
|
|
@ -125,7 +125,7 @@ else
|
|||
/**
|
||||
* RX_WINDOWS is true if the operating system is Windows.
|
||||
*/
|
||||
define('RX_WINDOWS', strncasecmp(PHP_OS, 'WIN', 3) === 0);
|
||||
define('RX_WINDOWS', PHP_OS_FAMILY === 'Windows');
|
||||
|
||||
/**
|
||||
* XE core compatibility constants (may be used by XE-compatible plugins and themes).
|
||||
|
|
@ -143,7 +143,7 @@ define('__XE_VERSION_ALPHA__', false);
|
|||
define('__XE_VERSION_BETA__', false);
|
||||
define('__XE_VERSION_RC__', false);
|
||||
define('__XE_VERSION_STABLE__', true);
|
||||
define('__XE_MIN_PHP_VERSION__', '7.2.5');
|
||||
define('__XE_MIN_PHP_VERSION__', '7.4.0');
|
||||
define('__XE_RECOMMEND_PHP_VERSION__', '7.4.0');
|
||||
define('__ZBXE_VERSION__', RX_VERSION);
|
||||
define('_XE_LOCATION_', 'ko');
|
||||
|
|
|
|||
|
|
@ -151,5 +151,7 @@ return array(
|
|||
],
|
||||
'use_rewrite' => true,
|
||||
'use_sso' => false,
|
||||
'other' => array(),
|
||||
'other' => [
|
||||
'proxy' => null,
|
||||
],
|
||||
);
|
||||
|
|
|
|||
|
|
@ -79,24 +79,7 @@ class Cookie
|
|||
$options['samesite'] = config('cookie.samesite') ?? 'Lax';
|
||||
}
|
||||
|
||||
// PHP 7.3+ supports the samesite attribute natively. PHP 7.2 requires a hack.
|
||||
if (\PHP_VERSION_ID >= 70300)
|
||||
{
|
||||
$result = setcookie($name, $value, $options);
|
||||
}
|
||||
else
|
||||
{
|
||||
$expires = $options['expires'];
|
||||
$path = $options['path'] ?? '/';
|
||||
$domain = $options['domain'] ?? null;
|
||||
$secure = $options['secure'] ?? false;
|
||||
$httponly = $options['httponly'] ?? false;
|
||||
if (!empty($options['samesite']))
|
||||
{
|
||||
$path = ($path ?: '/') . '; SameSite=' . $options['samesite'];
|
||||
}
|
||||
$result = setcookie($name, $value, $expires, $path, $domain, $secure, $httponly);
|
||||
}
|
||||
$result = setcookie($name, $value, $options);
|
||||
|
||||
// Make the cookie immediately available server-side.
|
||||
if ($result && $options['expires'] >= 0)
|
||||
|
|
|
|||
|
|
@ -209,9 +209,10 @@ class HTTP
|
|||
];
|
||||
|
||||
// Add proxy settings.
|
||||
if (defined('__PROXY_SERVER__'))
|
||||
$proxy = config('other.proxy') ?: (defined('__PROXY_SERVER__') ? constant('__PROXY_SERVER__') : '');
|
||||
if ($proxy !== '')
|
||||
{
|
||||
$proxy = parse_url(constant('__PROXY_SERVER__'));
|
||||
$proxy = parse_url($proxy);
|
||||
$proxy_scheme = preg_match('/^(https|socks)/', $proxy['scheme'] ?? '') ? ($proxy['scheme'] . '://') : 'http://';
|
||||
$proxy_auth = (!empty($proxy['user']) && !empty($proxy['pass'])) ? ($proxy['user'] . ':' . $proxy['pass'] . '@') : '';
|
||||
$settings['proxy'] = sprintf('%s%s%s:%s', $proxy_scheme, $proxy_auth, $proxy['host'], $proxy['port']);
|
||||
|
|
|
|||
|
|
@ -79,17 +79,7 @@ class Session
|
|||
ini_set('session.use_cookies', 1);
|
||||
ini_set('session.use_only_cookies', 1);
|
||||
ini_set('session.use_strict_mode', 1);
|
||||
if ($samesite)
|
||||
{
|
||||
if (PHP_VERSION_ID >= 70300)
|
||||
{
|
||||
ini_set('session.cookie_samesite', $samesite);
|
||||
}
|
||||
else
|
||||
{
|
||||
$path = ($path ?: '/') . '; SameSite=' . $samesite;
|
||||
}
|
||||
}
|
||||
ini_set('session.cookie_samesite', $samesite ? 1 : 0);
|
||||
session_set_cookie_params($lifetime, $path, $domain, $secure, $httponly);
|
||||
session_name($session_name = Config::get('session.name') ?: session_name());
|
||||
|
||||
|
|
|
|||
|
|
@ -899,19 +899,23 @@ class Template
|
|||
protected function _v2_checkCapability(int $check_type, $capability): bool
|
||||
{
|
||||
$grant = \Context::get('grant');
|
||||
if ($check_type === 1)
|
||||
if (!($grant instanceof \Rhymix\Modules\Module\Models\Permission))
|
||||
{
|
||||
return isset($grant->$capability) ? boolval($grant->$capability) : false;
|
||||
return false;
|
||||
}
|
||||
elseif ($check_type === 1)
|
||||
{
|
||||
return $grant->can($capability);
|
||||
}
|
||||
elseif ($check_type === 2)
|
||||
{
|
||||
return isset($grant->$capability) ? !boolval($grant->$capability) : true;
|
||||
return !$grant->can($capability);
|
||||
}
|
||||
elseif (is_array($capability))
|
||||
{
|
||||
foreach ($capability as $cap)
|
||||
{
|
||||
if (isset($grant->$cap) && $grant->$cap)
|
||||
if ($grant->can($cap))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,15 +7,6 @@ namespace Rhymix\Framework\Drivers\Mail;
|
|||
*/
|
||||
class MailFunction extends Base implements \Rhymix\Framework\Drivers\MailInterface
|
||||
{
|
||||
/**
|
||||
* Direct invocation of the constructor is not permitted.
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
include_once \RX_BASEDIR . 'common/libraries/swift_mail.php';
|
||||
$this->_mailer = new \Swift_Mailer(new \Swift_MailTransport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this mail driver.
|
||||
*
|
||||
|
|
@ -58,6 +49,12 @@ class MailFunction extends Base implements \Rhymix\Framework\Drivers\MailInterfa
|
|||
*/
|
||||
public function send(\Rhymix\Framework\Mail $message)
|
||||
{
|
||||
if ($this->_mailer === null)
|
||||
{
|
||||
include_once \RX_BASEDIR . 'common/libraries/swift_mail.php';
|
||||
$this->_mailer = new \Swift_Mailer(new \Swift_MailTransport);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$errors = [];
|
||||
|
|
|
|||
|
|
@ -116,12 +116,13 @@ class Mailgun extends Base implements \Rhymix\Framework\Drivers\MailInterface
|
|||
// Send the API request.
|
||||
$url = self::$_url . '/' . $this->_config['api_domain'] . '/messages.mime';
|
||||
$request = \Rhymix\Framework\HTTP::post($url, $data, $headers, [], $settings);
|
||||
$result = @json_decode($request->getBody()->getContents());
|
||||
$result_text = $request->getBody()->getContents();
|
||||
$result = @json_decode($result_text);
|
||||
|
||||
// Parse the result.
|
||||
if (!$result)
|
||||
{
|
||||
$message->errors[] = 'Mailgun: API error: ' . $request->getBody()->getContents();
|
||||
$message->errors[] = 'Mailgun: API error: ' . $result_text;
|
||||
return false;
|
||||
}
|
||||
elseif (!$result->id)
|
||||
|
|
|
|||
|
|
@ -7,23 +7,6 @@ namespace Rhymix\Framework\Drivers\Mail;
|
|||
*/
|
||||
class SMTP extends Base implements \Rhymix\Framework\Drivers\MailInterface
|
||||
{
|
||||
/**
|
||||
* Direct invocation of the constructor is not permitted.
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
$security = in_array($config['smtp_security'], ['ssl', 'tls']) ? $config['smtp_security'] : null;
|
||||
$transport = new \Swift_SmtpTransport($config['smtp_host'], $config['smtp_port'], $security);
|
||||
$transport->setUsername($config['smtp_user']);
|
||||
$transport->setPassword($config['smtp_pass']);
|
||||
$local_domain = $transport->getLocalDomain();
|
||||
if (preg_match('/^\*\.(.+)$/', $local_domain, $matches))
|
||||
{
|
||||
$transport->setLocalDomain($matches[1]);
|
||||
}
|
||||
$this->mailer = new \Swift_Mailer($transport);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this mail driver.
|
||||
*
|
||||
|
|
@ -56,9 +39,32 @@ class SMTP extends Base implements \Rhymix\Framework\Drivers\MailInterface
|
|||
*/
|
||||
public function send(\Rhymix\Framework\Mail $message)
|
||||
{
|
||||
if ($this->_mailer === null)
|
||||
{
|
||||
if (isset($this->_config['smtp_security']) && in_array($this->_config['smtp_security'], ['ssl', 'tls']))
|
||||
{
|
||||
$security = $this->_config['smtp_security'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$security = null;
|
||||
}
|
||||
|
||||
$transport = new \Swift_SmtpTransport($this->_config['smtp_host'], $this->_config['smtp_port'], $security);
|
||||
$transport->setUsername($this->_config['smtp_user']);
|
||||
$transport->setPassword($this->_config['smtp_pass']);
|
||||
$local_domain = $transport->getLocalDomain();
|
||||
if (preg_match('/^\*\.(.+)$/', $local_domain, $matches))
|
||||
{
|
||||
$transport->setLocalDomain($matches[1]);
|
||||
}
|
||||
$this->_mailer = new \Swift_Mailer($transport);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$result = $this->mailer->send($message->message, $errors);
|
||||
$errors = [];
|
||||
$result = $this->_mailer->send($message->message, $errors);
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -151,7 +151,8 @@ class FCMv1 extends Base implements PushInterface
|
|||
foreach ($responses as $i => $response)
|
||||
{
|
||||
$status_code = $response->getStatusCode();
|
||||
$result = @json_decode($response->getBody()->getContents());
|
||||
$result_text = $response->getBody()->getContents();
|
||||
$result = @json_decode($result_text);
|
||||
if ($status_code === 200)
|
||||
{
|
||||
$output->success[$tokens[$i]] = $result->name ?? '';
|
||||
|
|
@ -164,6 +165,10 @@ class FCMv1 extends Base implements PushInterface
|
|||
{
|
||||
$output->invalid[$tokens[$i]] = $tokens[$i];
|
||||
}
|
||||
elseif (str_contains($error_message, 'Requested entity was not found'))
|
||||
{
|
||||
$output->invalid[$tokens[$i]] = $tokens[$i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -196,7 +201,8 @@ class FCMv1 extends Base implements PushInterface
|
|||
foreach ($responses as $i => $response)
|
||||
{
|
||||
$status_code = $response->getStatusCode();
|
||||
$result = @json_decode($response->getBody()->getContents());
|
||||
$result_text = $response->getBody()->getContents();
|
||||
$result = @json_decode($result_text);
|
||||
if ($status_code === 200)
|
||||
{
|
||||
$output->success[$topics[$i]] = $result->name ?? '';
|
||||
|
|
|
|||
|
|
@ -93,8 +93,8 @@ class DB implements QueueInterface
|
|||
public function addTask(string $handler, ?object $args = null, ?object $options = null): int
|
||||
{
|
||||
$oDB = RFDB::getInstance();
|
||||
$stmt = $oDB->prepare('INSERT INTO task_queue (handler, args, options) VALUES (?, ?, ?)');
|
||||
$result = $stmt->execute([$handler, serialize($args), serialize($options)]);
|
||||
$stmt = $oDB->prepare('INSERT INTO task_queue (handler, args, options, regdate) VALUES (?, ?, ?, ?)');
|
||||
$result = $stmt->execute([$handler, serialize($args), serialize($options), date('Y-m-d H:i:s')]);
|
||||
return $result ? $oDB->getInsertID() : 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,141 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\SMS;
|
||||
|
||||
/**
|
||||
* The ApiStore SMS driver.
|
||||
*/
|
||||
class ApiStore extends Base implements \Rhymix\Framework\Drivers\SMSInterface
|
||||
{
|
||||
/**
|
||||
* API specifications.
|
||||
*/
|
||||
protected static $_spec = array(
|
||||
'max_recipients' => 500,
|
||||
'sms_max_length' => 90,
|
||||
'sms_max_length_in_charset' => 'CP949',
|
||||
'lms_supported' => true,
|
||||
'lms_supported_country_codes' => array(82),
|
||||
'lms_max_length' => 2000,
|
||||
'lms_max_length_in_charset' => 'CP949',
|
||||
'lms_subject_supported' => true,
|
||||
'lms_subject_max_length' => 60,
|
||||
'mms_supported' => false,
|
||||
'delay_supported' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Config keys used by this driver are stored here.
|
||||
*/
|
||||
protected static $_required_config = array('api_user', 'api_key');
|
||||
|
||||
/**
|
||||
* Check if the current SMS driver is supported on this server.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Store the last response.
|
||||
*/
|
||||
protected $_last_response = '';
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param array $messages
|
||||
* @param object $original
|
||||
* @return bool
|
||||
*/
|
||||
public function send(array $messages, \Rhymix\Framework\SMS $original)
|
||||
{
|
||||
$status = true;
|
||||
|
||||
foreach ($messages as $i => $message)
|
||||
{
|
||||
$data = array();
|
||||
$data['send_phone'] = $message->from;
|
||||
$data['dest_phone'] = implode(',', $message->to);
|
||||
$data['msg_body'] = strval($message->content);
|
||||
if ($message->type !== 'SMS' && $message->subject)
|
||||
{
|
||||
$data['subject'] = $message->subject;
|
||||
}
|
||||
|
||||
$result = $this->_apiCall(sprintf('message/%s', strtolower($message->type)), $data);
|
||||
if (!$result)
|
||||
{
|
||||
$message->errors[] = 'ApiStore API returned invalid response: ' . $this->_getLastResponse();
|
||||
$status = false;
|
||||
}
|
||||
if ($result->result_message !== 'OK')
|
||||
{
|
||||
$message->errors[] = 'ApiStore API error: ' . $result->result_code . ' ' . $result->result_message;
|
||||
}
|
||||
}
|
||||
|
||||
return $status;
|
||||
}
|
||||
|
||||
/**
|
||||
* API call.
|
||||
*
|
||||
* @param string $url
|
||||
* @param array $data
|
||||
* @param string $method (optional)
|
||||
* @return object|false
|
||||
*/
|
||||
protected function _apiCall(string $url, array $data, string $method = 'POST')
|
||||
{
|
||||
// Build the request URL.
|
||||
if ($data['version'])
|
||||
{
|
||||
$version = $data['version'];
|
||||
unset($data['version']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$version = 1;
|
||||
}
|
||||
$url = sprintf('http://api.apistore.co.kr/ppurio/%d/%s/%s', $version, trim($url, '/'), $this->_config['api_user']);
|
||||
|
||||
// Set the API key in the header.
|
||||
$headers = array(
|
||||
'x-waple-authorization' => $this->_config['api_key'],
|
||||
);
|
||||
|
||||
// Send the API reqeust.
|
||||
if ($method === 'GET')
|
||||
{
|
||||
if ($data)
|
||||
{
|
||||
$url .= '?' . http_build_query($data);
|
||||
}
|
||||
$this->_last_response = \FileHandler::getRemoteResource($url, null, 5, $method, null, $headers) ?: '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->_last_response = \FileHandler::getRemoteResource($url, $data, 5, $method, null, $headers) ?: '';
|
||||
}
|
||||
$result = @json_decode($this->_last_response);
|
||||
return $result ?: false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the last API response.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _getLastResponse()
|
||||
{
|
||||
return $this->_last_response;
|
||||
}
|
||||
}
|
||||
|
|
@ -740,20 +740,6 @@ function is_empty_html_content($str): bool
|
|||
return $str === '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Polyfill for is_countable() in PHP < 7.3
|
||||
*
|
||||
* @param mixed $var
|
||||
* @return bool
|
||||
**/
|
||||
if (!function_exists('is_countable'))
|
||||
{
|
||||
function is_countable($var)
|
||||
{
|
||||
return is_array($var) || $var instanceof Countable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Polyfill for str_starts_with() in PHP < 8.0
|
||||
*
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ else
|
|||
}
|
||||
|
||||
// Get queue configuration set by the administrator.
|
||||
$display_errors = config('queue.display_errors') === false ? false : true;
|
||||
$timeout = (config('queue.interval') ?? 1) * 60;
|
||||
$process_count = config('queue.process_count') ?? 1;
|
||||
|
||||
|
|
@ -41,6 +42,14 @@ if (PHP_SAPI !== 'cli')
|
|||
{
|
||||
ignore_user_abort(true);
|
||||
set_time_limit(max(60, $timeout));
|
||||
if ($display_errors)
|
||||
{
|
||||
ini_set('display_errors', true);
|
||||
}
|
||||
if (Rhymix\Framework\Session::checkStart())
|
||||
{
|
||||
Rhymix\Framework\Session::close();
|
||||
}
|
||||
}
|
||||
|
||||
// Create multiple processes if configured.
|
||||
|
|
@ -89,3 +98,9 @@ else
|
|||
{
|
||||
Rhymix\Framework\Queue::process($timeout);
|
||||
}
|
||||
|
||||
// If called over the network, display a simple OK message to indicate success.
|
||||
if (PHP_SAPI !== 'cli')
|
||||
{
|
||||
echo "OK\n";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@
|
|||
<meta charset="utf-8">
|
||||
<meta name="generator" content="Rhymix">
|
||||
<meta name="viewport" content="{{ config('mobile.viewport') ?? HTMLDisplayHandler::DEFAULT_VIEWPORT }}" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
@foreach (Context::getMetaTag() as $val)
|
||||
<meta http-equiv="{{ $val['name'] }}"|if="$val['is_http_equiv']" name="{{ $val['name'] }}"|if="!$val['is_http_equiv']" content="{{ $val['content'] }}" />
|
||||
@endforeach
|
||||
<meta name="csrf-token" content="{!! \Rhymix\Framework\Session::getGenericToken() !!}" />
|
||||
@foreach (Context::getMetaTag() as $val)
|
||||
@if ($val['is_before_title'])
|
||||
<meta http-equiv="{{ $val['name'] }}"|if="$val['is_http_equiv']" name="{{ $val['name'] }}"|if="!$val['is_http_equiv']" content="{!! $val['content'] !!}" />
|
||||
@endif
|
||||
@endforeach
|
||||
|
||||
<!-- TITLE -->
|
||||
<title>{{ Context::getBrowserTitle() }}</title>
|
||||
|
|
@ -55,6 +56,11 @@
|
|||
@endforeach
|
||||
|
||||
<!-- OTHER HEADERS -->
|
||||
@foreach (Context::getMetaTag() as $val)
|
||||
@if (!$val['is_before_title'])
|
||||
<meta http-equiv="{{ $val['name'] }}"|if="$val['is_http_equiv']" name="{{ $val['name'] }}"|if="!$val['is_http_equiv']" content="{!! $val['content'] !!}" />
|
||||
@endif
|
||||
@endforeach
|
||||
@foreach (Context::getOpenGraphData() as $og_metadata)
|
||||
<meta property="{{ $og_metadata['property'] }}" content="{{ $og_metadata['content'] }}" />
|
||||
@endforeach
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class ServerEnv extends Base
|
|||
$info = array();
|
||||
$skip = array(
|
||||
'phpext' => array('core', 'session', 'spl', 'standard', 'date', 'ctype', 'tokenizer', 'apache2handler', 'filter', 'reflection'),
|
||||
'module' => array('addon', 'admin', 'adminlogging', 'advanced_mailer', 'autoinstall', 'board', 'comment', 'communication', 'counter', 'document', 'editor', 'file', 'importer', 'install', 'integration_search', 'krzip', 'layout', 'member', 'menu', 'message', 'module', 'ncenterlite', 'opage', 'page', 'point', 'poll', 'rss', 'session', 'spamfilter', 'tag', 'trackback', 'trash', 'widget'),
|
||||
'module' => array('addon', 'admin', 'adminlogging', 'advanced_mailer', 'autoinstall', 'board', 'comment', 'communication', 'counter', 'document', 'editor', 'extravar', 'file', 'importer', 'install', 'integration_search', 'krzip', 'layout', 'member', 'menu', 'message', 'module', 'ncenterlite', 'opage', 'page', 'point', 'poll', 'rss', 'session', 'spamfilter', 'tag', 'trackback', 'trash', 'widget'),
|
||||
'addon' => array('adminlogging', 'autolink', 'counter', 'member_extra_info', 'point_level_icon', 'photoswipe', 'resize_image'),
|
||||
'layout' => array('default', 'user_layout', 'xedition'),
|
||||
'widget' => array('content', 'counter_status', 'language_select', 'login_info', 'mcontent', 'pollWidget'),
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ class CacheReset extends Base
|
|||
// If possible, use system command to speed up recursive deletion
|
||||
if (function_exists('exec') && !preg_match('/(?<!_)exec/', ini_get('disable_functions')))
|
||||
{
|
||||
if (strncasecmp(\PHP_OS, 'win', 3) == 0)
|
||||
if (\RX_WINDOWS)
|
||||
{
|
||||
@exec('rmdir /S /Q ' . escapeshellarg($tmp_dir));
|
||||
}
|
||||
|
|
@ -115,6 +115,12 @@ class CacheReset extends Base
|
|||
$oAutoinstallAdminController = getAdminController('autoinstall');
|
||||
$oAutoinstallAdminController->checkInstalled();
|
||||
|
||||
// Opcache reset
|
||||
if (function_exists('opcache_reset'))
|
||||
{
|
||||
opcache_reset();
|
||||
}
|
||||
|
||||
$this->setMessage('success_updated');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,11 +172,7 @@ class Cleanup extends Base
|
|||
}
|
||||
|
||||
// Return default values for most common operating systems.
|
||||
if (preg_match('/Linux/', \PHP_OS))
|
||||
{
|
||||
return $cache = true;
|
||||
}
|
||||
if (preg_match('/Win/i', \PHP_OS))
|
||||
if (\RX_WINDOWS)
|
||||
{
|
||||
return $cache = false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ class Advanced extends Base
|
|||
Context::set('minify_scripts', Config::get('view.minify_scripts'));
|
||||
Context::set('concat_scripts', Config::get('view.concat_scripts'));
|
||||
Context::set('jquery_version', Config::get('view.jquery_version'));
|
||||
Context::set('outgoing_proxy', Config::get('other.proxy'));
|
||||
|
||||
$this->setTemplateFile('config_advanced');
|
||||
}
|
||||
|
|
@ -215,6 +216,13 @@ class Advanced extends Base
|
|||
Config::set('locale.auto_select_lang', $vars->auto_select_lang === 'Y');
|
||||
Config::set('locale.default_timezone', $vars->default_timezone);
|
||||
|
||||
// Proxy
|
||||
$proxy = trim($vars->outgoing_proxy ?? '');
|
||||
if ($proxy !== '' && !preg_match('!^(https?|socks)://.+!', $proxy))
|
||||
{
|
||||
throw new Exception('msg_invalid_outgoing_proxy');
|
||||
}
|
||||
|
||||
// Other settings
|
||||
Config::set('url.rewrite', intval($vars->use_rewrite));
|
||||
Config::set('use_rewrite', $vars->use_rewrite > 0);
|
||||
|
|
@ -226,6 +234,7 @@ class Advanced extends Base
|
|||
Config::set('view.concat_scripts', $vars->concat_scripts ?: 'none');
|
||||
Config::set('view.delay_compile', intval($vars->delay_template_compile));
|
||||
Config::set('view.jquery_version', $vars->jquery_version == 3 ? 3 : 2);
|
||||
Config::set('other.proxy', $proxy);
|
||||
|
||||
// Save
|
||||
if (!Config::save())
|
||||
|
|
|
|||
|
|
@ -84,6 +84,9 @@ class Queue extends Base
|
|||
$driver_config[$conf_name] = $conf_value === '' ? null : $conf_value;
|
||||
}
|
||||
|
||||
// Validate error display setting.
|
||||
$display_errors = Context::get('webcron_display_errors') === 'Y' ? true : false;
|
||||
|
||||
// Validate the interval.
|
||||
$interval = intval($vars->queue_interval ?? 1);
|
||||
if ($interval < 1 || $interval > 10)
|
||||
|
|
@ -116,10 +119,10 @@ class Queue extends Base
|
|||
throw new Exception('msg_queue_driver_not_usable');
|
||||
}
|
||||
|
||||
|
||||
// Save system config.
|
||||
Config::set("queue.enabled", $enabled);
|
||||
Config::set("queue.driver", $driver);
|
||||
Config::set("queue.display_errors", $display_errors);
|
||||
Config::set("queue.interval", $interval);
|
||||
Config::set("queue.process_count", $process_count);
|
||||
Config::set("queue.key", $key);
|
||||
|
|
|
|||
|
|
@ -203,6 +203,9 @@ $lang->cache_truncate_method_empty = 'Delete content of cache folder';
|
|||
$lang->about_cache_truncate_method = 'It is faster and more reliable to delete the cache folder itself.<br />Choose the option to delete content only if the cache folder cannot be deleted, e.g. it is a mountpoint.';
|
||||
$lang->cache_control_header = 'Cache-Control header';
|
||||
$lang->about_cache_control_header = 'Select the Cache-Control header to apply to HTML pages that generally should not be cached.<br>Deselecting some of these options may help in certain circumstances, but at the cost of displaying outdated information.';
|
||||
$lang->outgoing_proxy = 'Proxy Outgoing Requests';
|
||||
$lang->about_outgoing_proxy = 'Use a proxy to hide the server\'s IP when making requests to other sites.<br>This setting does not apply to modules that implement their own HTTP clients.';
|
||||
$lang->msg_invalid_outgoing_proxy = 'Proxy URL must begin with http://, https:// or socks://';
|
||||
$lang->msg_cache_handler_not_supported = 'Your server does not support the selected cache method, or Rhymix is unable to use the cache with the given settings.';
|
||||
$lang->msg_invalid_default_url = 'The default URL is invalid.';
|
||||
$lang->msg_default_url_ssl_inconsistent = 'In order to use SSL always, the default URL must also begin with https://';
|
||||
|
|
@ -288,6 +291,8 @@ $lang->cmd_queue_enabled = 'Use Task Queue';
|
|||
$lang->cmd_queue_enabled_help = 'The task queue will stop accepting new tasks if you uncheck the above.';
|
||||
$lang->cmd_queue_driver = 'Queue Driver';
|
||||
$lang->cmd_queue_driver_help = 'Select the driver for the task queue that suits your hosting environment and website needs.<br>Some drivers such as Redis will need the corresponding program to be installed on the server.';
|
||||
$lang->cmd_queue_webcron_display_errors = 'Display Webcron Errors';
|
||||
$lang->cmd_queue_webcron_display_errors_help = 'Show webcron errors to help with debugging, if you have difficulty accessing server error logs.';
|
||||
$lang->cmd_queue_interval = 'Calling Interval';
|
||||
$lang->cmd_queue_interval_help = 'Use a scheduler such as crontab or systemd timer to call the script on a set interval.<br>All tasks are processed as soon as possible regardless of the interval, but a short interval means quick recovery from any error.<br>For web-based cron, this should not exceed the max_execution_time setting in php.ini.<br>The max_execution_time on this server is %d seconds.';
|
||||
$lang->cmd_queue_process_count = 'Process Count';
|
||||
|
|
@ -300,8 +305,8 @@ $lang->cmd_queue_config_keys['user'] = 'User';
|
|||
$lang->cmd_queue_config_keys['pass'] = 'Password';
|
||||
$lang->cmd_queue_config_keys['dbnum'] = 'DB Number';
|
||||
$lang->msg_queue_instructions['same_as_php'] = '(same as PHP)';
|
||||
$lang->msg_queue_instructions['crontab1'] = 'Log into the server as the <code>%s</code> account and run <code>crontab -e</code> to paste the following content into your crontab. (DO NOT run it as root!)<br>The <code>%s</code> directory in the example should be replaced with a path where logs can be recorded.';
|
||||
$lang->msg_queue_instructions['crontab2'] = 'If you change the calling interval below, the crontab interval must be adjusted accordingly.';
|
||||
$lang->msg_queue_instructions['crontab1'] = 'Log into the server as the <code>%s</code> account and run <code>crontab -e</code> to paste the following content into your crontab. <span style="color:red">(DO NOT run it as root!)</span><br>If the account shown above cannot be logged into, such as <code>apache</code> or <code>www-data</code>, try running <code>sudo crontab -e -u %s</code> from a different account.';
|
||||
$lang->msg_queue_instructions['crontab2'] = 'The <code>%s</code> directory in the example should be replaced with a path where logs can be recorded.<br>If you change the calling interval below, the crontab interval must be adjusted accordingly.';
|
||||
$lang->msg_queue_instructions['webcron'] = 'Configure an external cron service to make a GET request to the following URL every minute, or following the interval set below.<br>Check your logs to make sure that the cron service is reaching your website.';
|
||||
$lang->msg_queue_instructions['systemd1'] = 'Put the following content in <code>/etc/systemd/system/rhymix-queue.service</code>';
|
||||
$lang->msg_queue_instructions['systemd2'] = 'Put the following content in <code>/etc/systemd/system/rhymix-queue.timer</code>';
|
||||
|
|
|
|||
|
|
@ -204,6 +204,9 @@ $lang->cache_truncate_method_empty = '캐시 내용만 삭제';
|
|||
$lang->about_cache_truncate_method = '캐시 폴더를 삭제하는 방법이 더 빠르고 안정적입니다.<br />내용만 삭제하는 방법은 램디스크를 캐시 폴더로 사용하는 등 폴더 자체를 삭제해서는 안 되는 경우에만 선택하십시오.';
|
||||
$lang->cache_control_header = '캐시 컨트롤 헤더';
|
||||
$lang->about_cache_control_header = '브라우저 캐시를 적용하지 않을 일반 HTML 페이지에 적용할 Cache-Control 헤더 내용을 선택할 수 있습니다.<br>선택을 해제하면 뒤로가기 등 특정한 상황에서 성능이 개선될 수도 있지만, 오래된 정보가 노출되는 등 부작용이 발생할 수도 있습니다.';
|
||||
$lang->outgoing_proxy = '외부 요청 프록시';
|
||||
$lang->about_outgoing_proxy = '외부 요청시 프록시를 사용하여 서버 IP 노출을 방지합니다.<br>코어에서 제공하는 클래스와 함수를 사용하지 않고 외부 요청을 자체 구현한 서드파티 자료에는 적용되지 않습니다.';
|
||||
$lang->msg_invalid_outgoing_proxy = '프록시 주소는 http://, https:// 또는 socks://로 시작해야 합니다.';
|
||||
$lang->msg_cache_handler_not_supported = '선택하신 캐시 방식을 서버에서 지원하지 않거나, 주어진 정보로 캐시에 접속할 수 없습니다.';
|
||||
$lang->msg_invalid_default_url = '기본 URL이 올바르지 않습니다.';
|
||||
$lang->msg_default_url_ssl_inconsistent = 'SSL을 항상 사용하실 경우 기본 URL도 https://로 시작해야 합니다.';
|
||||
|
|
@ -284,6 +287,8 @@ $lang->cmd_queue_enabled = '비동기 작업 사용';
|
|||
$lang->cmd_queue_enabled_help = '체크를 해제하면 더이상 작업을 접수하지 않습니다.';
|
||||
$lang->cmd_queue_driver = '비동기 드라이버';
|
||||
$lang->cmd_queue_driver_help = '비동기 작업을 관리할 방법을 설정합니다. 호스팅 환경과 사이트의 필요에 맞추어 선택하세요.<br>Redis 등 일부 드라이버는 서버에 해당 기능이 설치되어 있어야 사용할 수 있습니다.';
|
||||
$lang->cmd_queue_webcron_display_errors = '웹크론 오류 표시';
|
||||
$lang->cmd_queue_webcron_display_errors_help = '에러 로그를 확인하기 어려운 서버 환경인 경우, 웹크론 에러를 화면에 표시하여 문제 파악을 돕습니다.';
|
||||
$lang->cmd_queue_interval = '호출 간격';
|
||||
$lang->cmd_queue_interval_help = 'crontab, systemd timer, 웹크론 등을 사용하여 일정한 주기로 스크립트를 호출해 주십시오.<br>모든 비동기 작업은 호출 간격과 무관하게 실시간으로 처리되나, 호출 간격이 짧으면 장애 발생시 신속하게 복구됩니다.<br>웹크론 사용시에는 php.ini의 실행 시간 제한을 초과하지 않는 것이 좋습니다.<br>이 서버의 max_execution_time은 %d초로 설정되어 있습니다.';
|
||||
$lang->cmd_queue_process_count = '프로세스 갯수';
|
||||
|
|
@ -296,8 +301,8 @@ $lang->cmd_queue_config_keys['user'] = '아이디';
|
|||
$lang->cmd_queue_config_keys['pass'] = '암호';
|
||||
$lang->cmd_queue_config_keys['dbnum'] = 'DB 번호';
|
||||
$lang->msg_queue_instructions['same_as_php'] = 'PHP를 실행하는 계정과 동일한';
|
||||
$lang->msg_queue_instructions['crontab1'] = '%s 계정으로 서버에 로그인하여 <code>crontab -e</code> 명령을 실행한 후, 아래의 내용을 붙여넣으십시오. (root 권한으로 실행하지 마십시오.)<br>예제의 <code>%s</code> 디렉토리는 로그를 기록할 수 있는 경로로 변경하여 사용하십시오.';
|
||||
$lang->msg_queue_instructions['crontab2'] = '스크립트 호출 간격을 변경할 경우, 설정에 맞추어 crontab 실행 간격도 조절하여야 합니다.';
|
||||
$lang->msg_queue_instructions['crontab1'] = '<code>%s</code> 계정으로 서버에 로그인하여 <code>crontab -e</code> 명령을 실행한 후, 아래의 내용을 붙여넣으십시오. <span style="color:red">(root 권한으로 실행하지 마십시오!)</span><br>만약 <code>apache</code>나 <code>www-data</code>처럼 로그인할 수 없는 계정이라면, 다른 계정에서 <code>sudo crontab -e -u %s</code> 명령을 실행해 볼 수 있습니다.';
|
||||
$lang->msg_queue_instructions['crontab2'] = '예제의 <code>%s</code> 디렉토리는 로그를 기록할 권한이 있는 경로로 변경하여 사용하십시오.<br>스크립트 호출 간격을 변경할 경우, 설정에 맞추어 crontab 실행 간격도 조절하여야 합니다.';
|
||||
$lang->msg_queue_instructions['webcron'] = '아래의 URL을 1분 간격 또는 아래에서 설정한 호출 간격에 맞추어 GET으로 호출하도록 합니다.<br>웹크론 서비스가 방화벽이나 CDN 등에 의해 차단되지 않도록 주의하고, 정상적으로 호출되는지 서버 로그를 확인하십시오.';
|
||||
$lang->msg_queue_instructions['systemd1'] = '<code>/etc/systemd/system/rhymix-queue.service</code> 파일에 아래와 같은 내용을 넣습니다.';
|
||||
$lang->msg_queue_instructions['systemd2'] = '<code>/etc/systemd/system/rhymix-queue.timer</code> 파일에 아래와 같은 내용을 넣습니다.';
|
||||
|
|
|
|||
|
|
@ -201,6 +201,13 @@
|
|||
<p class="x_help-block">{$lang->about_cache_control_header}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="outgoing_proxy">{$lang->outgoing_proxy}</label>
|
||||
<div class="x_controls">
|
||||
<input type="text" name="outgoing_proxy" id="outgoing_proxy" value="{$outgoing_proxy}" />
|
||||
<p class="x_help-block">{$lang->about_outgoing_proxy}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="partial_page_rendering">{$lang->cmd_partial_page_rendering}</label>
|
||||
<div class="x_controls">
|
||||
|
|
|
|||
|
|
@ -116,11 +116,11 @@
|
|||
endif;
|
||||
}
|
||||
<p class="qss-instruction">
|
||||
{sprintf($lang->msg_queue_instructions['crontab1'], $user_info['name'] ?? 'PHP', $user_info['dir'] . 'logs')|noescape}
|
||||
{sprintf($lang->msg_queue_instructions['crontab1'], $user_info['name'] ?? 'PHP', $user_info['name'] ?? 'PHP')|noescape}
|
||||
</p>
|
||||
<pre><code>* * * * * php {\RX_BASEDIR}index.php common.cron >> {$user_info['dir']}logs{\DIRECTORY_SEPARATOR}queue.log 2>&1</code></pre>
|
||||
<pre><code>* * * * * /usr/bin/php {\RX_BASEDIR}index.php common.cron >> {$user_info['dir']}logs{\DIRECTORY_SEPARATOR}queue.log 2>&1</code></pre>
|
||||
<p class="qss-instruction">
|
||||
{$lang->msg_queue_instructions['crontab2']|noescape}
|
||||
{sprintf($lang->msg_queue_instructions['crontab2'], $user_info['dir'] . 'logs')|noescape}
|
||||
</p>
|
||||
</div>
|
||||
<div class="qss-content webcron">
|
||||
|
|
@ -137,7 +137,7 @@
|
|||
Description=Rhymix Queue Service
|
||||
|
||||
[Service]
|
||||
ExecStart=php {\RX_BASEDIR}index.php common.cron
|
||||
ExecStart=/usr/bin/php {\RX_BASEDIR}index.php common.cron
|
||||
User={$user_info['name']}</code></pre>
|
||||
<p class="qss-instruction">
|
||||
{$lang->msg_queue_instructions['systemd2']|noescape}
|
||||
|
|
@ -167,6 +167,21 @@ systemctl enable rhymix-queue.timer</code></pre>
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label">{$lang->cmd_queue_webcron_display_errors}</label>
|
||||
<div class="x_controls">
|
||||
<label class="x_inline">
|
||||
<input type="radio" name="webcron_display_errors" value="Y" checked="checked"|cond="config('queue.display_errors') !== false" />
|
||||
{$lang->cmd_yes}
|
||||
</label>
|
||||
<label class="x_inline">
|
||||
<input type="radio" name="webcron_display_errors" value="N" checked="checked"|cond="config('queue.display_errors') === false" />
|
||||
{$lang->cmd_no}
|
||||
</label>
|
||||
<p class="x_help-block">{$lang->cmd_queue_webcron_display_errors_help}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="queue_interval">{$lang->cmd_queue_interval}</label>
|
||||
<div class="x_controls">
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ class adminlogging extends ModuleObject
|
|||
*/
|
||||
function moduleInstall()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -27,7 +27,23 @@ class adminlogging extends ModuleObject
|
|||
*/
|
||||
function checkUpdate()
|
||||
{
|
||||
return FALSE;
|
||||
$oDB = DB::getInstance();
|
||||
if (!$oDB->isColumnExists('admin_log', 'member_srl'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!$oDB->isIndexExists('admin_log', 'idx_member_srl'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$column_info = $oDB->getColumnInfo('admin_log', 'request_vars');
|
||||
if ($column_info->xetype !== 'bigtext')
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -36,7 +52,21 @@ class adminlogging extends ModuleObject
|
|||
*/
|
||||
function moduleUpdate()
|
||||
{
|
||||
|
||||
$oDB = DB::getInstance();
|
||||
if (!$oDB->isColumnExists('admin_log', 'member_srl'))
|
||||
{
|
||||
$oDB->addColumn('admin_log', 'member_srl', 'number', null, 0, true, 'site_srl');
|
||||
}
|
||||
if (!$oDB->isIndexExists('admin_log', 'idx_member_srl'))
|
||||
{
|
||||
$oDB->addIndex('admin_log', 'idx_member_srl', ['member_srl']);
|
||||
}
|
||||
|
||||
$column_info = $oDB->getColumnInfo('admin_log', 'request_vars');
|
||||
if ($column_info->xetype !== 'bigtext')
|
||||
{
|
||||
$oDB->modifyColumn('admin_log', 'request_vars', 'bigtext');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -45,7 +75,7 @@ class adminlogging extends ModuleObject
|
|||
*/
|
||||
function recompileCache()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,43 +11,26 @@
|
|||
*/
|
||||
class adminloggingController extends adminlogging
|
||||
{
|
||||
|
||||
/**
|
||||
* Initialization
|
||||
* @return void
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
// forbit access if the user is not an administrator
|
||||
$oMemberModel = getModel('member');
|
||||
$logged_info = $oMemberModel->getLoggedInfo();
|
||||
if($logged_info->is_admin != 'Y')
|
||||
{
|
||||
throw new Rhymix\Framework\Exceptions\NotPermitted('admin.msg_is_not_administrator');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Insert log
|
||||
* @return void
|
||||
*/
|
||||
function insertLog($module, $act)
|
||||
public function insertLog($module, $act)
|
||||
{
|
||||
if(!$module || !$act)
|
||||
if (!$module || !$act)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$args = new stdClass();
|
||||
$args->member_srl = $this->user->member_srl;
|
||||
$args->module = $module;
|
||||
$args->act = $act;
|
||||
$args->ipaddress = \RX_CLIENT_IP;
|
||||
$args->request_vars = json_encode(Context::getRequestVars(), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT);
|
||||
$args->regdate = date('YmdHis');
|
||||
$args->requestVars = print_r(Context::getRequestVars(), TRUE);
|
||||
|
||||
$args->ipaddress = \RX_CLIENT_IP;
|
||||
$output = executeQuery('adminlogging.insertLog', $args);
|
||||
}
|
||||
|
||||
}
|
||||
/* End of file adminlogging.controller.php */
|
||||
/* Location: ./modules/adminlogging/adminlogging.controller.php */
|
||||
|
|
|
|||
|
|
@ -3,11 +3,12 @@
|
|||
<table name="admin_log" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="ipaddress" var="ipaddress" notnull="notnull" />
|
||||
<column name="regdate" var="regdate" />
|
||||
<column name="site_srl" var="siteSrl" filter="number" default="0" />
|
||||
<column name="site_srl" var="site_srl" filter="number" default="0" />
|
||||
<column name="member_srl" var="member_srl" filter="number" default="0" />
|
||||
<column name="module" var="module" />
|
||||
<column name="act" var="act" />
|
||||
<column name="request_vars" var="requestVars" />
|
||||
<column name="request_vars" var="request_vars" />
|
||||
<column name="regdate" var="regdate" default="curdate()" />
|
||||
<column name="ipaddress" var="ipaddress" default="ipaddress()" />
|
||||
</columns>
|
||||
</query>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
<table name="admin_log">
|
||||
<column name="ipaddress" type="varchar" size="60" notnull="notnull" index="idx_admin_ip" />
|
||||
<column name="regdate" type="date" index="idx_admin_date" />
|
||||
<column name="site_srl" type="number" size="11" default="0" />
|
||||
<column name="id" type="number" notnull="notnull" primary_key="primary_key" auto_increment="auto_increment" />
|
||||
<column name="site_srl" type="number" default="0" />
|
||||
<column name="member_srl" type="number" default="0" index="idx_member_srl" />
|
||||
<column name="module" type="varchar" size="100" />
|
||||
<column name="act" type="varchar" size="100" />
|
||||
<column name="request_vars" type="text" />
|
||||
<column name="request_vars" type="bigtext" />
|
||||
<column name="regdate" type="date" index="idx_admin_date" />
|
||||
<column name="ipaddress" type="varchar" size="60" notnull="notnull" index="idx_admin_ip" />
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -289,9 +289,6 @@ class BoardView extends Board
|
|||
}
|
||||
}
|
||||
|
||||
// check the manage grant
|
||||
if($this->grant->manager) $oDocument->setGrant();
|
||||
|
||||
// if the consultation function is enabled, and the document is not a notice
|
||||
if($this->consultation && !$oDocument->isNotice())
|
||||
{
|
||||
|
|
@ -904,7 +901,7 @@ class BoardView extends Board
|
|||
}
|
||||
}
|
||||
|
||||
if ($this->module_info->protect_admin_content_update !== 'N')
|
||||
if (($this->module_info->protect_admin_content_update ?? 'N') !== 'N')
|
||||
{
|
||||
$member_info = MemberModel::getMemberInfo($oDocument->get('member_srl'));
|
||||
if(isset($member_info->is_admin) && $member_info->is_admin == 'Y' && $this->user->is_admin != 'Y')
|
||||
|
|
|
|||
|
|
@ -116,21 +116,21 @@
|
|||
<action name="dispBoardAdminContent" type="view" admin_index="true" menu_name="board" menu_index="true" />
|
||||
<action name="dispBoardAdminInsertBoard" type="view" setup_index="true" menu_name="board" />
|
||||
<action name="dispBoardAdminDeleteBoard" type="view" menu_name="board" />
|
||||
<action name="dispBoardAdminBoardInfo" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminCategoryInfo" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminExtraVars" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminGrantInfo" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminBoardAdditionSetup" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminSkinInfo" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminMobileSkinInfo" type="view" permission="manager" menu_name="board" />
|
||||
<action name="dispBoardAdminBoardInfo" type="view" permission="manager:config:*" menu_name="board" />
|
||||
<action name="dispBoardAdminCategoryInfo" type="view" permission="manager:config:*" menu_name="board" />
|
||||
<action name="dispBoardAdminExtraVars" type="view" permission="manager:config:*" menu_name="board" />
|
||||
<action name="dispBoardAdminGrantInfo" type="view" permission="manager:config:*" menu_name="board" />
|
||||
<action name="dispBoardAdminBoardAdditionSetup" type="view" permission="manager:config:*" menu_name="board" />
|
||||
<action name="dispBoardAdminSkinInfo" type="view" permission="manager:config:*" menu_name="board" />
|
||||
<action name="dispBoardAdminMobileSkinInfo" type="view" permission="manager:config:*" menu_name="board" />
|
||||
|
||||
<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" permission="manager" check_var="module_srl" />
|
||||
<action name="procBoardAdminInsertBoard" type="controller" permission="manager:config:*" check_var="module_srl" ruleset="insertBoard" />
|
||||
<action name="procBoardAdminDeleteBoard" type="controller" permission="manager:config:*" check_var="module_srl" />
|
||||
<action name="procBoardAdminUpdateBoard" type="controller" ruleset="insertBoardForBasic" />
|
||||
<action name="procBoardAdminInsertCombinedConfig" type="controller" />
|
||||
<action name="procBoardAdminSaveCategorySettings" type="controller" permission="manager" check_var="module_srl" ruleset="saveCategorySettings" />
|
||||
<action name="procBoardAdminSaveCategorySettings" type="controller" permission="manager:config:*" check_var="module_srl" ruleset="saveCategorySettings" />
|
||||
</actions>
|
||||
<eventHandlers>
|
||||
<eventHandler after="member.getMemberMenu" class="controller" method="triggerMemberMenu" />
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ $lang->cmd_do_not_message = 'Never';
|
|||
$lang->delete_placeholder = 'Delete Placeholder';
|
||||
$lang->msg_document_notify_mail = '[%s] The new post : %s';
|
||||
$lang->cmd_board_combined_board = 'Combined Board';
|
||||
$lang->about_board_combined_board = 'You can use this board to view documents from other boards. Press the Ctrl key and click to select multiple boards.<br />Caution: view permissions for the current board will apply to all affected documents.';
|
||||
$lang->about_board_combined_board = 'You can use this board to view documents from other boards. Press the Ctrl key and click to select multiple boards.<br /><span style="color:red">Warning: permissions for the current board will apply to all affected documents and comments.</span>';
|
||||
$lang->cmd_board_include_modules = 'Include Boards';
|
||||
$lang->cmd_board_include_modules_none = '(None)';
|
||||
$lang->cmd_board_include_days = 'Include Duration';
|
||||
|
|
|
|||
|
|
@ -109,7 +109,7 @@ $lang->cmd_document_vote_user = '이 글의 추천인 목록';
|
|||
$lang->cmd_comment_vote_user = '이 댓글의 추천인 목록';
|
||||
$lang->msg_not_target = '문서 또는 댓글의 추천인목록만 조회가능합니다.';
|
||||
$lang->cmd_board_combined_board = '통합 게시판';
|
||||
$lang->about_board_combined_board = '다른 게시판의 글을 모아서 볼 수 있습니다. 여러 게시판을 선택하려면 Ctrl 키를 누르고 클릭하세요.<br />주의: 현재 게시판의 읽기 권한 설정이 모든 글에 적용됩니다.';
|
||||
$lang->about_board_combined_board = '다른 게시판의 글을 모아서 볼 수 있습니다. 여러 게시판을 선택하려면 Ctrl 키를 누르고 클릭하세요.<br /><span style="color:red">주의: 현재 게시판의 권한 설정이 모든 글에 적용됩니다.</span>';
|
||||
$lang->cmd_board_include_modules = '포함할 게시판 선택';
|
||||
$lang->cmd_board_include_modules_none = '(포함하지 않음)';
|
||||
$lang->cmd_board_include_days = '포함할 기간';
|
||||
|
|
|
|||
|
|
@ -91,8 +91,10 @@
|
|||
</span>
|
||||
<input cond="$is_logged" type="checkbox" name="notify_message" value="Y" id="notify_message" class="iCheck" />
|
||||
<label cond="$is_logged" for="notify_message">{$lang->notify}</label>
|
||||
<input cond="$module_info->secret=='Y'" type="checkbox" name="is_secret" value="Y" id="is_secret" class="iCheck" />
|
||||
<label cond="$module_info->secret=='Y'" for="is_secret">{$lang->secret}</label>
|
||||
<!--@if(isset($module_info->secret) && $module_info->secret === 'Y')-->
|
||||
<input type="checkbox" name="is_secret" value="Y" id="is_secret" class="iCheck" />
|
||||
<label for="is_secret">{$lang->secret}</label>
|
||||
<!--@endif-->
|
||||
</div>
|
||||
<div class="write_captcha" cond="isset($captcha) && $captcha && $captcha->isTargetAction('comment')">
|
||||
{$captcha}
|
||||
|
|
|
|||
|
|
@ -29,8 +29,10 @@
|
|||
</span>
|
||||
<input cond="$is_logged" type="checkbox" name="notify_message" value="Y" checked="checked"|cond="$oComment->get('notify_message')=='Y'" id="notify_message" class="iCheck" />
|
||||
<label cond="$is_logged" for="notify_message">{$lang->notify}</label>
|
||||
<input cond="$module_info->secret=='Y'" type="checkbox" name="is_secret" value="Y" id="is_secret" checked="checked"|cond="$oComment->get('is_secret')=='Y'" class="iCheck" />
|
||||
<label cond="$module_info->secret=='Y'" for="is_secret">{$lang->secret}</label>
|
||||
<!--@if(isset($module_info->secret) && $module_info->secret === 'Y')-->
|
||||
<input type="checkbox" name="is_secret" value="Y" id="is_secret" checked="checked"|cond="$oComment->get('is_secret')=='Y'" class="iCheck" />
|
||||
<label for="is_secret">{$lang->secret}</label>
|
||||
<!--@endif-->
|
||||
</div>
|
||||
<div class="write_captcha" cond="isset($captcha) && $captcha && $captcha->isTargetAction('comment')">
|
||||
{$captcha}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@
|
|||
</thead>
|
||||
<tbody>
|
||||
<tr loop="$board_list => $no,$val">
|
||||
<td>{$no}</td>
|
||||
<td>{$val->module_srl}</td>
|
||||
<td>
|
||||
<block cond="!$val->module_category_srl">
|
||||
<block cond="$val->site_srl">{$lang->virtual_site}</block>
|
||||
|
|
@ -32,7 +32,7 @@
|
|||
</td>
|
||||
<td class="domain_prefix"><span class="domain">{$val->domain ?? ''}</span>{\RX_BASEURL}</td>
|
||||
<td>{$val->mid}</td>
|
||||
<td><a href="{getSiteUrl($val->domain,'','mid',$val->mid)}">{$val->browser_title}</a></td>
|
||||
<td><a href="{getSiteUrl($val->domain,'','mid',$val->mid)}" target="_blank">{$val->browser_title}</a></td>
|
||||
<td>{zdate($val->regdate,"Y-m-d")}</td>
|
||||
<td>
|
||||
<a href="{getUrl('act','dispBoardAdminBoardInfo','module_srl',$val->module_srl)}"><i class="x_icon-cog"></i> {$lang->cmd_setup}</a>
|
||||
|
|
|
|||
|
|
@ -126,7 +126,7 @@ class CommentItem extends BaseObject
|
|||
}
|
||||
|
||||
$grant = ModuleModel::getGrant(ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl')), $logged_info);
|
||||
if ($grant->manager)
|
||||
if ($grant->manager && $grant->can('moderate:comment'))
|
||||
{
|
||||
return $this->grant_cache = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
<action name="procCommentVoteDownCancel" type="controller" />
|
||||
<action name="procCommentDeclare" type="controller" permission="member" />
|
||||
<action name="procCommentDeclareCancel" type="controller" permission="member" />
|
||||
<action name="procCommentGetList" type="controller" permission="manager" check_type="comment" check_var="comment_srls" />
|
||||
<action name="procCommentInsertModuleConfig" type="controller" permission="manager" check_var="target_module_srl" ruleset="insertCommentModuleConfig" />
|
||||
<action name="procCommentGetList" type="controller" permission="manager:moderate:comment" check_type="comment" check_var="comment_srls" />
|
||||
<action name="procCommentInsertModuleConfig" type="controller" permission="manager:config:comment" check_var="target_module_srl" ruleset="insertCommentModuleConfig" />
|
||||
|
||||
<action name="dispCommentAdminList" type="view" admin_index="true" menu_name="comment" menu_index="true" />
|
||||
<action name="dispCommentAdminDeclared" type="view" menu_name="comment" />
|
||||
|
|
@ -23,9 +23,9 @@
|
|||
<action name="procCommentAdminChangeStatus" type="controller"/>
|
||||
<action name="procCommentAdminChangePublishedStatusChecked" type="controller" />
|
||||
<action name="procCommentAdminCancelDeclare" type="controller" />
|
||||
<action name="procCommentAdminAddCart" type="controller" permission="manager" check_type="comment" check_var="comment_srl" />
|
||||
<action name="procCommentAdminDeleteChecked" type="controller" permission="manager" check_type="comment" check_var="cart" ruleset="deleteChecked" />
|
||||
<action name="procCommentAdminMoveToTrash" type="controller" permission="manager" check_type="comment" check_var="comment_srl" />
|
||||
<action name="procCommentAdminAddCart" type="controller" permission="manager:moderate:comment" check_type="comment" check_var="comment_srl" />
|
||||
<action name="procCommentAdminDeleteChecked" type="controller" permission="manager:moderate:comment" check_type="comment" check_var="cart" ruleset="deleteChecked" />
|
||||
<action name="procCommentAdminMoveToTrash" type="controller" permission="manager:moderate:comment" check_type="comment" check_var="comment_srl" />
|
||||
</actions>
|
||||
<eventHandlers>
|
||||
<eventHandler after="document.deleteDocument" class="controller" method="triggerDeleteDocumentComments" />
|
||||
|
|
|
|||
|
|
@ -22,14 +22,14 @@
|
|||
<action name="procDocumentDeclare" type="controller" permission="member" />
|
||||
<action name="procDocumentDeclareCancel" type="controller" permission="member" />
|
||||
<action name="procDocumentDeleteTempSaved" type="controller" permission="member" />
|
||||
<action name="procDocumentGetList" type="controller" permission="manager" check_type="document" check_var="document_srls" />
|
||||
<action name="procDocumentAddCart" type="controller" permission="manager" check_type="document" check_var="srls" />
|
||||
<action name="procDocumentManageCheckedDocument" type="controller" permission="manager" check_type="document" check_var="cart" />
|
||||
<action name="procDocumentInsertModuleConfig" type="controller" permission="manager" check_var="target_module_srl" />
|
||||
<action name="procDocumentInsertCategory" type="controller" permission="manager" check_var="module_srl" ruleset="insertCategory" />
|
||||
<action name="procDocumentDeleteCategory" type="controller" permission="manager" check_var="module_srl" />
|
||||
<action name="procDocumentMoveCategory" type="controller" permission="manager" check_var="module_srl" />
|
||||
<action name="procDocumentMakeXmlFile" type="controller" permission="manager" check_var="module_srl" />
|
||||
<action name="procDocumentGetList" type="controller" permission="manager:moderate:document" check_type="document" check_var="document_srls" />
|
||||
<action name="procDocumentAddCart" type="controller" permission="manager:moderate:document" check_type="document" check_var="srls" />
|
||||
<action name="procDocumentManageCheckedDocument" type="controller" permission="manager:moderate:document" check_type="document" check_var="cart" />
|
||||
<action name="procDocumentInsertModuleConfig" type="controller" permission="manager:config:*" check_var="target_module_srl" />
|
||||
<action name="procDocumentInsertCategory" type="controller" permission="manager:config:*" check_var="module_srl" ruleset="insertCategory" />
|
||||
<action name="procDocumentDeleteCategory" type="controller" permission="manager:config:*" check_var="module_srl" />
|
||||
<action name="procDocumentMoveCategory" type="controller" permission="manager:config:*" check_var="module_srl" />
|
||||
<action name="procDocumentMakeXmlFile" type="controller" permission="manager:config:*" check_var="module_srl" />
|
||||
|
||||
<action name="dispDocumentAdminList" type="view" admin_index="true" menu_name="document" menu_index="true" />
|
||||
<action name="dispDocumentAdminConfig" type="view" menu_name="document" />
|
||||
|
|
@ -44,11 +44,11 @@
|
|||
<action name="procDocumentAdminCancelDeclare" type="controller" />
|
||||
<action name="procDocumentAdminInsertAlias" type="controller" ruleset="insertAlias" />
|
||||
<action name="procDocumentAdminDeleteAlias" type="controller" ruleset="deleteAlias" />
|
||||
<action name="procDocumentAdminMoveToTrash" type="controller" permission="manager" check_type="document" check_var="document_srl" />
|
||||
<action name="procDocumentAdminMoveToTrash" type="controller" permission="manager:moderate:document" check_type="document" check_var="document_srl" />
|
||||
<action name="procDocumentAdminRestoreTrash" type="controller" />
|
||||
<action name="procDocumentAdminInsertExtraVar" type="controller" permission="manager" check_var="module_srl" ruleset="insertExtraVar" />
|
||||
<action name="procDocumentAdminDeleteExtraVar" type="controller" permission="manager" check_var="module_srl" />
|
||||
<action name="procDocumentAdminMoveExtraVar" type="controller" permission="manager" check_var="module_srl" />
|
||||
<action name="procDocumentAdminInsertExtraVar" type="controller" permission="manager:config:*" check_var="module_srl" ruleset="insertExtraVar" />
|
||||
<action name="procDocumentAdminDeleteExtraVar" type="controller" permission="manager:config:*" check_var="module_srl" />
|
||||
<action name="procDocumentAdminMoveExtraVar" type="controller" permission="manager:config:*" check_var="module_srl" />
|
||||
</actions>
|
||||
<eventHandlers>
|
||||
<eventHandler after="module.deleteModule" class="controller" method="triggerDeleteModuleDocuments" />
|
||||
|
|
|
|||
|
|
@ -218,7 +218,7 @@ class DocumentItem extends BaseObject
|
|||
}
|
||||
|
||||
$grant = ModuleModel::getGrant(ModuleModel::getModuleInfoByModuleSrl($this->get('module_srl')), $logged_info);
|
||||
if ($grant->manager)
|
||||
if ($grant->manager && $grant->can('moderate:document'))
|
||||
{
|
||||
return $this->grant_cache = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
<action name="procEditorSaveDoc" type="controller" />
|
||||
<action name="procEditorRemoveSavedDoc" type="controller" />
|
||||
<action name="procEditorLoadSavedDocument" type="controller" />
|
||||
<action name="procEditorInsertModuleConfig" type="controller" permission="manager" check_var="target_module_srl" />
|
||||
<action name="procEditorInsertModuleConfig" type="controller" permission="manager:config:*" check_var="target_module_srl" />
|
||||
|
||||
<action name="dispEditorAdminIndex" type="view" menu_name="editor" menu_index="true" admin_index="true" />
|
||||
<action name="dispEditorAdminSetupComponent" type="view" menu_name="editor" />
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
<action name="procFileAdminInsertUploadConfig" type="controller" ruleset="insertConfig" />
|
||||
<action name="procFileAdminInsertDownloadConfig" type="controller" />
|
||||
<action name="procFileAdminInsertOtherConfig" type="controller" />
|
||||
<action name="procFileAdminInsertModuleConfig" type="controller" permission="manager" check_var="target_module_srl" ruleset="fileModuleConfig" />
|
||||
<action name="procFileAdminInsertModuleConfig" type="controller" permission="manager:config:*" check_var="target_module_srl" ruleset="fileModuleConfig" />
|
||||
</actions>
|
||||
<eventHandlers>
|
||||
<eventHandler after="document.deleteDocument" class="controller" method="triggerDeleteAttached" />
|
||||
|
|
|
|||
|
|
@ -58,6 +58,10 @@ class MemberAdminView extends Member
|
|||
|
||||
// retrieve group list
|
||||
$this->group_list = $oMemberModel->getGroups();
|
||||
foreach ($this->group_list as $group)
|
||||
{
|
||||
$group->title = Context::replaceUserLang($group->title, true);
|
||||
}
|
||||
Context::set('group_list', $this->group_list);
|
||||
|
||||
$security = new Security();
|
||||
|
|
|
|||
|
|
@ -14,16 +14,6 @@ class Member extends ModuleObject
|
|||
public const NOUSE_EXTRA_VARS = ['error_return_url', 'success_return_url', '_rx_ajax_compat', '_rx_ajax_form', '_rx_csrf_token', 'ruleset', 'captchaType', 'use_editor', 'use_html'];
|
||||
public const STATUS_LIST = ['APPROVED', 'DENIED', 'UNAUTHED', 'SUSPENDED', 'DELETED'];
|
||||
|
||||
/**
|
||||
* constructor
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement if additional tasks are necessary when installing
|
||||
*
|
||||
|
|
|
|||
|
|
@ -176,6 +176,11 @@ class MemberView extends Member
|
|||
$member_info->email_address = sprintf('%s@%s', $protect_id, $email_host);
|
||||
}
|
||||
|
||||
foreach ($member_info->group_list ?? [] as $key => $val)
|
||||
{
|
||||
$member_info->group_list[$key] = Context::replaceUserLang($val, true);
|
||||
}
|
||||
|
||||
Context::set('memberInfo', get_object_vars($member_info));
|
||||
|
||||
$extendForm = MemberModel::getCombineJoinForm($member_info);
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@
|
|||
<i class="no_profile">?</i>
|
||||
<!--@end-->
|
||||
</td>
|
||||
{@ $member_info['group_list'] = implode(', ', $member_info['group_list'])}
|
||||
{@ $member_info['group_list'] = Context::replaceUserLang(implode(', ', $member_info['group_list']), true)}
|
||||
<td class="nowr" loop="$usedIdentifiers=>$name,$title">
|
||||
<!--@if($name === 'email_address')-->
|
||||
<a href="#popup_menu_area" class="member_{$member_info['member_srl']}">{getEncodeEmailAddress($member_info['email_address'])}</a>
|
||||
|
|
|
|||
|
|
@ -97,6 +97,10 @@ $lang->about_mobile_page_count = 'You can set the number of page links to move p
|
|||
$lang->about_admin_id = 'You can grant someone permission to manage this module. Please enter the user ID or email address of the person you wish to add.';
|
||||
$lang->about_grant_deatil = 'Registered users mean users who signed-up to the virtual sites (e.g., cafeXE).';
|
||||
$lang->about_module = 'Rhymix consists of modules except the basic library. [Module Manage] module will show all installed modules and help you to manage them.';
|
||||
$lang->admin_scope = 'Scope of Admin Powers';
|
||||
$lang->admin_scopes['moderate:document'] = 'Manage documents';
|
||||
$lang->admin_scopes['moderate:comment'] = 'Manage comments';
|
||||
$lang->admin_scopes['config:*'] = 'Change settings';
|
||||
$lang->extra_vars_is_strict = 'Specified values only';
|
||||
$lang->extra_vars_options = 'Options';
|
||||
$lang->about_extra_vars_is_strict = 'In single and multiple choice fields, only allow the values specified below. If you change the allowed values, it may affect previous posts.';
|
||||
|
|
|
|||
|
|
@ -96,6 +96,10 @@ $lang->about_mobile_page_count = '목록 하단, 페이지를 이동하는 링
|
|||
$lang->about_admin_id = '특정 회원에게 이 모듈의 관리 권한을 부여할 수 있습니다. 권한을 부여할 회원의 아이디 또는 이메일 주소를 입력해 주세요.';
|
||||
$lang->about_grant_deatil = '가입한 사용자는 cafeXE 등 분양형 가상 사이트에 가입을 한 로그인 사용자를 의미합니다.';
|
||||
$lang->about_module = 'Rhymix는 기본 라이브러리를 제외한 나머지는 모두 모듈로 구성되어 있습니다. 모듈 관리 모듈은 설치된 모든 모듈을 보여주고 관리를 돕습니다.';
|
||||
$lang->admin_scope = '관리자 권한 범위';
|
||||
$lang->admin_scopes['moderate:document'] = '문서 관리';
|
||||
$lang->admin_scopes['moderate:comment'] = '댓글 관리';
|
||||
$lang->admin_scopes['config:*'] = '모듈 설정 변경';
|
||||
$lang->extra_vars_is_strict = '임의입력 금지';
|
||||
$lang->extra_vars_options = '선택지';
|
||||
$lang->about_extra_vars_is_strict = '단일/다중 선택에서 미리 주어진 선택지만 입력할 수 있도록 합니다. 선택지를 변경할 경우 기존 게시물에 영향을 줄 수 있습니다.';
|
||||
|
|
|
|||
64
modules/module/models/Permission.php
Normal file
64
modules/module/models/Permission.php
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Modules\Module\Models;
|
||||
|
||||
#[\AllowDynamicProperties]
|
||||
class Permission
|
||||
{
|
||||
/**
|
||||
* Default properties.
|
||||
*
|
||||
* Note that $is_admin is an alias to $root,
|
||||
* and $is_site_admin is an alias to $manager.
|
||||
*/
|
||||
public $access;
|
||||
public $root;
|
||||
public $manager;
|
||||
public $scopes;
|
||||
|
||||
/**
|
||||
* Alias to $root, kept for backward compatibility only.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public $is_admin;
|
||||
|
||||
/**
|
||||
* Alias to $manager, kept for backward compatibility only.
|
||||
*
|
||||
* @deprecated
|
||||
*/
|
||||
public $is_site_admin;
|
||||
|
||||
/**
|
||||
* Primary method to determine whether a user is allowed to do something.
|
||||
*
|
||||
* @param string $scope
|
||||
* @return bool
|
||||
*/
|
||||
public function can(string $scope): bool
|
||||
{
|
||||
if (isset($this->{$scope}) && $scope !== 'scopes')
|
||||
{
|
||||
return boolval($this->{$scope});
|
||||
}
|
||||
|
||||
if ($this->manager && $this->scopes && preg_match('/^(\w+):(.+)$/', $scope, $matches))
|
||||
{
|
||||
if ($this->scopes === true)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (is_array($this->scopes) && in_array($scope, $this->scopes))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (is_array($this->scopes) && in_array($matches[1] . ':*', $this->scopes))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -292,6 +292,11 @@ class ModuleAdminController extends Module
|
|||
// Register Admin ID
|
||||
$oModuleController->deleteAdminId($module_srl);
|
||||
$admin_member = Context::get('admin_member');
|
||||
$scopes = Context::get('admin_scopes') ?: null;
|
||||
if(is_string($scopes) && $scopes !== '')
|
||||
{
|
||||
$scopes = explode('|@|', $scopes);
|
||||
}
|
||||
if($admin_member)
|
||||
{
|
||||
$admin_members = explode(',',$admin_member);
|
||||
|
|
@ -299,7 +304,7 @@ class ModuleAdminController extends Module
|
|||
{
|
||||
$admin_id = trim($admin_id);
|
||||
if(!$admin_id) continue;
|
||||
$oModuleController->insertAdminId($module_srl, $admin_id);
|
||||
$oModuleController->insertAdminId($module_srl, $admin_id, $scopes);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -197,6 +197,8 @@ class ModuleAdminModel extends Module
|
|||
// Extract admin ID set in the current module
|
||||
$admin_member = ModuleModel::getAdminId($module_srl) ?: [];
|
||||
Context::set('admin_member', $admin_member);
|
||||
// Get defined scopes
|
||||
Context::set('manager_scopes', $this->getModuleAdminScopes());
|
||||
// Get a list of groups
|
||||
$group_list = MemberModel::getGroups();
|
||||
Context::set('group_list', $group_list);
|
||||
|
|
@ -286,6 +288,19 @@ class ModuleAdminModel extends Module
|
|||
$this->add('grantList', $grantList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get defined scopes of module admin.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getModuleAdminScopes(): array
|
||||
{
|
||||
$obj = new \stdClass;
|
||||
$obj->scopes = lang('module.admin_scopes')->getArrayCopy();
|
||||
ModuleHandler::triggerCall('module.getModuleAdminScopes', 'after', $obj);
|
||||
return $obj->scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Common:: skin setting page for the module
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -148,6 +148,12 @@ class Module extends ModuleObject
|
|||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// check scope column on module_admins table
|
||||
if (!$oDB->isColumnExists('module_admins', 'scopes'))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -311,6 +317,12 @@ class Module extends ModuleObject
|
|||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
// check scope column on module_admins table
|
||||
if (!$oDB->isColumnExists('module_admins', 'scopes'))
|
||||
{
|
||||
$oDB->addColumn('module_admins', 'scopes', 'text', null, null, false, 'member_srl');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -806,7 +806,7 @@ class ModuleController extends Module
|
|||
/**
|
||||
* @brief Specify the admin ID to a module
|
||||
*/
|
||||
function insertAdminId($module_srl, $admin_id)
|
||||
function insertAdminId($module_srl, $admin_id, $scopes = null)
|
||||
{
|
||||
if (strpos($admin_id, '@') !== false)
|
||||
{
|
||||
|
|
@ -824,6 +824,14 @@ class ModuleController extends Module
|
|||
$args = new stdClass();
|
||||
$args->module_srl = intval($module_srl);
|
||||
$args->member_srl = $member_info->member_srl;
|
||||
if (is_array($scopes))
|
||||
{
|
||||
$args->scopes = json_encode(array_values($scopes));
|
||||
}
|
||||
else
|
||||
{
|
||||
$args->scopes = new Rhymix\Framework\Parsers\DBQuery\NullValue;
|
||||
}
|
||||
$output = executeQuery('module.insertAdminId', $args);
|
||||
|
||||
Rhymix\Framework\Cache::delete("site_and_module:module_admins:" . intval($module_srl));
|
||||
|
|
|
|||
|
|
@ -1853,7 +1853,9 @@ class ModuleModel extends Module
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Check if a member is a module administrator
|
||||
* Check if a member is a module administrator
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public static function isModuleAdmin($member_info, $module_srl = null)
|
||||
{
|
||||
|
|
@ -1882,14 +1884,22 @@ class ModuleModel extends Module
|
|||
$module_admins = array();
|
||||
foreach ($output->data as $module_admin)
|
||||
{
|
||||
$module_admins[$module_admin->member_srl] = true;
|
||||
$module_admins[$module_admin->member_srl] = $module_admin->scopes ? json_decode($module_admin->scopes) : true;
|
||||
}
|
||||
if ($output->toBool())
|
||||
{
|
||||
Rhymix\Framework\Cache::set("site_and_module:module_admins:$module_srl", $module_admins, 0, true);
|
||||
}
|
||||
}
|
||||
return isset($module_admins[$member_info->member_srl]);
|
||||
|
||||
if (isset($module_admins[$member_info->member_srl]))
|
||||
{
|
||||
return $module_admins[$member_info->member_srl];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1900,8 +1910,14 @@ class ModuleModel extends Module
|
|||
$obj = new stdClass();
|
||||
$obj->module_srl = $module_srl;
|
||||
$output = executeQueryArray('module.getAdminID', $obj);
|
||||
if(!$output->toBool() || !$output->data) return;
|
||||
|
||||
if (!$output->toBool() || !$output->data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach ($output->data as $row)
|
||||
{
|
||||
$row->scopes = !empty($row->scopes) ? json_decode($row->scopes) : null;
|
||||
}
|
||||
return $output->data;
|
||||
}
|
||||
|
||||
|
|
@ -2129,7 +2145,12 @@ class ModuleModel extends Module
|
|||
}
|
||||
|
||||
/**
|
||||
* @brief Return privileges(granted) information by using module info, xml info and member info
|
||||
* Get privileges(granted) information by using module info, xml info and member info
|
||||
*
|
||||
* @param object $module_info
|
||||
* @param object $member_info
|
||||
* @param ?object $xml_info
|
||||
* @return Rhymix\Modules\Module\Models\Permission
|
||||
*/
|
||||
public static function getGrant($module_info, $member_info, $xml_info = null)
|
||||
{
|
||||
|
|
@ -2148,8 +2169,6 @@ class ModuleModel extends Module
|
|||
}
|
||||
}
|
||||
|
||||
$grant = new stdClass;
|
||||
|
||||
// Get information of module.xml
|
||||
if(!$xml_info)
|
||||
{
|
||||
|
|
@ -2172,6 +2191,7 @@ class ModuleModel extends Module
|
|||
$privilege_list = array_unique($privilege_list, SORT_STRING);
|
||||
|
||||
// Grant first
|
||||
$grant = new Rhymix\Modules\Module\Models\Permission;
|
||||
foreach($privilege_list as $val)
|
||||
{
|
||||
// If an administrator, grant all
|
||||
|
|
@ -2180,7 +2200,7 @@ class ModuleModel extends Module
|
|||
$grant->{$val} = true;
|
||||
}
|
||||
// If a module manager, grant all (except 'root', 'is_admin')
|
||||
else if($is_module_admin === true && $val !== 'root' && $val !== 'is_admin')
|
||||
elseif ($is_module_admin && $val !== 'root' && $val !== 'is_admin')
|
||||
{
|
||||
$grant->{$val} = true;
|
||||
}
|
||||
|
|
@ -2196,6 +2216,20 @@ class ModuleModel extends Module
|
|||
}
|
||||
}
|
||||
|
||||
// If module admin, add scopes
|
||||
if ($member_info && $member_info->is_admin == 'Y')
|
||||
{
|
||||
$grant->scopes = true;
|
||||
}
|
||||
elseif ($is_module_admin)
|
||||
{
|
||||
$grant->scopes = $is_module_admin;
|
||||
}
|
||||
else
|
||||
{
|
||||
$grant->scopes = [];
|
||||
}
|
||||
|
||||
// If access were not granted, check more
|
||||
if(!$grant->access)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2,6 +2,9 @@
|
|||
<tables>
|
||||
<table name="module_admins" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="*" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="module_srl" var="module_srl" filter="number" />
|
||||
<condition operation="equal" column="member_srl" var="member_srl" pipe="and" />
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
<columns>
|
||||
<column name="module_srl" var="module_srl" notnull="notnull" />
|
||||
<column name="member_srl" var="member_srl" notnull="notnull" />
|
||||
<column name="scopes" var="scopes" />
|
||||
<column name="regdate" default="curdate()" />
|
||||
</columns>
|
||||
</query>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
<table name="module_admins">
|
||||
<column name="module_srl" type="number" size="11" notnull="notnull" unique="unique_module_admin" />
|
||||
<column name="member_srl" type="number" size="11" notnull="notnull" unique="unique_module_admin" />
|
||||
<column name="scopes" type="text" />
|
||||
<column name="regdate" type="date" index="idx_regdate" />
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -3,5 +3,5 @@
|
|||
<column name="handler" type="varchar" size="191" notnull="notnull" />
|
||||
<column name="args" type="longtext" notnull="notnull" />
|
||||
<column name="options" type="longtext" notnull="notnull" />
|
||||
<column name="regdate" type="datetime" notnull="notnull" default="current_timestamp()" index="idx_regdate" />
|
||||
<column name="regdate" type="datetime" notnull="notnull" index="idx_regdate" />
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<form action="./" method="post" onsubmit="return procFilter(this, insert_grant)" id="fo_obj">
|
||||
<input type="hidden" name="module_srl" value="{$module_srl}" />
|
||||
<input type="hidden" name="admin_member" value="<!--@foreach($admin_member as $key => $val)--><!--@if($member_config->identifier == 'email_address')-->{$val->email_address},<!--@else-->{$val->user_id},<!--@end--><!--@end-->" />
|
||||
|
||||
|
||||
<div class="section x_form-horizontal">
|
||||
<h1>{$lang->module_admin}</h1>
|
||||
<div class="x_control-group">
|
||||
|
|
@ -34,6 +34,21 @@
|
|||
<p id="adminListHelp" class="x_help-block">{$lang->about_admin_id}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label">
|
||||
{$lang->admin_scope}
|
||||
</label>
|
||||
<div class="x_controls">
|
||||
{@ $default_scopes = array_keys($manager_scopes)}
|
||||
{@ $admin_scopes = $admin_member ? (array_first($admin_member)->scopes ?? $default_scopes) : $default_scopes}
|
||||
<!--@foreach($manager_scopes as $key => $val)-->
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="admin_scopes[]" value="{$key}" checked="checked"|cond="in_array($key, $admin_scopes)" />
|
||||
{$val}
|
||||
</label>
|
||||
<!--@endforeach-->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
<h1 cond="($module_info->display_mobile_title ?? '') !== 'hide'">{$oDocument->getTitle()}</h1>
|
||||
{$oDocument->getContent(($module_info->display_popupmenu ?? '') !== 'hide')}
|
||||
{$oDocument->getContent(false)}
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ jQuery(function($){
|
|||
<tbody>
|
||||
<!--@foreach($page_list as $no => $val)-->
|
||||
<tr class="row{$cycle_idx}">
|
||||
<td>{$no}</td>
|
||||
<td>{$val->module_srl}</td>
|
||||
<td>
|
||||
<!--@if(!$val->module_category_srl)-->
|
||||
<!--@if($val->site_srl)-->
|
||||
|
|
|
|||
|
|
@ -3,15 +3,15 @@
|
|||
<grants />
|
||||
<actions>
|
||||
<action name="getMembersPointInfo" type="model" permission="member" />
|
||||
|
||||
|
||||
<action name="dispPointAdminConfig" type="view" admin_index="true" menu_name="point" menu_index="true" />
|
||||
<action name="dispPointAdminModuleConfig" type="view" menu_name="point" />
|
||||
<action name="dispPointAdminPointList" type="view" menu_name="point" />
|
||||
|
||||
|
||||
<action name="procPointAdminInsertConfig" type="controller" ruleset="insertConfig" />
|
||||
<action name="procPointAdminInsertModuleConfig" type="controller" />
|
||||
<action name="procPointAdminUpdatePoint" type="controller" ruleset="updatePoint" />
|
||||
<action name="procPointAdminInsertPointModuleConfig" type="controller" permission="manager" check_var="target_module_srl" />
|
||||
<action name="procPointAdminInsertPointModuleConfig" type="controller" permission="manager:config:*" check_var="target_module_srl" />
|
||||
<action name="procPointAdminReCal" type="controller" />
|
||||
<action name="procPointAdminApplyPoint" type="controller" />
|
||||
<action name="procPointAdminReset" type="controller" />
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
<action name="dispRssAdminIndex" type="view" admin_index="true" menu_name="rss" menu_index="true" />
|
||||
<action name="procRssAdminInsertConfig" type="controller" ruleset="insertRssConfig" />
|
||||
<action name="procRssAdminInsertModuleConfig" type="controller" permission="manager" check_var="target_module_srl" />
|
||||
<action name="procRssAdminInsertModuleConfig" type="controller" permission="manager:config:*" check_var="target_module_srl" />
|
||||
<action name="procRssAdminDeleteFeedImage" type="controller" />
|
||||
</actions>
|
||||
<eventHandlers>
|
||||
|
|
|
|||
|
|
@ -17,11 +17,15 @@
|
|||
<action name="procSpamfilterAdminInsertConfigCaptcha" type="controller" />
|
||||
</actions>
|
||||
<eventHandlers>
|
||||
<eventHandler before="document.manage" class="controller" method="triggerManageDocument" />
|
||||
<eventHandler before="document.insertDocument" class="controller" method="triggerInsertDocument" />
|
||||
<eventHandler before="document.updateDocument" class="controller" method="triggerInsertDocument" />
|
||||
<eventHandler before="document.manage" class="controller" method="triggerManageDocument" />
|
||||
<eventHandler before="document.updateVotedCount" class="controller" method="triggerVote" />
|
||||
<eventHandler before="document.declaredDocument" class="controller" method="triggerDeclare" />
|
||||
<eventHandler before="comment.insertComment" class="controller" method="triggerInsertComment" />
|
||||
<eventHandler before="comment.updateComment" class="controller" method="triggerInsertComment" />
|
||||
<eventHandler before="comment.updateVotedCount" class="controller" method="triggerVote" />
|
||||
<eventHandler before="comment.declaredComment" class="controller" method="triggerDeclare" />
|
||||
<eventHandler before="communication.sendMessage" class="controller" method="triggerSendMessage" />
|
||||
<eventHandler before="moduleObject.proc" class="controller" method="triggerCheckCaptcha" />
|
||||
</eventHandlers>
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@ $lang->word = 'Keyword';
|
|||
$lang->hit = 'Hit';
|
||||
$lang->latest_hit = 'Latest Hits';
|
||||
$lang->custom_message = 'Error Message';
|
||||
$lang->enable_description = 'Enter # as description';
|
||||
$lang->about_custom_message = 'You can customize the error message that will be displayed if a spam keyword is found.<br>%s can be used as a placeholder for the keyword. If not used, the keyword will be hidden.';
|
||||
$lang->about_interval = 'All articles attempted for posting within the assigned time will be blocked.';
|
||||
$lang->about_denied_ip = 'Please enter one IP address (e.g. 127.0.0.1) or range (e.g. 127.0.0.0/24) per line. Comments may start with // or #.';
|
||||
$lang->about_denied_word = 'Please enter one keyword (2 to 180 characters) per line. Comments may start with #.<br>Formats such as /spam(key|word)?/ will be treated as a regular expression, and must use the proper syntax.<br>Spam keywords are not case sensitive.';
|
||||
$lang->about_denied_word = 'Please enter one keyword (2 to 180 characters) per line. Comments start with #. If you need to block a keyword that includes #, disable the checkbox above.<br>Formats such as /spam(key|word)?/ will be treated as a regular expression, and must use the proper syntax.<br>Spam keywords are not case sensitive.';
|
||||
$lang->msg_alert_limited_by_config = 'Please do not post repeatedly within %d seconds. If you keep trying, your IP address will be blocked.';
|
||||
$lang->msg_alert_limited_message_by_config = 'Please do not send messages repeatedly within %d seconds. If you keep trying, your IP address will be blocked.';
|
||||
$lang->msg_alert_denied_word = 'The word "%s" is not allowed on this site.';
|
||||
|
|
@ -27,7 +28,9 @@ $lang->cmd_spamfilter_except_member = 'Except Members';
|
|||
$lang->cmd_spamfilter_filter_html = 'HTML';
|
||||
$lang->cmd_spamfilter_is_regexp = 'REGEXP';
|
||||
$lang->cmd_interval = 'Block Post/Comment Spam';
|
||||
$lang->cmd_interval_help = 'Block IP addresses that post or comment too much in a short time. Blocked IP addresses will not be able to post, comment, or send messages.';
|
||||
$lang->cmd_interval_help = 'Block IP addresses that post or comment too much in a short time.';
|
||||
$lang->cmd_blocked_actions = 'Blocked actions';
|
||||
$lang->cmd_blocked_actions_help = 'The actions above will be disabled from blocked IP addresses.';
|
||||
$lang->cmd_check_trackback = 'Block Trackback Spam';
|
||||
$lang->cmd_check_trackback_help = 'Block IP addresses that send multiple trackbacks to the same document.<br>This only works if the trackback module is installed.';
|
||||
$lang->cmd_limits_interval = 'Block Interval';
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@ $lang->word = '키워드';
|
|||
$lang->hit = '히트';
|
||||
$lang->latest_hit = '최근 히트';
|
||||
$lang->custom_message = '차단 메시지 설정';
|
||||
$lang->enable_description = '# 뒷부분은 설명으로 입력';
|
||||
$lang->about_custom_message = '스팸 키워드 발견시 표시할 에러 메시지를 지정할 수 있습니다.<br>%s를 넣으면 그 자리에 해당 키워드를 표시하고, 그렇지 않으면 키워드를 숨깁니다.';
|
||||
$lang->about_interval = '지정된 시간 내에 글을 등록하지 못하게 합니다.';
|
||||
$lang->about_denied_ip = '한 줄에 하나씩 IP 주소 또는 대역을 입력하세요. "//" 또는 "#" 뒷부분은 설명으로 저장됩니다.<br>예: 127.0.0.1 // 설명, 127.0.0.1 #설명<br>IP 대역 표기법은 <a href="https://github.com/rhymix/rhymix-docs/blob/master/ko/misc/ipfilter.md" target="_blank">매뉴얼</a>을 참고하십시오.';
|
||||
$lang->about_denied_word = '한 줄에 하나씩 스팸 키워드(2~180자)를 입력하세요. "#" 뒷부분은 설명으로 입력됩니다.<br>/스팸(키+|워드)?/ 와 같은 형태로 입력하면 정규식으로 간주하며, 올바른 정규식 문법을 사용해야 합니다.<br>대소문자는 구분하지 않습니다.';
|
||||
$lang->about_denied_word = '한 줄에 하나씩 스팸 키워드(2~180자)를 입력하세요. "#" 뒷부분은 설명으로 입력됩니다. "#"을 포함하는 키워드를 차단하려면 위의 설정을 해제하세요.<br>/스팸(키+|워드)?/ 와 같은 형태로 입력하면 정규식으로 간주하며, 올바른 정규식 문법을 사용해야 합니다.<br>대소문자는 구분하지 않습니다.';
|
||||
$lang->msg_alert_limited_by_config = '%d초 이내에 연속 글 작성은 금지됩니다. 계속 시도하면 IP가 차단될 수 있습니다.';
|
||||
$lang->msg_alert_limited_message_by_config = '%d초 이내에 연속 쪽지 발송은 금지됩니다. 계속 시도하면 IP가 차단될 수 있습니다.';
|
||||
$lang->msg_alert_denied_word = '"%s"은(는) 사용이 금지된 단어입니다.';
|
||||
|
|
@ -26,8 +27,10 @@ $lang->msg_alert_trackback_denied = '한 글에는 하나의 트랙백만 허용
|
|||
$lang->cmd_spamfilter_except_member = '회원 제외';
|
||||
$lang->cmd_spamfilter_filter_html = 'HTML';
|
||||
$lang->cmd_spamfilter_is_regexp = '정규식';
|
||||
$lang->cmd_interval = '글, 댓글 스팸 차단';
|
||||
$lang->cmd_interval_help = '지정한 시간 내에 다수의 글이나 댓글을 작성하면 스패머로 간주하고 글, 댓글 작성과 엮인글 발송, 쪽지 발송을 차단합니다.';
|
||||
$lang->cmd_interval = '단시간 다수 작성 차단';
|
||||
$lang->cmd_interval_help = '지정한 시간 내에 다수의 글이나 댓글을 작성하면 스패머로 간주하고 IP를 차단합니다.';
|
||||
$lang->cmd_blocked_actions = '차단할 행동';
|
||||
$lang->cmd_blocked_actions_help = '차단된 IP에서는 위의 행동들을 할 수 없게 됩니다.';
|
||||
$lang->cmd_check_trackback = '트랙백 스팸 차단';
|
||||
$lang->cmd_check_trackback_help = '하나의 글에 2회 이상 엮인글을 등록하면 스패머로 간주하고 엮인글을 차단합니다.<br>트랙백 모듈이 설치되어 있는 경우에만 적용됩니다.';
|
||||
$lang->cmd_limits_interval = '글, 댓글 제한 시간';
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class SpamfilterAdminController extends Spamfilter
|
|||
$config = ModuleModel::getModuleConfig('spamfilter') ?: new stdClass;
|
||||
|
||||
// Get the default information
|
||||
$args = Context::gets('limits', 'limits_interval', 'limits_count', 'ipv4_block_range', 'ipv6_block_range', 'except_ip', 'custom_message');
|
||||
$args = Context::gets('limits', 'limits_interval', 'limits_count', 'blocked_actions', 'ipv4_block_range', 'ipv6_block_range', 'except_ip', 'custom_message');
|
||||
|
||||
// Set default values
|
||||
if($args->limits != 'Y')
|
||||
|
|
@ -38,6 +38,7 @@ class SpamfilterAdminController extends Spamfilter
|
|||
$args->except_ip = array_map('trim', preg_split('/[\n,]/', trim($args->except_ip ?? ''), -1, \PREG_SPLIT_NO_EMPTY));
|
||||
$args->limits_interval = intval($args->limits_interval);
|
||||
$args->limits_count = intval($args->limits_count);
|
||||
$args->blocked_actions = array_values($args->blocked_actions ?? []);
|
||||
$args->custom_message = escape(utf8_trim($args->custom_message));
|
||||
foreach ($args as $key => $val)
|
||||
{
|
||||
|
|
@ -177,9 +178,10 @@ class SpamfilterAdminController extends Spamfilter
|
|||
{
|
||||
//스팸 키워드 추가
|
||||
$word_list = Context::get('word_list');
|
||||
$enable_description = Context::get('enable_description') ?? 'N';
|
||||
if($word_list)
|
||||
{
|
||||
$output = $this->insertWord($word_list);
|
||||
$output = $this->insertWord($word_list, $enable_description);
|
||||
if(!$output->toBool() && !$output->get('fail_list')) return $output;
|
||||
|
||||
if($output->get('fail_list')) $message_fail = '<em>'.sprintf(lang('msg_faillist'),$output->get('fail_list')).'</em>';
|
||||
|
|
@ -258,7 +260,7 @@ class SpamfilterAdminController extends Spamfilter
|
|||
* @brief Register the spam word
|
||||
* The post, which contains the newly registered spam word, should be considered as a spam
|
||||
*/
|
||||
public function insertWord($word_list)
|
||||
public function insertWord($word_list, $enable_description = 'Y')
|
||||
{
|
||||
if (!is_array($word_list))
|
||||
{
|
||||
|
|
@ -273,7 +275,7 @@ class SpamfilterAdminController extends Spamfilter
|
|||
{
|
||||
continue;
|
||||
}
|
||||
if (preg_match('/^(.+?)#(.+)$/', $word, $matches))
|
||||
if ($enable_description === 'Y' && preg_match('/^(.+?)#(.+)$/', $word, $matches))
|
||||
{
|
||||
$word = trim($matches[1]);
|
||||
$description = trim($matches[2]);
|
||||
|
|
|
|||
|
|
@ -50,10 +50,17 @@ class SpamfilterController extends Spamfilter
|
|||
if($grant->manager) return;
|
||||
}
|
||||
|
||||
$oFilterModel = getModel('spamfilter');
|
||||
// Check if the IP is prohibited
|
||||
$output = $oFilterModel->isDeniedIP();
|
||||
if(!$output->toBool()) return $output;
|
||||
$output = SpamfilterModel::isDeniedIP();
|
||||
if(!$output->toBool())
|
||||
{
|
||||
$config = SpamfilterModel::getConfig();
|
||||
if (!isset($config->blocked_actions) || in_array('document', $config->blocked_actions))
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a ban on the word
|
||||
$filter_targets = [$obj->title, $obj->content, $obj->tags ?? ''];
|
||||
if(!$is_logged)
|
||||
|
|
@ -71,7 +78,7 @@ class SpamfilterController extends Spamfilter
|
|||
}
|
||||
}
|
||||
}
|
||||
$output = $oFilterModel->isDeniedWord(implode("\n", $filter_targets));
|
||||
$output = SpamfilterModel::isDeniedWord(implode("\n", $filter_targets));
|
||||
if(!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
|
|
@ -79,7 +86,7 @@ class SpamfilterController extends Spamfilter
|
|||
// Check the specified time beside the modificaiton time
|
||||
if($obj->document_srl == 0)
|
||||
{
|
||||
$output = $oFilterModel->checkLimited();
|
||||
$output = SpamfilterModel::checkLimited();
|
||||
if(!$output->toBool()) return $output;
|
||||
}
|
||||
// Save a log
|
||||
|
|
@ -103,10 +110,17 @@ class SpamfilterController extends Spamfilter
|
|||
if($grant->manager) return;
|
||||
}
|
||||
|
||||
$oFilterModel = getModel('spamfilter');
|
||||
// Check if the IP is prohibited
|
||||
$output = $oFilterModel->isDeniedIP();
|
||||
if(!$output->toBool()) return $output;
|
||||
$output = SpamfilterModel::isDeniedIP();
|
||||
if(!$output->toBool())
|
||||
{
|
||||
$config = SpamfilterModel::getConfig();
|
||||
if (!isset($config->blocked_actions) || in_array('comment', $config->blocked_actions))
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a ban on the word
|
||||
if($is_logged)
|
||||
{
|
||||
|
|
@ -116,12 +130,12 @@ class SpamfilterController extends Spamfilter
|
|||
{
|
||||
$text = $obj->content . ' ' . $obj->nick_name . ' ' . $obj->homepage;
|
||||
}
|
||||
$output = $oFilterModel->isDeniedWord($text);
|
||||
$output = SpamfilterModel::isDeniedWord($text);
|
||||
if(!$output->toBool()) return $output;
|
||||
// If the specified time check is not modified
|
||||
if(!$obj->__isupdate)
|
||||
{
|
||||
$output = $oFilterModel->checkLimited();
|
||||
$output = SpamfilterModel::checkLimited();
|
||||
if(!$output->toBool()) return $output;
|
||||
}
|
||||
unset($obj->__isupdate);
|
||||
|
|
@ -182,31 +196,101 @@ class SpamfilterController extends Spamfilter
|
|||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Block voting from a spam IP.
|
||||
*/
|
||||
function triggerVote(&$obj)
|
||||
{
|
||||
if (!empty($_SESSION['avoid_log']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->user->isAdmin() || (Context::get('grant')->manager ?? false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$config = SpamfilterModel::getConfig();
|
||||
if ($obj->point > 0 && isset($config->blocked_actions) && !in_array('vote_up', $config->blocked_actions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
if ($obj->point < 0 && isset($config->blocked_actions) && !in_array('vote_down', $config->blocked_actions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$output = SpamfilterModel::isDeniedIP();
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Block reporting from a spam IP.
|
||||
*/
|
||||
function triggerDeclare(&$obj)
|
||||
{
|
||||
if (!empty($_SESSION['avoid_log']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ($this->user->isAdmin() || (Context::get('grant')->manager ?? false))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$config = SpamfilterModel::getConfig();
|
||||
if (isset($config->blocked_actions) && !in_array('declare', $config->blocked_actions))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$output = SpamfilterModel::isDeniedIP();
|
||||
if (!$output->toBool())
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief The routine process to check the time it takes to store a message, when writing it, and to ban IP/word
|
||||
*/
|
||||
function triggerSendMessage(&$obj)
|
||||
{
|
||||
if($_SESSION['avoid_log']) return;
|
||||
if($this->user->isAdmin() || !empty($_SESSION['avoid_log']))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(isset($obj->use_spamfilter) && $obj->use_spamfilter === false)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$logged_info = Context::get('logged_info');
|
||||
if($logged_info->is_admin == 'Y') return;
|
||||
|
||||
$oFilterModel = getModel('spamfilter');
|
||||
// Check if the IP is prohibited
|
||||
$output = $oFilterModel->isDeniedIP();
|
||||
if(!$output->toBool()) return $output;
|
||||
$output = SpamfilterModel::isDeniedIP();
|
||||
if(!$output->toBool())
|
||||
{
|
||||
$config = SpamfilterModel::getConfig();
|
||||
if (!isset($config->blocked_actions) || in_array('message', $config->blocked_actions))
|
||||
{
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if there is a ban on the word
|
||||
$text = $obj->title . ' ' . $obj->content;
|
||||
$output = $oFilterModel->isDeniedWord($text);
|
||||
$output = SpamfilterModel::isDeniedWord($text);
|
||||
if(!$output->toBool()) return $output;
|
||||
|
||||
// Check the specified time
|
||||
$output = $oFilterModel->checkLimited(TRUE);
|
||||
$output = SpamfilterModel::checkLimited(TRUE);
|
||||
if(!$output->toBool()) return $output;
|
||||
|
||||
// Save a log
|
||||
$this->insertLog();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,17 +7,10 @@
|
|||
*/
|
||||
class SpamfilterModel extends Spamfilter
|
||||
{
|
||||
/**
|
||||
* @brief Initialization
|
||||
*/
|
||||
function init()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Return the user setting values of the Spam filter module
|
||||
*/
|
||||
function getConfig()
|
||||
public static function getConfig()
|
||||
{
|
||||
return ModuleModel::getModuleConfig('spamfilter') ?: new stdClass;
|
||||
}
|
||||
|
|
@ -25,7 +18,7 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Return the list of registered IP addresses which were banned
|
||||
*/
|
||||
function getDeniedIPList($sort_index = 'regdate')
|
||||
public static function getDeniedIPList($sort_index = 'regdate')
|
||||
{
|
||||
$args = new stdClass();
|
||||
$args->sort_index = $sort_index;
|
||||
|
|
@ -38,12 +31,12 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Check if the ipaddress is in the list of banned IP addresses
|
||||
*/
|
||||
function isDeniedIP()
|
||||
public static function isDeniedIP()
|
||||
{
|
||||
$ip_list = Rhymix\Framework\Cache::get('spamfilter:denied_ip_list');
|
||||
if ($ip_list === null)
|
||||
{
|
||||
$ip_list = $this->getDeniedIPList();
|
||||
$ip_list = self::getDeniedIPList();
|
||||
Rhymix\Framework\Cache::set('spamfilter:denied_ip_list', $ip_list);
|
||||
}
|
||||
if (!count($ip_list))
|
||||
|
|
@ -75,7 +68,7 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Return the list of registered Words which were banned
|
||||
*/
|
||||
function getDeniedWordList($sort_index = 'hit')
|
||||
public static function getDeniedWordList($sort_index = 'hit')
|
||||
{
|
||||
$args = new stdClass();
|
||||
$args->sort_index = $sort_index;
|
||||
|
|
@ -86,12 +79,12 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Check if the text, received as a parameter, is banned or not
|
||||
*/
|
||||
function isDeniedWord($text)
|
||||
public static function isDeniedWord($text)
|
||||
{
|
||||
$word_list = Rhymix\Framework\Cache::get('spamfilter:denied_word_list');
|
||||
if ($word_list === null)
|
||||
{
|
||||
$word_list = $this->getDeniedWordList();
|
||||
$word_list = self::getDeniedWordList();
|
||||
Rhymix\Framework\Cache::set('spamfilter:denied_word_list', $word_list);
|
||||
}
|
||||
if (!count($word_list))
|
||||
|
|
@ -128,7 +121,7 @@ class SpamfilterModel extends Spamfilter
|
|||
$args->word = $word;
|
||||
executeQuery('spamfilter.updateDeniedWordHit', $args);
|
||||
|
||||
$config = $this->getConfig();
|
||||
$config = self::getConfig();
|
||||
|
||||
if($config->custom_message)
|
||||
{
|
||||
|
|
@ -161,9 +154,9 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Check the specified time
|
||||
*/
|
||||
function checkLimited($isMessage = FALSE)
|
||||
public static function checkLimited($isMessage = FALSE)
|
||||
{
|
||||
$config = $this->getConfig();
|
||||
$config = self::getConfig();
|
||||
|
||||
if($config->limits != 'Y') return new BaseObject();
|
||||
$limit_count = $config->limits_count ?: 3;
|
||||
|
|
@ -177,7 +170,7 @@ class SpamfilterModel extends Spamfilter
|
|||
}
|
||||
}
|
||||
|
||||
$count = $this->getLogCount($interval);
|
||||
$count = self::getLogCount($interval);
|
||||
|
||||
// Ban the IP address if the interval is exceeded
|
||||
if($count>=$limit_count)
|
||||
|
|
@ -272,7 +265,7 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Check if the trackbacks have already been registered to a particular article
|
||||
*/
|
||||
function isInsertedTrackback($document_srl)
|
||||
public static function isInsertedTrackback($document_srl)
|
||||
{
|
||||
$oTrackbackModel = getModel('trackback');
|
||||
if (is_object($oTrackbackModel) && method_exists($oTrackbackModel, 'getTrackbackCountByIPAddress'))
|
||||
|
|
@ -289,7 +282,7 @@ class SpamfilterModel extends Spamfilter
|
|||
/**
|
||||
* @brief Return the number of logs recorded within the interval for the specified IPaddress
|
||||
*/
|
||||
function getLogCount($time = 60, $ipaddress='')
|
||||
public static function getLogCount($time = 60, $ipaddress='')
|
||||
{
|
||||
if(!$ipaddress) $ipaddress = \RX_CLIENT_IP;
|
||||
|
||||
|
|
|
|||
|
|
@ -27,6 +27,36 @@
|
|||
<p class="x_help-block">{$lang->cmd_interval_help}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label">{$lang->cmd_blocked_actions}</label>
|
||||
<div class="x_controls">
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="blocked_actions[]" value="document" checked="checked"|cond="!$config->blocked_actions || in_array('document', $config->blocked_actions)" />
|
||||
{$lang->document}
|
||||
</label>
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="blocked_actions[]" value="comment" checked="checked"|cond="!$config->blocked_actions || in_array('comment', $config->blocked_actions)" />
|
||||
{$lang->comment}
|
||||
</label>
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="blocked_actions[]" value="vote_up" checked="checked"|cond="!$config->blocked_actions || in_array('vote_up', $config->blocked_actions)" />
|
||||
{$lang->cmd_vote}
|
||||
</label>
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="blocked_actions[]" value="vote_down" checked="checked"|cond="!$config->blocked_actions || in_array('vote_down', $config->blocked_actions)" />
|
||||
{$lang->cmd_vote_down}
|
||||
</label>
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="blocked_actions[]" value="declare" checked="checked"|cond="!$config->blocked_actions || in_array('declare', $config->blocked_actions)" />
|
||||
{$lang->cmd_declare}
|
||||
</label>
|
||||
<label class="x_inline">
|
||||
<input type="checkbox" name="blocked_actions[]" value="message" checked="checked"|cond="!$config->blocked_actions || in_array('message', $config->blocked_actions)" />
|
||||
{$lang->member_message}
|
||||
</label>
|
||||
<p class="x_help-block">{$lang->cmd_blocked_actions_help}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label" for="custom_message">{$lang->custom_message}</label>
|
||||
<div class="x_controls">
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
<input type="hidden" name="active" value="word" />
|
||||
<input type="hidden" name="xe_validator_id" value="modules/spamfilter/tpl/1" />
|
||||
<textarea name="word_list" title="{$lang->add_denied_word}" rows="4" cols="42" style="width:100%"></textarea>
|
||||
<label><input type="checkbox" name="enable_description" value="Y" checked="checked" /> {$lang->enable_description}</label>
|
||||
<p class="x_help-block">{$lang->about_denied_word}</p>
|
||||
<span class="x_pull-right" style="margin-right:-14px">
|
||||
<button type="submit" class="x_btn x_btn-primary">{$lang->add_denied_word}</button>
|
||||
|
|
|
|||
|
|
@ -16,13 +16,11 @@ class SMSTest extends \Codeception\Test\Unit
|
|||
{
|
||||
$drivers = Rhymix\Framework\SMS::getSupportedDrivers();
|
||||
$this->assertTrue(isset($drivers['dummy']));
|
||||
$this->assertTrue(isset($drivers['apistore']));
|
||||
$this->assertTrue(isset($drivers['coolsms']));
|
||||
$this->assertTrue(isset($drivers['iwinv']));
|
||||
$this->assertTrue(isset($drivers['solapi']));
|
||||
$this->assertTrue(isset($drivers['ppurio']));
|
||||
$this->assertEquals('Dummy', $drivers['dummy']['name']);
|
||||
$this->assertTrue(in_array('api_user', $drivers['apistore']['required']));
|
||||
$this->assertTrue(in_array('api_key', $drivers['coolsms']['required']));
|
||||
$this->assertTrue(in_array('api_url', $drivers['iwinv']['required']));
|
||||
$this->assertTrue(in_array('api_user', $drivers['ppurio']['required']));
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ class content extends WidgetHandler
|
|||
$obj->sort_index = $args->order_target;
|
||||
$obj->list_count = $args->list_count * $args->page_count;
|
||||
$obj->statusList = [1];
|
||||
if($args->show_secret != 'Y')
|
||||
if(($args->show_secret ?? 'N') !== 'Y')
|
||||
{
|
||||
$obj->is_secret = 'N';
|
||||
}
|
||||
|
|
@ -201,7 +201,7 @@ class content extends WidgetHandler
|
|||
foreach($output as $key => $oComment)
|
||||
{
|
||||
$oDocument = getModel('document')->getDocument($oComment->get('document_srl'), false, false);
|
||||
if(!$oDocument->isExists() || $oDocument->isSecret() && $args->show_secret != 'Y')
|
||||
if(!$oDocument->isExists() || $oDocument->isSecret() && ($args->show_secret ?? 'N') !== 'Y')
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -256,7 +256,7 @@ class content extends WidgetHandler
|
|||
$obj->order_type = $args->order_type=="desc"?"desc":"asc";
|
||||
}
|
||||
|
||||
if($args->show_secret == 'Y')
|
||||
if(($args->show_secret ?? 'N') == 'Y')
|
||||
{
|
||||
$obj->statusList = array('PUBLIC', 'SECRET');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@
|
|||
<span class="icon">{$item->printExtraImages()}</span>
|
||||
<!--@end-->
|
||||
|
||||
<!--@if($widget_info->option_view_arr[$j+1]=='regdate')-->
|
||||
<!--@if(isset($widget_info->option_view_arr[$j+1]) && $widget_info->option_view_arr[$j+1]=='regdate')-->
|
||||
<span class="date">{$item->getRegdate("Y-m-d")}</span> <span class="hour">{$item->getRegdate("H:i")}</span>
|
||||
<!--@end-->
|
||||
</p>
|
||||
|
|
@ -52,7 +52,7 @@
|
|||
<!--@else if($widget_info->option_view_arr[$j]=='content')-->
|
||||
<p class="text" style="margin-left:{$widget_info->thumbnail_width+20}px;">
|
||||
{$item->getContent()}
|
||||
<!--@if($widget_info->option_view_arr[$j+1]=='regdate')-->
|
||||
<!--@if(isset($widget_info->option_view_arr[$j+1]) && $widget_info->option_view_arr[$j+1]=='regdate')-->
|
||||
<span class="date">{$item->getRegdate("Y-m-d")}</span> <span class="hour">{$item->getRegdate("H:i")}</span>
|
||||
<!--@end-->
|
||||
</p>
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
<!--@else if($widget_info->option_view_arr[$j]=='nickname')-->
|
||||
<p class="authorArea" style="margin-left:{$widget_info->thumbnail_width+20}px;">
|
||||
<a href="#" onclick="return false;" class="author member_{$item->getMemberSrl()}" target="_blank"|cond="$widget_info->new_window">{$item->getNickName($widget_info->nickname_cut_size)}</a>
|
||||
<!--@if($widget_info->option_view_arr[$j+1]=='regdate')-->
|
||||
<!--@if(isset($widget_info->option_view_arr[$j+1]) && $widget_info->option_view_arr[$j+1]=='regdate')-->
|
||||
<span class="date">{$item->getRegdate("Y-m-d")}</span> <span class="hour">{$item->getRegdate("H:i")}</span>
|
||||
<!--@end-->
|
||||
</p>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue