mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-06 18:21:39 +09:00
commit
04da475562
24 changed files with 1202 additions and 13 deletions
87
common/framework/drivers/push/apns.php
Normal file
87
common/framework/drivers/push/apns.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\Push;
|
||||
|
||||
/**
|
||||
* The APNs (Apple) Push driver.
|
||||
*/
|
||||
class APNs extends Base implements \Rhymix\Framework\Drivers\PushInterface
|
||||
{
|
||||
/**
|
||||
* Config keys used by this driver are stored here.
|
||||
*/
|
||||
protected static $_required_config = array('certificate', 'passphrase');
|
||||
protected static $_optional_config = array();
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Push driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'iOS (APNs)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current Push driver is supported on this server.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param object $message
|
||||
* @param array $tokens
|
||||
* @return object
|
||||
*/
|
||||
public function send(\Rhymix\Framework\Push $message, array $tokens)
|
||||
{
|
||||
$output = new \stdClass;
|
||||
$output->success = [];
|
||||
$output->invalid = [];
|
||||
$output->needUpdate = [];
|
||||
|
||||
// Set parameters
|
||||
$local_cert = $this->_config['certificate'];
|
||||
$passphrase = $this->_config['passphrase'];
|
||||
$alert = [];
|
||||
$alert['title'] = $message->getSubject();
|
||||
$alert['body'] = $message->getContent();
|
||||
|
||||
$body['aps'] = array('alert' => $alert);
|
||||
$payload = json_encode($body);
|
||||
|
||||
foreach($tokens as $token)
|
||||
{
|
||||
$ctx = stream_context_create();
|
||||
stream_context_set_option($ctx, 'ssl', 'local_cert', $local_cert);
|
||||
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
|
||||
|
||||
$fp = stream_socket_client('ssl://gateway.push.apple.com:2195', $err, $errstr, 5, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
|
||||
if(!$fp)
|
||||
{
|
||||
$message->addError('Failed to connect socket - error code: '. $err .' - '. $errstr);
|
||||
}
|
||||
$msg = chr(0) . pack('n', 32) . pack('H*', $token) . pack('n', strlen($payload)) . $payload;
|
||||
$result = fwrite($fp, $msg, strlen($msg));
|
||||
if(!$result)
|
||||
{
|
||||
$message->addError('APNs return empty response.');
|
||||
}
|
||||
$output->success[] = $token;
|
||||
fclose($fp);
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
97
common/framework/drivers/push/base.php
Normal file
97
common/framework/drivers/push/base.php
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\Push;
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* The base class for other Push drivers.
|
||||
*/
|
||||
abstract class Base implements \Rhymix\Framework\Drivers\PushInterface
|
||||
{
|
||||
/**
|
||||
* The configuration is stored here.
|
||||
*/
|
||||
protected $_config = null;
|
||||
|
||||
/**
|
||||
* Config keys used by this driver are stored here.
|
||||
*/
|
||||
protected static $_required_config = array();
|
||||
protected static $_optional_config = array();
|
||||
|
||||
/**
|
||||
* Direct invocation of the constructor is not permitted.
|
||||
*/
|
||||
protected function __construct(array $config)
|
||||
{
|
||||
$this->_config = $config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new instance of the current Push driver, using the given settings.
|
||||
*
|
||||
* @param array $config
|
||||
* @return object
|
||||
*/
|
||||
public static function getInstance(array $config): object
|
||||
{
|
||||
return new static($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Push driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string
|
||||
{
|
||||
return class_basename(get_called_class());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this Push driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRequiredConfig(): array
|
||||
{
|
||||
return static::$_required_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields optionally used by this Push driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOptionalConfig(): array
|
||||
{
|
||||
return static::$_optional_config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current Push driver is supported on this server.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param object $message
|
||||
* @param array $tokens
|
||||
* @return object
|
||||
*/
|
||||
public function send(\Rhymix\Framework\Push $message, array $tokens)
|
||||
{
|
||||
return new \stdClass;
|
||||
}
|
||||
}
|
||||
111
common/framework/drivers/push/fcm.php
Normal file
111
common/framework/drivers/push/fcm.php
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers\Push;
|
||||
|
||||
/**
|
||||
* The FCM (Google) Push driver.
|
||||
*/
|
||||
class FCM extends Base implements \Rhymix\Framework\Drivers\PushInterface
|
||||
{
|
||||
/**
|
||||
* Config keys used by this driver are stored here.
|
||||
*/
|
||||
protected static $_required_config = array('api_key');
|
||||
protected static $_optional_config = array();
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Push driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string
|
||||
{
|
||||
return 'Android (FCM)';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the current Push driver is supported on this server.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function isSupported(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param object $message
|
||||
* @param array $tokens
|
||||
* @return object
|
||||
*/
|
||||
public function send(\Rhymix\Framework\Push $message, array $tokens)
|
||||
{
|
||||
$output = new \stdClass;
|
||||
$output->success = [];
|
||||
$output->invalid = [];
|
||||
$output->needUpdate = [];
|
||||
|
||||
$url = 'https://fcm.googleapis.com/fcm/send';
|
||||
$api_key = $this->_config['api_key'];
|
||||
$headers = array(
|
||||
'Authorization' => 'key=' . $api_key,
|
||||
'Content-Type' => 'application/json',
|
||||
);
|
||||
|
||||
// Set notification
|
||||
$notification = [];
|
||||
$notification['title'] = $message->getSubject();
|
||||
$notification['body'] = $message->getContent();
|
||||
$notification['click_action'] = $message->getClickAction();
|
||||
|
||||
$chunked_token = array_chunk($tokens, 1000);
|
||||
foreach($chunked_token as $token_unit)
|
||||
{
|
||||
$data = json_encode(array(
|
||||
'registration_ids' => $token_unit,
|
||||
'notification' => $notification,
|
||||
'priority' => 'normal',
|
||||
'data' => $message->getData() ?: new \stdClass,
|
||||
));
|
||||
|
||||
$response = \FileHandler::getRemoteResource($url, $data, 5, 'POST', 'application/json', $headers);
|
||||
if($response)
|
||||
{
|
||||
$decoded_response = json_decode($response);
|
||||
if(!$decoded_response)
|
||||
{
|
||||
$message->addError('FCM return invalid json : '. $response);
|
||||
return $output;
|
||||
}
|
||||
$results = $decoded_response->results ?: [];
|
||||
foreach($results as $i => $result)
|
||||
{
|
||||
if($result->error)
|
||||
{
|
||||
$message->addError('FCM error code: '. $result->error);
|
||||
$output->invalid[$token_unit[$i]] = $token_unit[$i];
|
||||
}
|
||||
else if($result->message_id && $result->registration_id)
|
||||
{
|
||||
$output->needUpdate[$token_unit[$i]] = $result->registration_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
$output->success[$token_unit[$i]] = $result->message_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$message->addError('FCM return empty response.');
|
||||
}
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
58
common/framework/drivers/pushinterface.php
Normal file
58
common/framework/drivers/pushinterface.php
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework\Drivers;
|
||||
|
||||
/**
|
||||
* The Push driver interface.
|
||||
*/
|
||||
interface PushInterface
|
||||
{
|
||||
/**
|
||||
* Create a new instance of the current Push driver, using the given settings.
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
public static function getInstance(array $config): object;
|
||||
|
||||
/**
|
||||
* Get the human-readable name of this Push driver.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getName(): string;
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields required by this Push driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getRequiredConfig(): array;
|
||||
|
||||
/**
|
||||
* Get the list of configuration fields optionally used by this Push driver.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getOptionalConfig(): array;
|
||||
|
||||
/**
|
||||
* 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(): bool;
|
||||
|
||||
/**
|
||||
* Send a message.
|
||||
*
|
||||
* This method returns true on success and false on failure.
|
||||
*
|
||||
* @param object $message
|
||||
* @param array $tokens
|
||||
* @return object
|
||||
*/
|
||||
public function send(\Rhymix\Framework\Push $message, array $tokens);
|
||||
}
|
||||
441
common/framework/push.php
Normal file
441
common/framework/push.php
Normal file
|
|
@ -0,0 +1,441 @@
|
|||
<?php
|
||||
|
||||
namespace Rhymix\Framework;
|
||||
|
||||
/**
|
||||
* The Push class.
|
||||
*/
|
||||
class Push
|
||||
{
|
||||
/**
|
||||
* Instance properties.
|
||||
*/
|
||||
protected $from = 0;
|
||||
protected $to = array();
|
||||
protected $subject = '';
|
||||
protected $content = '';
|
||||
protected $click_action = '';
|
||||
protected $data = [];
|
||||
protected $errors = array();
|
||||
protected $sent = false;
|
||||
|
||||
/**
|
||||
* Static properties.
|
||||
*/
|
||||
protected static $_drivers = array();
|
||||
|
||||
/**
|
||||
* Add a custom Push driver.
|
||||
*
|
||||
* @param string $name
|
||||
* @param object $driver
|
||||
* @return void
|
||||
*/
|
||||
public static function addDriver(string $name, Drivers\PushInterface $driver)
|
||||
{
|
||||
self::$_drivers[$name] = $driver;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default driver.
|
||||
*
|
||||
* @param string $name
|
||||
* @return object|null
|
||||
*/
|
||||
public static function getDriver(string $name)
|
||||
{
|
||||
if (isset(self::$_drivers[$name]))
|
||||
{
|
||||
return self::$_drivers[$name];
|
||||
}
|
||||
|
||||
$driver_class = '\Rhymix\Framework\Drivers\Push\\' . $name;
|
||||
if (class_exists($driver_class))
|
||||
{
|
||||
$driver_config = config('push.' . $name) ?: array();
|
||||
return self::$_drivers[$name] = $driver_class::getInstance($driver_config);
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of supported Push drivers.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getSupportedDrivers()
|
||||
{
|
||||
$result = array();
|
||||
foreach (Storage::readDirectory(__DIR__ . '/drivers/push', false) as $filename)
|
||||
{
|
||||
$driver_name = substr($filename, 0, -4);
|
||||
$class_name = '\Rhymix\Framework\Drivers\Push\\' . $driver_name;
|
||||
if ($class_name::isSupported())
|
||||
{
|
||||
$result[$driver_name] = array(
|
||||
'name' => $class_name::getName(),
|
||||
'required' => $class_name::getRequiredConfig(),
|
||||
'optional' => $class_name::getOptionalConfig(),
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach (self::$_drivers as $driver_name => $driver)
|
||||
{
|
||||
if ($driver->isSupported())
|
||||
{
|
||||
$result[$driver_name] = array(
|
||||
'name' => $driver->getName(),
|
||||
'required' => $driver->getRequiredConfig(),
|
||||
'optional' => $driver->getOptionalConfig(),
|
||||
);
|
||||
}
|
||||
}
|
||||
ksort($result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the sender's member_srl.
|
||||
*
|
||||
* @param int $member_srl
|
||||
* @return bool
|
||||
*/
|
||||
public function setFrom(int $member_srl): bool
|
||||
{
|
||||
$this->from = $member_srl;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the sender's phone number.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getFrom(): int
|
||||
{
|
||||
return intval($this->from);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a recipient.
|
||||
*
|
||||
* @param int $member_srl
|
||||
* @return bool
|
||||
*/
|
||||
public function addTo(int $member_srl): bool
|
||||
{
|
||||
$this->to[] = $member_srl;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of recipients without country codes.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getRecipients(): array
|
||||
{
|
||||
return $this->to;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subject.
|
||||
*
|
||||
* @param string $subject
|
||||
* @return bool
|
||||
*/
|
||||
public function setSubject(string $subject): bool
|
||||
{
|
||||
$this->subject = utf8_trim(utf8_clean($subject));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subject.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSubject(): string
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content.
|
||||
*
|
||||
* @param string $content
|
||||
* @return bool
|
||||
*/
|
||||
public function setContent(string $content): bool
|
||||
{
|
||||
$this->content = utf8_trim(utf8_clean($content));
|
||||
$this->content = strtr($this->content, array("\r\n" => "\n"));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the content.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set an click-action to associate with this push notification.
|
||||
*
|
||||
* @param string $click_action
|
||||
* @return bool
|
||||
*/
|
||||
public function setClickAction(string $click_action): bool
|
||||
{
|
||||
$this->click_action = utf8_trim(utf8_clean($click_action));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the click-action associated with this push notification.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getClickAction(): string
|
||||
{
|
||||
return $this->click_action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a data to associate with this push notification.
|
||||
*
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public function setData(array $data): bool
|
||||
{
|
||||
$this->data = $data;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data associated with this push notification.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getData(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a URL to associate with this push notification.
|
||||
*
|
||||
* @param string $url
|
||||
* @return bool
|
||||
*/
|
||||
public function setURL(string $url): bool
|
||||
{
|
||||
$this->data['url'] = $url;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL associated with this push notification.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getURL(): string
|
||||
{
|
||||
return $this->data['url'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function send(): bool
|
||||
{
|
||||
// Get caller information.
|
||||
$backtrace = debug_backtrace(0);
|
||||
if(count($backtrace) && isset($backtrace[0]['file']))
|
||||
{
|
||||
$this->caller = $backtrace[0]['file'] . ($backtrace[0]['line'] ? (' line ' . $backtrace[0]['line']) : '');
|
||||
}
|
||||
|
||||
$output = \ModuleHandler::triggerCall('push.send', 'before', $this);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
$this->errors[] = $output->getMessage();
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
$tokens = $this->_getDeviceTokens();
|
||||
// Android FCM
|
||||
if(count($tokens->android))
|
||||
{
|
||||
$fcm_driver = $this->getDriver('fcm');
|
||||
$output = $fcm_driver->send($this, $tokens->android);
|
||||
$this->sent = $output->invalid ? false : true;
|
||||
$this->_deleteInvalidTokens($output->invalid);
|
||||
$this->_updateDeviceTokens($output->needUpdate);
|
||||
}
|
||||
|
||||
// iOS APNs
|
||||
if(count($tokens->ios))
|
||||
{
|
||||
$apns_driver =$this->getDriver('apns');
|
||||
$output = $apns_driver->send($this, $tokens->ios);
|
||||
$this->sent = $output->invalid ? false : true;
|
||||
$this->_deleteInvalidTokens($output->invalid);
|
||||
$this->_updateDeviceTokens($output->needUpdate);
|
||||
}
|
||||
}
|
||||
catch(\Exception $e)
|
||||
{
|
||||
$this->errors[] = class_basename($e) . ': ' . $e->getMessage();
|
||||
$this->sent = false;
|
||||
}
|
||||
|
||||
$output = \ModuleHandler::triggerCall('push.send', 'after', $this);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
$this->errors[] = $output->getMessage();
|
||||
}
|
||||
|
||||
return $this->sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the device token
|
||||
*
|
||||
* @return object
|
||||
*
|
||||
*/
|
||||
protected function _getDeviceTokens()
|
||||
{
|
||||
$member_srl_list = $this->getRecipients();
|
||||
$result = new \stdClass;
|
||||
$result->android = [];
|
||||
$result->ios = [];
|
||||
|
||||
$args = new \stdClass;
|
||||
$args->member_srl = $member_srl_list;
|
||||
$args->device_type = [];
|
||||
$driver_types = config('push.types') ?: array();
|
||||
if(!count($driver_types))
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
if(isset($driver_types['fcm']))
|
||||
{
|
||||
$args->device_type[] = 'android';
|
||||
}
|
||||
if(isset($driver_types['apns']))
|
||||
{
|
||||
$args->device_type[] = 'ios';
|
||||
}
|
||||
|
||||
$output = executeQueryArray('member.getMemberDeviceTokensByMemberSrl', $args);
|
||||
if(!$output->toBool() || !$output->data)
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
|
||||
foreach($output->data as $row)
|
||||
{
|
||||
$result->{$row->device_type}[] = $row->device_token;
|
||||
}
|
||||
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the device toekn
|
||||
*
|
||||
* @param array
|
||||
* @return void
|
||||
*/
|
||||
protected function _deleteInvalidTokens(array $invalid_tokens)
|
||||
{
|
||||
if(!count($invalid_tokens))
|
||||
{
|
||||
return;
|
||||
}
|
||||
$args = new \stdClass;
|
||||
$args->device_token = $invalid_tokens;
|
||||
executeQueryArray('member.deleteMemberDevice', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the device toekn
|
||||
*
|
||||
* @param array
|
||||
* @return void
|
||||
*/
|
||||
protected function _updateDeviceTokens(array $update_tokens)
|
||||
{
|
||||
$args = new \stdClass;
|
||||
foreach($update_tokens as $key => $value)
|
||||
{
|
||||
$args->old_token = $key;
|
||||
$args->new_token = $value;
|
||||
executeQueryArray('member.updateMemberDevice', $args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the message was sent.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isSent(): bool
|
||||
{
|
||||
return $this->sent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get caller information.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getCaller(): string
|
||||
{
|
||||
return $this->caller;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get errors.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an error message.
|
||||
*
|
||||
* @param string $message
|
||||
* @return void
|
||||
*/
|
||||
public function addError(string $message)
|
||||
{
|
||||
$this->errors[] = $message;
|
||||
}
|
||||
}
|
||||
|
|
@ -115,6 +115,7 @@ $lang->tag = 'Tag';
|
|||
$lang->mail = 'Mail';
|
||||
$lang->email = 'E-mail';
|
||||
$lang->sms = 'SMS';
|
||||
$lang->push_notification = 'Push Notification';
|
||||
$lang->allow_comment = 'Allow Comments';
|
||||
$lang->lock_comment = 'Block Comments';
|
||||
$lang->allow_trackback = 'Allow Trackbacks';
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ $lang->tag = '태그';
|
|||
$lang->mail = '메일';
|
||||
$lang->email = '이메일';
|
||||
$lang->sms = 'SMS';
|
||||
$lang->push_notification = '푸시 알림';
|
||||
$lang->allow_comment = '댓글 허용';
|
||||
$lang->lock_comment = '댓글 잠금';
|
||||
$lang->allow_trackback = '엮인글 허용';
|
||||
|
|
|
|||
|
|
@ -569,7 +569,7 @@ class adminAdminController extends admin
|
|||
$conf_value = $vars->{'sms_' . $sms_driver . '_' . $conf_name} ?: null;
|
||||
if (!$conf_value)
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_advanced_mailer_smtp_host_is_invalid');
|
||||
throw new Rhymix\Framework\Exception('msg_advanced_mailer_sms_config_invalid');
|
||||
}
|
||||
$sms_driver_config[$conf_name] = $conf_value;
|
||||
}
|
||||
|
|
@ -579,6 +579,61 @@ class adminAdminController extends admin
|
|||
$sms_driver_config[$conf_name] = $conf_value;
|
||||
}
|
||||
|
||||
// Validate the selected Push drivers.
|
||||
$push_config = array('types' => array());
|
||||
$push_drivers = Rhymix\Framework\Push::getSupportedDrivers();
|
||||
$push_driver_list = $vars->push_driver ?: [];
|
||||
foreach ($push_driver_list as $driver_name)
|
||||
{
|
||||
if (array_key_exists($driver_name, $push_drivers))
|
||||
{
|
||||
$push_config['types'][$driver_name] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_advanced_mailer_sending_method_is_invalid');
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the Push driver settings.
|
||||
foreach ($push_drivers as $driver_name => $driver_definition)
|
||||
{
|
||||
foreach ($push_drivers[$driver_name]['required'] as $conf_name)
|
||||
{
|
||||
$conf_value = utf8_trim($vars->{'push_' . $driver_name . '_' . $conf_name}) ?: null;
|
||||
if (!$conf_value && in_array($driver_name, $push_driver_list))
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_advanced_mailer_push_config_invalid');
|
||||
}
|
||||
$push_config[$driver_name][$conf_name] = $conf_value;
|
||||
|
||||
// Save certificates in a separate file and only store the filename in config.php.
|
||||
if ($conf_name === 'certificate')
|
||||
{
|
||||
$filename = Rhymix\Framework\Config::get('push.' . $driver_name . '.certificate');
|
||||
if (!$filename)
|
||||
{
|
||||
$filename = './files/config/' . $driver_name . '/cert-' . Rhymix\Framework\Security::getRandom(32) . '.pem';
|
||||
}
|
||||
|
||||
if ($conf_value !== null)
|
||||
{
|
||||
Rhymix\Framework\Storage::write($filename, $conf_value);
|
||||
$push_config[$driver_name][$conf_name] = $filename;
|
||||
}
|
||||
elseif (Rhymix\Framework\Storage::exists($filename))
|
||||
{
|
||||
Rhymix\Framework\Storage::delete($filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach ($push_drivers[$driver_name]['optional'] as $conf_name)
|
||||
{
|
||||
$conf_value = utf8_trim($vars->{'push_' . $driver_name . '_' . $conf_name}) ?: null;
|
||||
$push_config[$driver_name][$conf_name] = $conf_value;
|
||||
}
|
||||
}
|
||||
|
||||
// Save advanced mailer config.
|
||||
getController('module')->updateModuleConfig('advanced_mailer', (object)array(
|
||||
'sender_name' => trim($vars->mail_default_name),
|
||||
|
|
@ -606,6 +661,7 @@ class adminAdminController extends admin
|
|||
Rhymix\Framework\Config::set("sms.$sms_driver", $sms_driver_config);
|
||||
Rhymix\Framework\Config::set("sms.allow_split.sms", toBool($vars->allow_split_sms));
|
||||
Rhymix\Framework\Config::set("sms.allow_split.lms", toBool($vars->allow_split_lms));
|
||||
Rhymix\Framework\Config::set("push", $push_config);
|
||||
if (!Rhymix\Framework\Config::save())
|
||||
{
|
||||
throw new Rhymix\Framework\Exception('msg_failed_to_save_config');
|
||||
|
|
|
|||
|
|
@ -443,6 +443,18 @@ class adminAdminView extends admin
|
|||
Context::set('sms_drivers', $sms_drivers);
|
||||
Context::set('sms_driver', config('sms.type') ?: 'dummy');
|
||||
|
||||
// Load Push drivers.
|
||||
$push_drivers = Rhymix\Framework\Push::getSupportedDrivers();
|
||||
uasort($push_drivers, function($a, $b) { return strcmp($a['name'], $b['name']); });
|
||||
Context::set('push_drivers', $push_drivers);
|
||||
Context::set('push_config', config('push') ?: []);
|
||||
$apns_certificate = false;
|
||||
if ($apns_certificate_filename = config('push.apns.certificate'))
|
||||
{
|
||||
$apns_certificate = Rhymix\Framework\Storage::read($apns_certificate_filename);
|
||||
}
|
||||
Context::set('apns_certificate', $apns_certificate);
|
||||
|
||||
// Workaround for compatibility with older version of Amazon SES driver.
|
||||
config('mail.ses.api_key', config('mail.ses.api_user'));
|
||||
config('mail.ses.api_secret', config('mail.ses.api_pass'));
|
||||
|
|
|
|||
|
|
@ -337,6 +337,60 @@
|
|||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="section">
|
||||
|
||||
<h2>{$lang->push_notification}</h2>
|
||||
|
||||
<div class="x_control-group">
|
||||
<label class="x_control-label">{$lang->cmd_admin_sending_method}</label>
|
||||
<div class="x_controls">
|
||||
<!--@foreach($push_drivers as $driver_name => $driver_definition)-->
|
||||
<label for="push_driver_{$driver_name}" class="x_inline"><input type="checkbox" name="push_driver[]" id="push_driver_{$driver_name}" value="{$driver_name}" checked="checked"|cond="isset($push_config['types'][$driver_name])" /> {$driver_definition['name']}</label>
|
||||
<!--@end-->
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!--@foreach($push_drivers as $driver_name => $driver_definition)-->
|
||||
|
||||
{@ $conf_names = array_merge($driver_definition['required'], $driver_definition['optional'])}
|
||||
|
||||
<!--@foreach($conf_names as $conf_name)-->
|
||||
|
||||
{@ $conf_value = escape(config("push.$driver_name.$conf_name"))}
|
||||
|
||||
<!--@if($conf_name === 'api_key')-->
|
||||
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
|
||||
<label class="x_control-label" for="push_{$driver_name}_api_key">{$lang->cmd_advanced_mailer_fcm_api_key}</label>
|
||||
<div class="x_controls">
|
||||
<input type="password" name="push_{$driver_name}_api_key" id="push_{$driver_name}_api_key" value="{$conf_value|escape}" />
|
||||
</div>
|
||||
</div>
|
||||
<!--@end-->
|
||||
|
||||
<!--@if($conf_name === 'certificate')-->
|
||||
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
|
||||
<label class="x_control-label" for="push_{$driver_name}_certificate">{$lang->cmd_advanced_mailer_apns_certificate}</label>
|
||||
<div class="x_controls full-width">
|
||||
<textarea name="push_{$driver_name}_certificate" id="push_{$driver_name}_certificate">{$apns_certificate|escape}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<!--@end-->
|
||||
|
||||
<!--@if($conf_name === 'passphrase')-->
|
||||
<div class="x_control-group hidden-by-default show-for-{$driver_name}">
|
||||
<label class="x_control-label" for="push_{$driver_name}_passphrase">{$lang->cmd_advanced_mailer_apns_passphrase}</label>
|
||||
<div class="x_controls">
|
||||
<input type="password" name="push_{$driver_name}_passphrase" id="push_{$driver_name}_passphrase" value="{$conf_value|escape}" />
|
||||
</div>
|
||||
</div>
|
||||
<!--@end-->
|
||||
|
||||
<!--@end-->
|
||||
|
||||
<!--@end-->
|
||||
|
||||
</section>
|
||||
|
||||
<div class="x_clearfix btnArea">
|
||||
<div class="x_pull-right">
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ $lang->cmd_advanced_mailer_api_type_free = 'Free account';
|
|||
$lang->cmd_advanced_mailer_api_type_paid = 'Paid account';
|
||||
$lang->cmd_advanced_mailer_api_user = 'Username';
|
||||
$lang->cmd_advanced_mailer_api_pass = 'Password';
|
||||
$lang->cmd_advanced_mailer_fcm_api_key = 'FCM API key';
|
||||
$lang->cmd_advanced_mailer_apns_certificate = 'APNs certificate file';
|
||||
$lang->cmd_advanced_mailer_apns_passphrase = 'APNs certificate passphrase';
|
||||
$lang->cmd_advanced_mailer_sender_key = 'Sender key';
|
||||
$lang->cmd_advanced_mailer_sender_identity = 'Sender Identity';
|
||||
$lang->cmd_advanced_mailer_about_sender_identity = 'You can change the sender\'s name and e-mail address in the <a href="index.php?module=admin&act=dispAdminConfigNotification" target="_blank">Notification Settings</a> screen.';
|
||||
|
|
@ -103,6 +106,8 @@ $lang->msg_advanced_mailer_recipient_email_is_invalid = 'The recipient\'s email
|
|||
$lang->msg_advanced_mailer_test_success = 'The test was successful. Please check your email.';
|
||||
$lang->msg_advanced_mailer_google_account_security = 'Either your login credentials are incorrect, or the SMTP connection was blocked by Google account security settings.<br />Please <a href="https://support.google.com/mail/answer/14257" target="_blank">see here</a> for more information.';
|
||||
$lang->msg_advanced_mailer_naver_smtp_disabled = 'Either your login credentials are incorrect, or POP3/SMTP is not enabled on your Naver account.';
|
||||
$lang->msg_advanced_mailer_sms_config_invalid = 'There are errors or omissions in the SMS API configuration.';
|
||||
$lang->msg_advanced_mailer_push_config_invalid = 'There are errors or omissions in the push notification configuration.';
|
||||
$lang->msg_advanced_mailer_unknown_error = 'An unknown error occurred.';
|
||||
$lang->msg_advanced_mailer_log_is_empty = 'There are no entries to display.';
|
||||
$lang->cmd_advanced_mailer_status_sender = 'Sender';
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ $lang->cmd_advanced_mailer_api_type_free = '무료';
|
|||
$lang->cmd_advanced_mailer_api_type_paid = '유료';
|
||||
$lang->cmd_advanced_mailer_api_user = '아이디';
|
||||
$lang->cmd_advanced_mailer_api_pass = '비밀번호';
|
||||
$lang->cmd_advanced_mailer_fcm_api_key = 'FCM API 키';
|
||||
$lang->cmd_advanced_mailer_apns_certificate = 'APNs 인증서 파일';
|
||||
$lang->cmd_advanced_mailer_apns_passphrase = 'APNs 인증서 암호';
|
||||
$lang->cmd_advanced_mailer_sender_key = '센더 키';
|
||||
$lang->cmd_advanced_mailer_sender_identity = '보낸이 설정';
|
||||
$lang->cmd_advanced_mailer_about_sender_identity = '보낸이의 이름과 메일 주소는 <a href="index.php?module=admin&act=dispAdminConfigNotification" target="_blank">알림 설정</a> 화면에서 변경할 수 있습니다.';
|
||||
|
|
@ -103,6 +106,8 @@ $lang->msg_advanced_mailer_recipient_email_is_invalid = '받는이 메일 주소
|
|||
$lang->msg_advanced_mailer_test_success = '테스트에 성공하였습니다. 메일을 확인해 보시기 바랍니다.';
|
||||
$lang->msg_advanced_mailer_google_account_security = '아이디 또는 비밀번호가 틀렸거나, 구글 보안 설정 때문에 SMTP 접속이 차단되었습니다.<br />자세한 정보는 <a href="https://support.google.com/mail/answer/14257?hl=ko" target="_blank">여기</a>를 참고하시기 바랍니다.';
|
||||
$lang->msg_advanced_mailer_naver_smtp_disabled = '아이디 또는 비밀번호가 틀렸거나, 네이버 계정 환경설정에서 POP3/SMTP를 사용하지 않도록 설정되어 있습니다.';
|
||||
$lang->msg_advanced_mailer_sms_config_invalid = 'SMS API 설정에 잘못되었거나 누락된 부분이 있습니다. 확인해 주십시오.';
|
||||
$lang->msg_advanced_mailer_push_config_invalid = '푸시 알림 설정에 잘못되었거나 누락된 부분이 있습니다. 확인해 주십시오.';
|
||||
$lang->msg_advanced_mailer_unknown_error = '알 수 없는 오류가 발생하였습니다.';
|
||||
$lang->msg_advanced_mailer_log_is_empty = '표시할 항목이 없습니다.';
|
||||
$lang->cmd_advanced_mailer_status_sender = '보낸이';
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@
|
|||
<action name="procMemberInsert" type="controller" ruleset="@insertMember" use-ssl="true" route="signup" />
|
||||
<action name="procMemberCheckValue" type="controller" />
|
||||
<action name="procMemberLogin" type="controller" ruleset="@login" use-ssl="true" route="login" />
|
||||
<action name="procMemberRegisterDevice" type="controller" route="device/register" />
|
||||
<action name="procMemberLoginWithDevice" type="controller" route="device/login" />
|
||||
<action name="procMemberFindAccount" type="controller" method="GET|POST" ruleset="findAccount" use-ssl="true" />
|
||||
<action name="procMemberFindAccountByQuestion" type="controller" method="GET|POST" use-ssl="true" />
|
||||
<action name="procMemberAuthAccount" type="controller" method="GET|POST" use-ssl="true" />
|
||||
|
|
|
|||
|
|
@ -80,6 +80,138 @@ class memberController extends member
|
|||
return $this->setRedirectUrl($returnUrl, $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register device
|
||||
*/
|
||||
function procMemberRegisterDevice()
|
||||
{
|
||||
Context::setResponseMethod('JSON');
|
||||
|
||||
// Check user_id, password, device_token
|
||||
$user_id = Context::get('user_id');
|
||||
$password = Context::get('password');
|
||||
$device_token = Context::get('device_token');
|
||||
$device_model = escape(Context::get('device_model'));
|
||||
|
||||
// Return an error when id and password doesn't exist
|
||||
if(!$user_id) return new BaseObject(-1, 'NULL_USER_ID');
|
||||
if(!$password) return new BaseObject(-1, 'NULL_PASSWORD');
|
||||
if(!$device_token) return new BaseObject(-1, 'NULL_DEVICE_TOKEN');
|
||||
|
||||
$browserInfo = Rhymix\Framework\UA::getBrowserInfo();
|
||||
$device_type = strtolower($browserInfo->os);
|
||||
|
||||
if('ios' === $device_type)
|
||||
{
|
||||
if(!preg_match("/^[0-9a-z]{64}$/", $device_token))
|
||||
{
|
||||
return new BaseObject(-1, 'INVALID_DEVICE_TOKEN');
|
||||
}
|
||||
}
|
||||
else if('android' === $device_type)
|
||||
{
|
||||
if(!preg_match("/^[0-9a-zA-Z:_-]+$/", $device_token))
|
||||
{
|
||||
return new BaseObject(-1, 'INVALID_DEVICE_TOKEN');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return new BaseObject(-1, 'NOT_SUPPORTED_OS');
|
||||
}
|
||||
|
||||
$device_version = $browserInfo->version;
|
||||
|
||||
$output = $this->procMemberLogin($user_id, $password);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
return new BaseObject(-1, 'LOGIN_FAILED');
|
||||
}
|
||||
$logged_info = Context::get('logged_info');
|
||||
|
||||
$random_key = Rhymix\Framework\Security::getRandom();
|
||||
$device_key = hash_hmac('sha256', $random_key, $logged_info->member_srl . ':' . config('crypto.authentication_key'));
|
||||
|
||||
// Start transaction
|
||||
$oDB = DB::getInstance();
|
||||
$oDB->begin();
|
||||
|
||||
// Remove duplicated token key
|
||||
$args = new stdClass;
|
||||
$args->device_token = $device_token;
|
||||
executeQuery('member.deleteMemberDevice', $args);
|
||||
|
||||
// Create member_device
|
||||
$args = new stdClass;
|
||||
$args->device_srl = getNextSequence();
|
||||
$args->member_srl = $logged_info->member_srl;
|
||||
$args->device_token = $device_token;
|
||||
$args->device_key = $device_key;
|
||||
$args->device_type = $device_type;
|
||||
$args->device_version = $device_version;
|
||||
$args->device_model = $device_model;
|
||||
$output3 = executeQuery('member.insertMemberDevice', $args);
|
||||
if(!$output3->toBool())
|
||||
{
|
||||
$oDB->rollback();
|
||||
return $output3;
|
||||
}
|
||||
|
||||
$oDB->commit();
|
||||
|
||||
// Set parameters
|
||||
$this->add('member_srl', $logged_info->member_srl);
|
||||
$this->add('user_id', $logged_info->user_id);
|
||||
$this->add('user_name', $logged_info->user_name);
|
||||
$this->add('nick_name', $logged_info->nick_name);
|
||||
$this->add('device_key', $random_key);
|
||||
}
|
||||
|
||||
/**
|
||||
* Automatically log-in to registered device
|
||||
*/
|
||||
function procMemberLoginWithDevice()
|
||||
{
|
||||
Context::setResponseMethod('JSON');
|
||||
// Check member_srl, device_token, device_key
|
||||
$member_srl = Context::get('member_srl');
|
||||
$device_token = Context::get('device_token');
|
||||
$random_key = Context::get('device_key');
|
||||
|
||||
// Return an error when id, password and device_key doesn't exist
|
||||
if(!$member_srl) return new BaseObject(-1, 'NULL_MEMBER_SRL');
|
||||
if(!$device_token) return new BaseObject(-1, 'NULL_DEVICE_TOKEN');
|
||||
if(!$random_key) return new BaseObject(-1, 'NULL_DEVICE_KEY');
|
||||
|
||||
$args = new stdClass;
|
||||
$args->member_srl = $member_srl;
|
||||
$args->device_token = $device_token;
|
||||
$args->device_key = hash_hmac('sha256', $random_key, $member_srl . ':' . config('crypto.authentication_key'));
|
||||
$output = executeQueryArray('member.getMemberDevice', $args);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
return new BaseObject(-1, 'DEVICE_RETRIEVE_FAILED');
|
||||
}
|
||||
|
||||
if(!$output->data)
|
||||
{
|
||||
return new BaseObject(-1, 'UNREGISTERED_DEVICE');
|
||||
}
|
||||
|
||||
// Log-in
|
||||
$member_info = MemberModel::getMemberInfoByMemberSrl($member_srl);
|
||||
$output = $this->doLogin($member_info->user_id);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
return new BaseObject(-1, 'LOGIN_FAILED');
|
||||
}
|
||||
|
||||
$this->add('member_srl', $member_info->member_srl);
|
||||
$this->add('user_id', $member_info->user_id);
|
||||
$this->add('user_name', $member_info->user_name);
|
||||
$this->add('nick_name', $member_info->nick_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Log-out
|
||||
*
|
||||
|
|
|
|||
10
modules/member/queries/deleteMemberDevice.xml
Normal file
10
modules/member/queries/deleteMemberDevice.xml
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
<query id="deleteMemberDevice" action="delete">
|
||||
<tables>
|
||||
<table name="member_devices" />
|
||||
</tables>
|
||||
<conditions>
|
||||
<condition operation="in" column="device_srl" var="device_srl" />
|
||||
<condition operation="in" column="member_srl" var="member_srl" pipe="and" />
|
||||
<condition operation="in" column="device_token" var="device_token" notnull="notnull" pipe="and" />
|
||||
</conditions>
|
||||
</query>
|
||||
13
modules/member/queries/getMemberDevice.xml
Normal file
13
modules/member/queries/getMemberDevice.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<query id="getMemberDevice" action="select">
|
||||
<tables>
|
||||
<table name="member_devices" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="*" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="member_srl" var="member_srl" notnull="notnull" />
|
||||
<condition operation="equal" column="device_token" var="device_token" notnull="notnull" pipe="and" />
|
||||
<condition operation="equal" column="device_key" var="device_key" notnull="notnull" pipe="and" />
|
||||
</conditions>
|
||||
</query>
|
||||
13
modules/member/queries/getMemberDeviceTokensByMemberSrl.xml
Normal file
13
modules/member/queries/getMemberDeviceTokensByMemberSrl.xml
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
<query id="getMemberDeviceTokensByMemberSrl" action="select">
|
||||
<tables>
|
||||
<table name="member_devices" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="device_token" />
|
||||
<column name="device_type" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="in" column="member_srl" var="member_srl" notnull="notnull" />
|
||||
<condition operation="in" column="device_type" var="device_type" notnull="notnull" pipe="and" />
|
||||
</conditions>
|
||||
</query>
|
||||
17
modules/member/queries/insertMemberDevice.xml
Normal file
17
modules/member/queries/insertMemberDevice.xml
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
<query id="insertMemberDevice" action="insert">
|
||||
<tables>
|
||||
<table name="member_devices" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="device_srl" var="device_srl" notnull="notnull" />
|
||||
<column name="member_srl" var="member_srl" notnull="notnull" />
|
||||
<column name="device_token" var="device_token" notnull="notnull" />
|
||||
<column name="device_key" var="device_key" notnull="notnull" />
|
||||
<column name="device_type" var="device_type" notnull="notnull" />
|
||||
<column name="device_version" var="device_version" notnull="notnull" />
|
||||
<column name="device_model" var="device_model" notnull="notnull" />
|
||||
<column name="device_description" var="device_description" />
|
||||
<column name="ipaddress" var="ipaddress" default="ipaddress()" />
|
||||
<column name="regdate" var="regdate" default="curdate()" />
|
||||
</columns>
|
||||
</query>
|
||||
11
modules/member/queries/updateMemberDevice.xml
Normal file
11
modules/member/queries/updateMemberDevice.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<query id="updateMemberDevice" action="update">
|
||||
<tables>
|
||||
<table name="member_devices" />
|
||||
</tables>
|
||||
<columns>
|
||||
<column name="device_token" var="new_token" notnull="notnull" />
|
||||
</columns>
|
||||
<conditions>
|
||||
<condition operation="equal" column="device_token" var="old_token" notnull="notnull" />
|
||||
</conditions>
|
||||
</query>
|
||||
12
modules/member/schemas/member_devices.xml
Normal file
12
modules/member/schemas/member_devices.xml
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
<table name="member_devices">
|
||||
<column name="device_srl" type="number" notnull="notnull" primary_key="primary_key" />
|
||||
<column name="member_srl" type="number" notnull="notnull" index="idx_member_srl" />
|
||||
<column name="device_token" type="varchar" size="191" notnull="notnull" unique="unique_device_token" />
|
||||
<column name="device_key" type="char" size="64" notnull="notnull" />
|
||||
<column name="device_type" type="varchar" size="20" notnull="notnull" index="idx_device_type" />
|
||||
<column name="device_version" type="varchar" size="20" notnull="notnull" />
|
||||
<column name="device_model" type="varchar" size="40" notnull="notnull" />
|
||||
<column name="device_description" type="varchar" size="200" />
|
||||
<column name="regdate" type="date" notnull="notnull" index="idx_regdate" />
|
||||
<column name="ipaddress" type="varchar" size="120" notnull="notnull" />
|
||||
</table>
|
||||
|
|
@ -157,7 +157,6 @@ $lang->mention_limit = '멘션 갯수 제한';
|
|||
$lang->about_mention_limit = '서버 과부하와 스팸을 방지하기 위해 한 글에서 지나치게 많은 회원들을 호출하지 못하도록 합니다.';
|
||||
$lang->ncenterlite_msg_setting_error = '설정에 오류가 있습니다. 다시 설정해 주세요.';
|
||||
$lang->ncenterlite_use_help = '회원들에게 전송할 알림을 선택할 수 있습니다. <br /> 모든 댓글 작성자에게 알림 기능은 게시글의 작성자가 댓글을 남길경우 게시글을 작성한 작성자를 제외하고 해당 글의 <strong>모든 댓글 작성자</strong>들에게 알림을 전송합니다.';
|
||||
$lang->ncenterlite_dont_use_push = '푸시 알림은 현재 지원중이 아닙니다.';
|
||||
$lang->member_phone_variable = '회원 전화번호 변수';
|
||||
$lang->member_phone_variable_about = '문자 알림 사용시 회원의 전화번호를 어디에서 불러올지 선택합니다. 회원정보의 전화번호 또는 확장변수를 선택할 수 있습니다.<br />전화번호 형태의 확장변수가 1개뿐인 경우 설치시 자동으로 설정이 저장됩니다.';
|
||||
$lang->member_phone_builtin_field = '회원정보의 전화정보';
|
||||
|
|
|
|||
|
|
@ -19,9 +19,16 @@ class ncenterliteAdminView extends ncenterlite
|
|||
{
|
||||
$sms_available = true;
|
||||
}
|
||||
|
||||
$push_avaliable = false;
|
||||
|
||||
|
||||
if(count(Rhymix\Framework\Config::get('push.types')))
|
||||
{
|
||||
$push_avaliable = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$push_avaliable = false;
|
||||
}
|
||||
|
||||
$config = $oNcenterliteModel->getConfig();
|
||||
Context::set('config', $config);
|
||||
Context::set('sms_available', $sms_available);
|
||||
|
|
|
|||
|
|
@ -7,12 +7,12 @@ class ncenterliteController extends ncenterlite
|
|||
*
|
||||
* @param int $from_member_srl Sender
|
||||
* @param int $to_member_srl Recipient
|
||||
* @param string $message Message content
|
||||
* @param string|object $message Message content
|
||||
* @param string $url The URL to redirect to when the recipient clicks the notification
|
||||
* @param int $target_srl The sequence number associated with this notification
|
||||
* @return BaseObject
|
||||
*/
|
||||
public function sendNotification($from_member_srl, $to_member_srl, $message, $url, $target_srl = 0)
|
||||
public function sendNotification($from_member_srl, $to_member_srl, $message, $url = '', $target_srl = 0)
|
||||
{
|
||||
$args = new stdClass();
|
||||
$args->config_type = 'custom';
|
||||
|
|
@ -27,7 +27,19 @@ class ncenterliteController extends ncenterlite
|
|||
$args->target_url = $url;
|
||||
$args->target_browser = '';
|
||||
$args->target_summary = '';
|
||||
$args->target_body = $message;
|
||||
|
||||
if (is_object($message))
|
||||
{
|
||||
$args->target_body = $message->subject;
|
||||
$args->target_url = $message->url ?: $args->target_url;
|
||||
$args->extra_content = $message->content;
|
||||
$args->extra_data = $message->data ?: [];
|
||||
}
|
||||
else
|
||||
{
|
||||
$args->target_body = $message;
|
||||
}
|
||||
|
||||
$output = $this->_insertNotify($args);
|
||||
if(!$output->toBool())
|
||||
{
|
||||
|
|
@ -1337,6 +1349,7 @@ class ncenterliteController extends ncenterlite
|
|||
if($output->toBool())
|
||||
{
|
||||
ModuleHandler::triggerCall('ncenterlite._insertNotify', 'after', $args);
|
||||
$this->sendPushMessage($args);
|
||||
$this->sendSmsMessage($args);
|
||||
$this->sendMailMessage($args);
|
||||
$this->removeFlagFile($args->member_srl);
|
||||
|
|
@ -1473,6 +1486,39 @@ class ncenterliteController extends ncenterlite
|
|||
return array_values($members);
|
||||
}
|
||||
|
||||
function sendPushMessage($args)
|
||||
{
|
||||
$oNcenterliteModel = getModel('ncenterlite');
|
||||
|
||||
$config = $oNcenterliteModel->getConfig();
|
||||
if(!isset($config->use[$args->config_type]['push']))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if($this->user->member_srl == $args->member_srl && $args->target_type != $this->_TYPE_CUSTOM)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $oNcenterliteModel->getNotificationText($args);
|
||||
$content = htmlspecialchars_decode(preg_replace('/<\/?(strong|)[^>]*>/', '', $content));
|
||||
|
||||
$target_url = $args->target_url;
|
||||
if (!preg_match('!^https?://!', $target_url))
|
||||
{
|
||||
$target_url = Rhymix\Framework\URL::getCurrentDomainUrl($target_url);
|
||||
}
|
||||
|
||||
$oPush = new \Rhymix\Framework\Push();
|
||||
$oPush->setSubject($content);
|
||||
$oPush->setContent(strval($args->extra_content));
|
||||
$oPush->setData($args->extra_data ?: []);
|
||||
$oPush->setURL(strval($target_url));
|
||||
$oPush->addTo(intval($args->member_srl));
|
||||
$oPush->send();
|
||||
}
|
||||
|
||||
function sendSmsMessage($args)
|
||||
{
|
||||
$oNcenterliteModel = getModel('ncenterlite');
|
||||
|
|
@ -1483,13 +1529,13 @@ class ncenterliteController extends ncenterlite
|
|||
return false;
|
||||
}
|
||||
|
||||
if($this->user->member_srl == $args->member_srl)
|
||||
if($this->user->member_srl == $args->member_srl && $args->target_type != $this->_TYPE_CUSTOM)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $oNcenterliteModel->getNotificationText($args);
|
||||
$content = preg_replace('/<\/?(strong|)[^>]*>/', '', $content);
|
||||
$content = htmlspecialchars_decode(preg_replace('/<\/?(strong|)[^>]*>/', '', $content));
|
||||
|
||||
$sms = $this->getSmsHandler();
|
||||
if($sms === false)
|
||||
|
|
@ -1544,11 +1590,11 @@ class ncenterliteController extends ncenterlite
|
|||
return false;
|
||||
}
|
||||
|
||||
$logged_info = Context::get('logged_info');
|
||||
if($logged_info->member_srl == $args->member_srl)
|
||||
if($this->user->member_srl == $args->member_srl && $args->target_type != $this->_TYPE_CUSTOM)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
$content = $oNcenterliteModel->getNotificationText($args);
|
||||
|
||||
switch ($args->config_type)
|
||||
|
|
|
|||
|
|
@ -66,7 +66,6 @@
|
|||
<label for="custom_push" class="x_inline" disabled="disabled"|cond="!$push_available"><input type="checkbox" name="use[custom][push]" id="custom_push" value="1" disabled="disabled"|cond="!$push_available" checked="checked"|cond="isset($config->use['custom']['push'])" /> {$lang->cmd_push_notify}</label>
|
||||
<p>
|
||||
<div>{$lang->ncenterlite_use_help}</div>
|
||||
<div><span class="x_label x_label-important">{$lang->ncenterlite_warning}</span> {$lang->ncenterlite_dont_use_push}</div>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue