Merge branch 'master' into pr/manager-scopes

This commit is contained in:
Kijin Sung 2024-10-27 23:09:40 +09:00
commit 2620049b4e
18 changed files with 136 additions and 202 deletions

View file

@ -2,7 +2,7 @@ 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:

View file

@ -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,
);
}

View file

@ -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);
}
}
}

View file

@ -693,7 +693,8 @@ class ModuleHandler extends Handler
}
}
if ($kind === 'admin') {
if ($kind === 'admin')
{
Context::addMetaTag('robots', 'noindex');
}

View file

@ -151,5 +151,7 @@ return array(
],
'use_rewrite' => true,
'use_sso' => false,
'other' => array(),
'other' => [
'proxy' => null,
],
);

View file

@ -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']);

View file

@ -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 = [];

View file

@ -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)
{

View file

@ -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;
}
}

View file

@ -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";
}

View file

@ -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

View file

@ -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())

View file

@ -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);

View file

@ -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>';

View file

@ -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> 파일에 아래와 같은 내용을 넣습니다.';

View file

@ -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">

View file

@ -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 &gt;&gt; {$user_info['dir']}logs{\DIRECTORY_SEPARATOR}queue.log 2&gt;&amp;1</code></pre>
<pre><code>* * * * * /usr/bin/php {\RX_BASEDIR}index.php common.cron &gt;&gt; {$user_info['dir']}logs{\DIRECTORY_SEPARATOR}queue.log 2&gt;&amp;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">

View file

@ -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']));