api
This commit is contained in:
parent
0516411193
commit
8af3e1d541
|
|
@ -1,41 +1,6 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
return [
|
return [
|
||||||
|
/*
|
||||||
'throttle' => [
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Enable throttling of Backend authentication attempts
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| If set to true, users will be given a limited number of attempts to sign
|
|
||||||
| in to the Backend before being blocked for a specified number of minutes.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
'enabled' => true,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Failed Authentication Attempt Limit
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| Number of failed attempts allowed while trying to authenticate a user.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
'attemptLimit' => 5,
|
|
||||||
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
| Suspension Time
|
|
||||||
|--------------------------------------------------------------------------
|
|
||||||
|
|
|
||||||
| The number of minutes to suspend further attempts on authentication once
|
|
||||||
| the attempt limit is reached.
|
|
||||||
|
|
|
||||||
*/
|
|
||||||
'suspensionTime' => 15,
|
|
||||||
],
|
|
||||||
/*
|
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Authentication Defaults
|
| Authentication Defaults
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
|
||||||
|
'throttle' => [
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Enable throttling of Backend authentication attempts
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| If set to true, users will be given a limited number of attempts to sign
|
||||||
|
| in to the Backend before being blocked for a specified number of minutes.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'enabled' => true,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Failed Authentication Attempt Limit
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Number of failed attempts allowed while trying to authenticate a user.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'attemptLimit' => 5,
|
||||||
|
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Suspension Time
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| The number of minutes to suspend further attempts on authentication once
|
||||||
|
| the attempt limit is reached.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'suspensionTime' => 15,
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Defaults
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| This option controls the default authentication "guard" and password
|
||||||
|
| reset options for your application. You may change these defaults
|
||||||
|
| as required, but they're a perfect start for most applications.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'defaults' => [
|
||||||
|
'guard' => env('AUTH_DEFAULT_GUARD', 'web'),
|
||||||
|
'passwords' => env('AUTH_DEFAULT_PASSWORDS', 'users'),
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Authentication Guards
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Next, you may define every authentication guard for your application.
|
||||||
|
| Of course, a great default configuration has been defined for you
|
||||||
|
| here which uses session storage and the Eloquent user provider.
|
||||||
|
|
|
||||||
|
| All authentication drivers have a user provider. This defines how the
|
||||||
|
| users are actually retrieved out of your database or other storage
|
||||||
|
| mechanisms used by this application to persist your user's data.
|
||||||
|
|
|
||||||
|
| Supported: "session", "token"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'guards' => [
|
||||||
|
'web' => [
|
||||||
|
'driver' => env('AUTH_GUARDS_WEB_DRIVER', 'session'),
|
||||||
|
'provider' => env('AUTH_GUARDS_WEB_PROVIDER', 'users'),
|
||||||
|
],
|
||||||
|
'api' => [
|
||||||
|
'driver' => env('AUTH_GUARDS_API_DRIVER', 'token'),
|
||||||
|
'provider' => env('AUTH_GUARDS_API_PROVIDER', 'users'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| User Providers
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| All authentication drivers have a user provider. This defines how the
|
||||||
|
| users are actually retrieved out of your database or other storage
|
||||||
|
| mechanisms used by this application to persist your user's data.
|
||||||
|
|
|
||||||
|
| If you have multiple user tables or models you may configure multiple
|
||||||
|
| sources which represent each model / table. These sources may then
|
||||||
|
| be assigned to any extra authentication guards you have defined.
|
||||||
|
|
|
||||||
|
| Supported: "database", "eloquent"
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'providers' => [
|
||||||
|
'users' => [
|
||||||
|
'driver' => env('AUTH_PROVIDERS_USERS_DRIVER', 'eloquent'),
|
||||||
|
'model' => env('AUTH_PROVIDERS_USERS_MODEL', '\RainLab\User\Models\User'),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
/*
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
| Resetting Passwords
|
||||||
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
| Here you may set the options for resetting passwords including the view
|
||||||
|
| that is your password reset e-mail. You may also set the name of the
|
||||||
|
| table that maintains all of the reset tokens for your application.
|
||||||
|
|
|
||||||
|
| You may specify multiple password reset configurations if you have more
|
||||||
|
| than one user table or model in the application and you want to have
|
||||||
|
| separate password reset settings based on the specific user types.
|
||||||
|
|
|
||||||
|
| The expire time is the number of minutes that the reset token should be
|
||||||
|
| considered valid. This security feature keeps tokens short-lived so
|
||||||
|
| they have less time to be guessed. You may change this as needed.
|
||||||
|
|
|
||||||
|
*/
|
||||||
|
'passwords' => [
|
||||||
|
'users' => [
|
||||||
|
'provider' => env('AUTH_PASSWORDS_USERS_PROVIDER', 'users'),
|
||||||
|
'email' => env('AUTH_PASSWORDS_USERS_EMAIL', 'auth.emails.password'),
|
||||||
|
'table' => env('AUTH_PASSWORDS_USERS_TABLE', 'password_resets'),
|
||||||
|
'expire' => env('AUTH_PASSWORDS_USERS_EXPIRE', 60),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
# MIT license
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
||||||
|
|
@ -1,69 +0,0 @@
|
||||||
<?php namespace RainLab\Notify;
|
|
||||||
|
|
||||||
use Backend;
|
|
||||||
|
|
||||||
use System\Classes\PluginBase;
|
|
||||||
use System\Classes\SettingsManager;
|
|
||||||
use TPS\Birzha\Events\MessageReceivedEvent;
|
|
||||||
use TPS\Birzha\Events\PaymentRecievedEvent;
|
|
||||||
use TPS\Birzha\Events\PaymentReviewedEvent;
|
|
||||||
use TPS\Birzha\Events\ProductRecievedEvent;
|
|
||||||
use TPS\Birzha\Events\ProductReviewedEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The plugin.php file (called the plugin initialization script) defines the plugin information class.
|
|
||||||
*/
|
|
||||||
class Plugin extends PluginBase
|
|
||||||
{
|
|
||||||
public function pluginDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'rainlab.notify::lang.plugin.name',
|
|
||||||
'description' => 'rainlab.notify::lang.plugin.description',
|
|
||||||
'author' => 'Alexey Bobkov, Samuel Georges',
|
|
||||||
'icon' => 'icon-bullhorn'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerSettings()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'notifications' => [
|
|
||||||
'label' => 'rainlab.notify::lang.notifications.menu_label',
|
|
||||||
'description' => 'rainlab.notify::lang.notifications.menu_description',
|
|
||||||
'category' => SettingsManager::CATEGORY_NOTIFICATIONS,
|
|
||||||
'icon' => 'icon-bullhorn',
|
|
||||||
'url' => Backend::url('rainlab/notify/notifications'),
|
|
||||||
'permissions' => ['rainlab.notify.manage_notifications'],
|
|
||||||
'order' => 600
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerNotificationRules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'groups' => [],
|
|
||||||
'events' => [
|
|
||||||
|
|
||||||
],
|
|
||||||
'actions' => [
|
|
||||||
\RainLab\Notify\NotifyRules\SaveDatabaseAction::class,
|
|
||||||
\RainLab\Notify\NotifyRules\SendMailTemplateAction::class,
|
|
||||||
],
|
|
||||||
'conditions' => [
|
|
||||||
\RainLab\Notify\NotifyRules\ExecutionContextCondition::class,
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerPermissions()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'rainlab.notify.manage_notifications' => [
|
|
||||||
'tab' => SettingsManager::CATEGORY_NOTIFICATIONS,
|
|
||||||
'label' => 'rainlab.notify::lang.permissions.manage_notifications'
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,400 +0,0 @@
|
||||||
# Notification engine
|
|
||||||
|
|
||||||
**Plugin is currently in Beta status. Proceed with caution.**
|
|
||||||
|
|
||||||
Adds support for sending notifications across a variety of different channels, including mail, SMS and Slack.
|
|
||||||
|
|
||||||
Notifications are managed in the back-end area by navigating to *Settings > Notification rules*.
|
|
||||||
|
|
||||||
## Notification workflow
|
|
||||||
|
|
||||||
When a notification fires, it uses the following workflow:
|
|
||||||
|
|
||||||
1. Plugin registers associated actions, conditions and events using `registerNotificationRules`
|
|
||||||
1. A notification class is bound to a system event using `Notifier::bindEvent`
|
|
||||||
1. A system event is fired `Event::fire`
|
|
||||||
1. The parameters of the event are captured, along with any global context parameters
|
|
||||||
1. A command is pushed on the queue to process the notification `Queue::push`
|
|
||||||
1. The command finds all notification rules using the notification class and triggers them
|
|
||||||
1. The notification conditions are checked and only proceed if met
|
|
||||||
1. The notification actions are triggered
|
|
||||||
|
|
||||||
Here is an example of a plugin registering notification rules. The `groups` definition will create containers that are used to better organise events. The `presets` definition specifies notification rules defined by the system.
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function registerNotificationRules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'events' => [
|
|
||||||
\RainLab\User\NotifyRules\UserActivatedEvent::class,
|
|
||||||
],
|
|
||||||
'actions' => [
|
|
||||||
\RainLab\User\NotifyRules\SaveToDatabaseAction::class,
|
|
||||||
],
|
|
||||||
'conditions' => [
|
|
||||||
\RainLab\User\NotifyRules\UserAttributeCondition::class
|
|
||||||
],
|
|
||||||
'groups' => [
|
|
||||||
'user' => [
|
|
||||||
'label' => 'User',
|
|
||||||
'icon' => 'icon-user'
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'presets' => '$/rainlab/user/config/notify_presets.yaml',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is an example of triggering a notification. The system event `rainlab.user.activate` is bound to the `UserActivatedEvent` class.
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Bind to a system event
|
|
||||||
\RainLab\Notify\Classes\Notifier::bindEvents([
|
|
||||||
'rainlab.user.activate' => \RainLab\User\NotifyRules\UserActivatedEvent::class
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Fire the system event
|
|
||||||
Event::fire('rainlab.user.activate', [$this]);
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is an example of registering context parameters, which are available globally to all notifications.
|
|
||||||
|
|
||||||
```php
|
|
||||||
\RainLab\Notify\Classes\Notifier::instance()->registerCallback(function($manager) {
|
|
||||||
$manager->registerGlobalParams([
|
|
||||||
'user' => Auth::getUser()
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
Here is an example of an event preset:
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# ===================================
|
|
||||||
# Event Presets
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
welcome_email:
|
|
||||||
name: Send welcome email to user
|
|
||||||
event: RainLab\User\NotifyRules\UserRegisteredEvent
|
|
||||||
items:
|
|
||||||
- action: RainLab\Notify\NotifyRules\SendMailTemplateAction
|
|
||||||
mail_template: rainlab.user::mail.welcome
|
|
||||||
send_to_mode: user
|
|
||||||
conditions:
|
|
||||||
- condition: RainLab\Notify\NotifyRules\ExecutionContextCondition
|
|
||||||
subcondition: environment
|
|
||||||
operator: is
|
|
||||||
value: dev
|
|
||||||
condition_text: Application environment <span class="operator">is</span> dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Creating Event classes
|
|
||||||
|
|
||||||
An event class is responsible for preparing the parameters passed to the conditions and actions. The static method `makeParamsFromEvent` will take the arguments provided by the system event and convert them in to parameters.
|
|
||||||
|
|
||||||
```php
|
|
||||||
class UserActivatedEvent extends \RainLab\Notify\Classes\EventBase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var array Local conditions supported by this event.
|
|
||||||
*/
|
|
||||||
public $conditions = [
|
|
||||||
\RainLab\User\NotifyRules\UserAttributeCondition::class
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns information about this event, including name and description.
|
|
||||||
*/
|
|
||||||
public function eventDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Activated',
|
|
||||||
'description' => 'A user is activated',
|
|
||||||
'group' => 'user'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the usable parameters provided by this class.
|
|
||||||
*/
|
|
||||||
public function defineParams()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => [
|
|
||||||
'title' => 'Name',
|
|
||||||
'label' => 'Name of the user',
|
|
||||||
],
|
|
||||||
// ...
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function makeParamsFromEvent(array $args, $eventName = null)
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'user' => array_get($args, 0)
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Creating Action classes
|
|
||||||
|
|
||||||
Action classes define the final step in a notification and subsequently perform the notification itself. Some examples might be sending and email or writing to the database.
|
|
||||||
|
|
||||||
```php
|
|
||||||
class SendMailTemplateAction extends \RainLab\Notify\Classes\ActionBase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns information about this event, including name and description.
|
|
||||||
*/
|
|
||||||
public function actionDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Compose a mail message',
|
|
||||||
'description' => 'Send a message to a recipient',
|
|
||||||
'icon' => 'icon-envelope'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Field configuration for the action.
|
|
||||||
*/
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
$template = $this->host->template_name;
|
|
||||||
|
|
||||||
return 'Send a message using '.$template;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers this action.
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function triggerAction($params)
|
|
||||||
{
|
|
||||||
$email = 'test@email.tld';
|
|
||||||
$template = $this->host->template_name;
|
|
||||||
|
|
||||||
Mail::sendTo($email, $template, $params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A form fields definition file is used to provide form fields when the action is established. These values are accessed from condition using the host model via the `$this->host` property.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
template_name:
|
|
||||||
label: Template name
|
|
||||||
type: text
|
|
||||||
```
|
|
||||||
|
|
||||||
An action may choose to provide no form fields by simply returning false from the `defineFormFields` method.
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Creating Condition classes
|
|
||||||
|
|
||||||
A condition class should specify how it should appear in the user interface, providing a name, title and summary text. It also must declare an `isTrue` method for evaluating whether the condition is true or not.
|
|
||||||
|
|
||||||
```php
|
|
||||||
class MyCondition extends \RainLab\Notify\Classes\ConditionBase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Return either ConditionBase::TYPE_ANY or ConditionBase::TYPE_LOCAL
|
|
||||||
*/
|
|
||||||
public function getConditionType()
|
|
||||||
{
|
|
||||||
// If the condition should appear for all events
|
|
||||||
return ConditionBase::TYPE_ANY;
|
|
||||||
|
|
||||||
// If the condition should appear only for some events
|
|
||||||
return ConditionBase::TYPE_LOCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Field configuration for the condition.
|
|
||||||
*/
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'My condition is checked';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return 'My condition';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
$value = $this->host->mycondition;
|
|
||||||
|
|
||||||
return 'My condition <span class="operator">is</span> '.$value;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the condition is TRUE for specified parameters
|
|
||||||
* @param array $params
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTrue(&$params)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
A form fields definition file is used to provide form fields when the condition is established. These values are accessed from condition using the host model via the `$this->host` property.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
mycondition:
|
|
||||||
label: My condition
|
|
||||||
type: dropdown
|
|
||||||
options:
|
|
||||||
true: True
|
|
||||||
false: False
|
|
||||||
```
|
|
||||||
|
|
||||||
## Model attribute condition classes
|
|
||||||
|
|
||||||
Model attribute conditions are designed specially for applying conditions to sets of model attributes.
|
|
||||||
|
|
||||||
```php
|
|
||||||
class UserAttributeCondition extends \RainLab\Notify\Classes\ModelAttributesConditionBase
|
|
||||||
{
|
|
||||||
protected $modelClass = \RainLab\User\Models\User::class;
|
|
||||||
|
|
||||||
public function getGroupingTitle()
|
|
||||||
{
|
|
||||||
return 'User attribute';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return 'User attribute';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the condition is TRUE for specified parameters
|
|
||||||
* @param array $params Specifies a list of parameters as an associative array.
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTrue(&$params)
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
|
|
||||||
$attribute = $hostObj->subcondition;
|
|
||||||
|
|
||||||
if (!$user = array_get($params, 'user')) {
|
|
||||||
throw new ApplicationException('Error evaluating the user attribute condition: the user object is not found in the condition parameters.');
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::evalIsTrue($user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
An attributes definition file is used to specify which attributes should be included in the condition.
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
# ===================================
|
|
||||||
# Condition Attribute Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
attributes:
|
|
||||||
|
|
||||||
name:
|
|
||||||
label: Name
|
|
||||||
|
|
||||||
email:
|
|
||||||
label: Email address
|
|
||||||
|
|
||||||
country:
|
|
||||||
label: Country
|
|
||||||
type: relation
|
|
||||||
relation:
|
|
||||||
model: RainLab\Location\Models\Country
|
|
||||||
label: Name
|
|
||||||
nameFrom: name
|
|
||||||
keyFrom: id
|
|
||||||
```
|
|
||||||
|
|
||||||
## Save to database action
|
|
||||||
|
|
||||||
There is a dedicated table in the database for storing events and their parameters. This table is accessed using the `RainLab\Notify\Models\Notification` model and can be referenced as a relation from your own models. In this example the `MyProject` model contains its own notification channel called `notifications`.
|
|
||||||
|
|
||||||
```php
|
|
||||||
class MyProject extends Model
|
|
||||||
{
|
|
||||||
// ...
|
|
||||||
|
|
||||||
public $morphMany = [
|
|
||||||
'my_notifications' => [
|
|
||||||
\RainLab\Notify\Models\Notification::class,
|
|
||||||
'name' => 'notifiable'
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
This channel should be registered with the `RainLab\Notify\NotifyRules\SaveDatabaseAction` so it appears as a related object when selecting the action.
|
|
||||||
|
|
||||||
```php
|
|
||||||
SaveDatabaseAction::extend(function ($action) {
|
|
||||||
$action->addTableDefinition([
|
|
||||||
'label' => 'Project activity',
|
|
||||||
'class' => MyProject::class,
|
|
||||||
'relation' => 'my_notifications',
|
|
||||||
'param' => 'project'
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
The **label** is shown as the related object, the **class** references the model class, the **relation** refers to the relation name. The **param** defines the parameter name, passed to the triggering event.
|
|
||||||
|
|
||||||
So essentially if you pass a `project` to the event parameters, or if `project` is a global parameter, a notification model is created with the parameters stored in the `data` attribute. Equivalent to the following code:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$myproject->my_notifications()->create([
|
|
||||||
// ...
|
|
||||||
'data' => $params
|
|
||||||
]);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dynamically adding conditions to events
|
|
||||||
|
|
||||||
Events can be extended to include new local conditions. Simply add the condition class to the event `$conditions` array property.
|
|
||||||
|
|
||||||
```php
|
|
||||||
UserActivatedEvent::extend(function($event) {
|
|
||||||
$event->conditions[] = \RainLab\UserPlus\NotifyRules\UserLocationAttributeCondition::class;
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use System\Classes\PluginManager;
|
|
||||||
use October\Rain\Extension\ExtensionBase;
|
|
||||||
use RainLab\Notify\Interfaces\Action as ActionInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification action base class
|
|
||||||
*
|
|
||||||
* @package rainlab\notify
|
|
||||||
* @author Alexey Bobkov, Samuel Georges
|
|
||||||
*/
|
|
||||||
class ActionBase extends ExtensionBase implements ActionInterface
|
|
||||||
{
|
|
||||||
use \System\Traits\ConfigMaker;
|
|
||||||
use \System\Traits\ViewMaker;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Model host object
|
|
||||||
*/
|
|
||||||
protected $host;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var mixed Extra field configuration for the condition.
|
|
||||||
*/
|
|
||||||
protected $fieldConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns information about this action, including name and description.
|
|
||||||
*/
|
|
||||||
public function actionDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Action',
|
|
||||||
'description' => 'Action description',
|
|
||||||
'icon' => 'icon-dot-circle-o'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct($host = null)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Paths
|
|
||||||
*/
|
|
||||||
$this->viewPath = $this->configPath = $this->guessConfigPathFrom($this);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse the config, if available
|
|
||||||
*/
|
|
||||||
if ($formFields = $this->defineFormFields()) {
|
|
||||||
$this->fieldConfig = $this->makeConfig($formFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->host = $host) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->boot($host);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Boot method called when the condition class is first loaded
|
|
||||||
* with an existing model.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function boot($host)
|
|
||||||
{
|
|
||||||
// Set default data
|
|
||||||
if (!$host->exists) {
|
|
||||||
$this->initConfigData($host);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply validation rules
|
|
||||||
$host->rules = array_merge($host->rules, $this->defineValidationRules());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function triggerAction($params)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return $this->getActionName();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
return $this->getActionDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActionName()
|
|
||||||
{
|
|
||||||
return array_get($this->actionDetails(), 'name');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActionDescription()
|
|
||||||
{
|
|
||||||
return array_get($this->actionDetails(), 'description');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActionIcon()
|
|
||||||
{
|
|
||||||
return array_get($this->actionDetails(), 'icon', 'icon-dot-circle-o');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra field configuration for the condition.
|
|
||||||
*/
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines if this action uses form fields.
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function hasFieldConfig()
|
|
||||||
{
|
|
||||||
return !!$this->fieldConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the field configuration used by this model.
|
|
||||||
*/
|
|
||||||
public function getFieldConfig()
|
|
||||||
{
|
|
||||||
return $this->fieldConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes configuration data when the condition is first created.
|
|
||||||
* @param Model $host
|
|
||||||
*/
|
|
||||||
public function initConfigData($host) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines validation rules for the custom fields.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function defineValidationRules()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spins over types registered in plugin base class with `registerNotificationRules`.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function findActions()
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
$bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules');
|
|
||||||
|
|
||||||
foreach ($bundles as $plugin => $bundle) {
|
|
||||||
foreach ((array) array_get($bundle, 'actions', []) as $conditionClass) {
|
|
||||||
if (!class_exists($conditionClass)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$obj = new $conditionClass;
|
|
||||||
$results[$conditionClass] = $obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,169 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use RainLab\Notify\Interfaces\CompoundCondition as CompoundConditionInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Compound Condition Class
|
|
||||||
*/
|
|
||||||
class CompoundCondition extends ConditionBase implements CompoundConditionInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns a condition title for displaying in the condition settings form
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return 'Compound condition';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
$result = $this->host->condition_type == 0
|
|
||||||
? 'ALL of subconditions should be '
|
|
||||||
: 'ANY of subconditions should be ';
|
|
||||||
|
|
||||||
$result .= $this->host->condition == 'false' ? 'FALSE' : 'TRUE';
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the text to use when joining two rules within.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getJoinText()
|
|
||||||
{
|
|
||||||
return $this->host->condition_type == 0 ? 'AND' : 'OR';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of condition types (`ConditionBase::TYPE_*` constants)
|
|
||||||
* that can be added to this compound condition
|
|
||||||
*/
|
|
||||||
public function getAllowedSubtypes()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initConfigData($host)
|
|
||||||
{
|
|
||||||
$host->condition_type = 0;
|
|
||||||
$host->condition = 'true';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConditionOptions()
|
|
||||||
{
|
|
||||||
$options = [
|
|
||||||
'true' => 'TRUE',
|
|
||||||
'false' => 'FALSE'
|
|
||||||
];
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConditionTypeOptions()
|
|
||||||
{
|
|
||||||
$options = [
|
|
||||||
'0' => 'ALL subconditions should meet the requirement',
|
|
||||||
'1' => 'ANY subconditions should meet the requirement'
|
|
||||||
];
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getChildOptions(array $options)
|
|
||||||
{
|
|
||||||
extract(array_merge([
|
|
||||||
'extraRules' => [],
|
|
||||||
], $options));
|
|
||||||
|
|
||||||
$result = [
|
|
||||||
'Compound condition' => CompoundCondition::class
|
|
||||||
];
|
|
||||||
|
|
||||||
$classes = $extraRules + self::findConditionsByType(ConditionBase::TYPE_ANY);
|
|
||||||
|
|
||||||
$result = $this->addClassesSubconditions($classes, $result);
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function addClassesSubconditions($classes, $list)
|
|
||||||
{
|
|
||||||
foreach ($classes as $conditionClass => $obj) {
|
|
||||||
|
|
||||||
$subConditions = $obj->listSubconditions();
|
|
||||||
|
|
||||||
if ($subConditions) {
|
|
||||||
$groupName = $obj->getGroupingTitle();
|
|
||||||
|
|
||||||
foreach ($subConditions as $name => $subcondition) {
|
|
||||||
if (!$groupName) {
|
|
||||||
$list[$name] = $conditionClass.':'.$subcondition;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (!array_key_exists($groupName, $list)) {
|
|
||||||
$list[$groupName] = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$list[$groupName][$name] = $conditionClass.':'.$subcondition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$list[$obj->getName()] = $conditionClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the condition is TRUE for specified parameters.
|
|
||||||
*
|
|
||||||
* @param array $params
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTrue(&$params)
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
|
|
||||||
$requiredConditionValue = $hostObj->condition == 'true' ? true : false;
|
|
||||||
|
|
||||||
foreach ($hostObj->children as $subcondition) {
|
|
||||||
$subconditionResult = $subcondition->getConditionObject()->isTrue($params) ? true : false;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* All
|
|
||||||
*/
|
|
||||||
if ($hostObj->condition_type == 0) {
|
|
||||||
if ($subconditionResult !== $requiredConditionValue) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Any
|
|
||||||
*/
|
|
||||||
else {
|
|
||||||
if ($subconditionResult === $requiredConditionValue) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* All
|
|
||||||
*/
|
|
||||||
if ($hostObj->condition_type == 0) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,211 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use System\Classes\PluginManager;
|
|
||||||
use October\Rain\Extension\ExtensionBase;
|
|
||||||
use RainLab\Notify\Interfaces\Condition as ConditionInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Condition Base Class
|
|
||||||
*/
|
|
||||||
class ConditionBase extends ExtensionBase implements ConditionInterface
|
|
||||||
{
|
|
||||||
use \System\Traits\ConfigMaker;
|
|
||||||
use \System\Traits\ViewMaker;
|
|
||||||
|
|
||||||
const TYPE_ANY = 'any';
|
|
||||||
const TYPE_LOCAL = 'local';
|
|
||||||
|
|
||||||
const CAST_FLOAT = 'float';
|
|
||||||
const CAST_STRING = 'string';
|
|
||||||
const CAST_INTEGER = 'integer';
|
|
||||||
const CAST_BOOLEAN = 'boolean';
|
|
||||||
const CAST_RELATION = 'relation';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Model host object
|
|
||||||
*/
|
|
||||||
protected $host;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var mixed Extra field configuration for the condition.
|
|
||||||
*/
|
|
||||||
protected $fieldConfig;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string The plugin class method used to look for conditions.
|
|
||||||
*/
|
|
||||||
protected static $registrationMethod = 'registerNotificationRules';
|
|
||||||
|
|
||||||
public function __construct($host = null)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Paths
|
|
||||||
*/
|
|
||||||
$this->viewPath = $this->configPath = $this->guessConfigPathFrom($this);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse the config
|
|
||||||
*/
|
|
||||||
$this->fieldConfig = $this->makeConfig($this->defineFormFields());
|
|
||||||
|
|
||||||
if (!$this->host = $host) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->boot($host);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Boot method called when the condition class is first loaded
|
|
||||||
* with an existing model.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function boot($host)
|
|
||||||
{
|
|
||||||
// Set default data
|
|
||||||
if (!$host->exists) {
|
|
||||||
$this->initConfigData($host);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply validation rules
|
|
||||||
$host->rules = array_merge($host->rules, $this->defineValidationRules());
|
|
||||||
|
|
||||||
// Inject view paths to the controller through the Form widget
|
|
||||||
$host->bindEvent('model.form.filterFields', function($form) {
|
|
||||||
$form->getController()->addViewPath($this->getViewPaths());
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extra field configuration for the condition.
|
|
||||||
*/
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initializes configuration data when the condition is first created.
|
|
||||||
* @param Model $host
|
|
||||||
*/
|
|
||||||
public function initConfigData($host) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines validation rules for the custom fields.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function defineValidationRules()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
return 'Condition text';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a condition name for displaying in the condition selection drop-down menu
|
|
||||||
*/
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'Condition';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a condition title for displaying in the condition settings form
|
|
||||||
*/
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return 'Condition';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should return one of the `ConditionBase::TYPE_*` constants
|
|
||||||
* depending on a place where the condition is valid
|
|
||||||
*/
|
|
||||||
public function getConditionType()
|
|
||||||
{
|
|
||||||
return ConditionBase::TYPE_ANY;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listSubconditions()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a title to use for grouping subconditions
|
|
||||||
* in the Create Condition drop-down menu
|
|
||||||
*/
|
|
||||||
public function getGroupingTitle()
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the field configuration used by this model.
|
|
||||||
*/
|
|
||||||
public function getFieldConfig()
|
|
||||||
{
|
|
||||||
return $this->fieldConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spins over types registered in plugin base class with `registerNotificationRules`,
|
|
||||||
* checks if the condition type matches and adds it to an array that is returned.
|
|
||||||
*
|
|
||||||
* @param string $type Use `self::TYPE_*` constants
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function findConditionsByType($type)
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
$bundles = PluginManager::instance()->getRegistrationMethodValues(static::$registrationMethod);
|
|
||||||
|
|
||||||
foreach ($bundles as $plugin => $bundle) {
|
|
||||||
foreach ((array) array_get($bundle, 'conditions', []) as $conditionClass) {
|
|
||||||
if (!class_exists($conditionClass)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$obj = new $conditionClass;
|
|
||||||
if ($obj->getConditionType() != $type) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$results[$conditionClass] = $obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setFormFields($fields)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCustomData()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onPreRender($controller, $widget)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the condition is TRUE for specified parameters
|
|
||||||
* @param array $params
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTrue(&$params)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getChildOptions(array $options)
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use Str;
|
|
||||||
use Yaml;
|
|
||||||
use File;
|
|
||||||
use Lang;
|
|
||||||
use System\Classes\PluginManager;
|
|
||||||
use October\Rain\Extension\ExtensionBase;
|
|
||||||
use RainLab\Notify\Interfaces\Event as EventInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification event base class
|
|
||||||
*
|
|
||||||
* @package rainlab\notify
|
|
||||||
* @author Alexey Bobkov, Samuel Georges
|
|
||||||
*/
|
|
||||||
class EventBase extends ExtensionBase implements EventInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Model host object
|
|
||||||
*/
|
|
||||||
protected $host;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Contains the event parameter values.
|
|
||||||
*/
|
|
||||||
protected $params = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Local conditions supported by this event.
|
|
||||||
*/
|
|
||||||
public $conditions = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns information about this event, including name and description.
|
|
||||||
*/
|
|
||||||
public function eventDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Event',
|
|
||||||
'description' => 'Event description',
|
|
||||||
'group' => 'groupcode'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function __construct($host = null)
|
|
||||||
{
|
|
||||||
$this->host = $host;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines the parameters used by this class.
|
|
||||||
* This method should be used as an override in the extended class.
|
|
||||||
*/
|
|
||||||
public function defineParams()
|
|
||||||
{
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Local conditions supported by this event.
|
|
||||||
*/
|
|
||||||
public function defineConditions()
|
|
||||||
{
|
|
||||||
return $this->conditions;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets multiple params.
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function setParams($params)
|
|
||||||
{
|
|
||||||
$this->params = $params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns all params.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getParams()
|
|
||||||
{
|
|
||||||
return $this->params;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates event parameters based on arguments from the triggering system event.
|
|
||||||
* @param array $args
|
|
||||||
* @param string $eventName
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function makeParamsFromEvent(array $args, $eventName = null)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEventName()
|
|
||||||
{
|
|
||||||
return Lang::get(array_get($this->eventDetails(), 'name'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEventDescription()
|
|
||||||
{
|
|
||||||
return Lang::get(array_get($this->eventDetails(), 'description'));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEventGroup()
|
|
||||||
{
|
|
||||||
return array_get($this->eventDetails(), 'group');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Resolves an event or action identifier from a class name or object.
|
|
||||||
* @param mixed Class name or object
|
|
||||||
* @return string Identifier in format of vendor-plugin-class
|
|
||||||
*/
|
|
||||||
public function getEventIdentifier()
|
|
||||||
{
|
|
||||||
$namespace = Str::normalizeClassName(get_called_class());
|
|
||||||
if (strpos($namespace, '\\') === null) {
|
|
||||||
return $namespace;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parts = explode('\\', $namespace);
|
|
||||||
$class = array_pop($parts);
|
|
||||||
$slice = array_slice($parts, 1, 2);
|
|
||||||
$code = strtolower(implode('-', $slice) . '-' . $class);
|
|
||||||
|
|
||||||
return $code;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spins over types registered in plugin base class with `registerNotificationRules`.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function findEvents()
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
$bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules');
|
|
||||||
|
|
||||||
foreach ($bundles as $plugin => $bundle) {
|
|
||||||
foreach ((array) array_get($bundle, 'events', []) as $conditionClass) {
|
|
||||||
if (!class_exists($conditionClass)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$obj = new $conditionClass;
|
|
||||||
$results[$conditionClass] = $obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findEventGroups()
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
$bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules');
|
|
||||||
|
|
||||||
foreach ($bundles as $plugin => $bundle) {
|
|
||||||
if ($groups = array_get($bundle, 'groups')) {
|
|
||||||
$results += $groups;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findEventsByGroup($group)
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
|
|
||||||
foreach (self::findEvents() as $conditionClass => $obj) {
|
|
||||||
if ($obj->getEventGroup() != $group) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$results[$conditionClass] = $obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findEventByIdentifier($identifier)
|
|
||||||
{
|
|
||||||
foreach (self::findEvents() as $class => $obj) {
|
|
||||||
if ($obj->getEventIdentifier() == $identifier) {
|
|
||||||
return $obj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spins over preset registered in plugin base class with `registerNotificationRules`.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function findEventPresets()
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
$bundles = PluginManager::instance()->getRegistrationMethodValues('registerNotificationRules');
|
|
||||||
|
|
||||||
foreach ($bundles as $plugin => $bundle) {
|
|
||||||
if (!$presets = array_get($bundle, 'presets')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!is_array($presets)) {
|
|
||||||
$presets = Yaml::parse(File::get(File::symbolizePath($presets)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($presets && is_array($presets)) {
|
|
||||||
$results += $presets;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function findEventPresetsByClass($className)
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
|
|
||||||
foreach (self::findEventPresets() as $code => $definition) {
|
|
||||||
if (!$eventClass = array_get($definition, 'event')) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($eventClass != $className) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$results[$code] = $definition;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
|
||||||
|
|
||||||
class EventParams
|
|
||||||
{
|
|
||||||
use \Illuminate\Queue\InteractsWithQueue;
|
|
||||||
use \Illuminate\Queue\SerializesAndRestoresModelIdentifiers;
|
|
||||||
|
|
||||||
protected $eventClass;
|
|
||||||
protected $params;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new job instance.
|
|
||||||
*
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function __construct($eventClass, array $params)
|
|
||||||
{
|
|
||||||
$this->eventClass = $eventClass;
|
|
||||||
|
|
||||||
$this->params = $this->serializeParams($params);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Execute the job.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function handle()
|
|
||||||
{
|
|
||||||
$this->delete();
|
|
||||||
|
|
||||||
Notifier::instance()->fireEvent($this->eventClass, $this->unserializeParams());
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function serializeParams($params)
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($params as $param => $value) {
|
|
||||||
$result[$param] = $this->getSerializedPropertyValue($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function unserializeParams()
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($this->params as $param => $value) {
|
|
||||||
$result[$param] = $this->getRestoredPropertyValue($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,731 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use Db;
|
|
||||||
use App;
|
|
||||||
use SystemException;
|
|
||||||
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
|
||||||
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
|
|
||||||
|
|
||||||
class ModelAttributesConditionBase extends ConditionBase
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string Special value to declare nothing provided.
|
|
||||||
*/
|
|
||||||
const NO_EVAL_VALUE = '__no_eval_value__';
|
|
||||||
|
|
||||||
protected $modelClass = null;
|
|
||||||
|
|
||||||
protected $operators = [
|
|
||||||
'is' => 'is',
|
|
||||||
'is_not' => 'is not',
|
|
||||||
'equals_or_greater' => 'equals or greater than',
|
|
||||||
'equals_or_less' => 'equals or less than',
|
|
||||||
'contains' => 'contains',
|
|
||||||
'does_not_contain' => 'does not contain',
|
|
||||||
'greater' => 'greater than',
|
|
||||||
'less' => 'less than',
|
|
||||||
'one_of' => 'is one of',
|
|
||||||
'not_one_of' => 'is not one of'
|
|
||||||
];
|
|
||||||
|
|
||||||
protected $modelObj = null;
|
|
||||||
protected $referenceInfo = null;
|
|
||||||
protected $modelAttributes = null;
|
|
||||||
|
|
||||||
protected static $modelObjCache = [];
|
|
||||||
protected static $attributeControlTypeCache = [];
|
|
||||||
|
|
||||||
public function __construct($host = null)
|
|
||||||
{
|
|
||||||
parent::__construct($host);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is used as a base class, so register view path from here too
|
|
||||||
*/
|
|
||||||
$this->addViewPath($this->guessViewPathFrom(__CLASS__));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initConfigData($host)
|
|
||||||
{
|
|
||||||
$host->operator = 'is';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCustomData()
|
|
||||||
{
|
|
||||||
$this->host->condition_control_type = $this->evalControlType();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Definitions
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function should return one of the `ConditionBase::TYPE_*` constants
|
|
||||||
* depending on a place where the condition is valid
|
|
||||||
*/
|
|
||||||
public function getConditionType()
|
|
||||||
{
|
|
||||||
return ConditionBase::TYPE_LOCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function defineModelAttributes($type = null)
|
|
||||||
{
|
|
||||||
return 'attributes.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function defineValidationRules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'value' => 'required'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return plugins_path('rainlab/notify/classes/modelattributesconditionbase/fields.yaml');
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Text helpers
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
$host = $this->host;
|
|
||||||
$attributes = $this->listModelAttributes();
|
|
||||||
|
|
||||||
if (isset($attributes[$host->subcondition])) {
|
|
||||||
$result = $this->getConditionTextPrefix($host, $attributes);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$result = 'Unknown attribute';
|
|
||||||
}
|
|
||||||
|
|
||||||
$result .= ' <span class="operator">'.array_get($this->operators, $host->operator, $host->operator).'</span> ';
|
|
||||||
|
|
||||||
$controlType = $this->getValueControlType();
|
|
||||||
|
|
||||||
if ($controlType == 'text') {
|
|
||||||
$result .= $host->value;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$textValue = $this->getCustomTextValue();
|
|
||||||
if ($textValue !== false) {
|
|
||||||
return $result.' '.$textValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$referenceInfo = $this->prepareReferenceListInfo();
|
|
||||||
$modelObj = $referenceInfo->referenceModel;
|
|
||||||
|
|
||||||
if (!count($referenceInfo->columns)) {
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!strlen($host->value)) {
|
|
||||||
return $result .= '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
$visibleField = $referenceInfo->primaryColumn;
|
|
||||||
|
|
||||||
if ($controlType == 'dropdown') {
|
|
||||||
$obj = $modelObj->where('id', $host->value)->first();
|
|
||||||
if ($obj) {
|
|
||||||
$result .= e($obj->{$visibleField});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$ids = explode(',', $host->value);
|
|
||||||
foreach ($ids as &$id) {
|
|
||||||
$id = trim(e($id));
|
|
||||||
}
|
|
||||||
|
|
||||||
$records = $modelObj
|
|
||||||
->whereIn('id', $ids)
|
|
||||||
->orderBy($visibleField)
|
|
||||||
->get();
|
|
||||||
|
|
||||||
$recordNames = [];
|
|
||||||
foreach ($records as $record) {
|
|
||||||
$recordNames[] = $record->{$visibleField};
|
|
||||||
}
|
|
||||||
|
|
||||||
$result .= '('.implode(', ', $recordNames).')';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getConditionTextPrefix($parametersHost, $attributes)
|
|
||||||
{
|
|
||||||
return $attributes[$parametersHost->subcondition];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCustomTextValue()
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Options
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getSubconditionOptions()
|
|
||||||
{
|
|
||||||
return $this->listModelAttributes();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOperatorOptions()
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
$options = [];
|
|
||||||
$attribute = $hostObj->subcondition;
|
|
||||||
|
|
||||||
$currentOperatorValue = $hostObj->operator;
|
|
||||||
|
|
||||||
$model = $this->getModelObj();
|
|
||||||
$definitions = $this->listModelAttributeInfo();
|
|
||||||
|
|
||||||
if (!isset($definitions[$attribute])) {
|
|
||||||
$options = ['none' => 'Unknown attribute selected'];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$columnType = array_get($definitions[$attribute], 'type');
|
|
||||||
|
|
||||||
if ($columnType != ConditionBase::CAST_RELATION) {
|
|
||||||
if ($columnType == ConditionBase::CAST_STRING) {
|
|
||||||
$options = [
|
|
||||||
'is' => 'is',
|
|
||||||
'is_not' => 'is not',
|
|
||||||
'contains' => 'contains',
|
|
||||||
'does_not_contain' => 'does not contain'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$options = [
|
|
||||||
'is' => 'is',
|
|
||||||
'is_not' => 'is not',
|
|
||||||
'equals_or_greater' => 'equals or greater than',
|
|
||||||
'equals_or_less' => 'equals or less than',
|
|
||||||
'greater' => 'greater than',
|
|
||||||
'less' => 'less than'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$options = [
|
|
||||||
'is' => 'is',
|
|
||||||
'is_not' => 'is not',
|
|
||||||
'one_of' => 'is one of',
|
|
||||||
'not_one_of' => 'is not one of'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($currentOperatorValue, $options)) {
|
|
||||||
$keys = array_keys($options);
|
|
||||||
if (count($keys)) {
|
|
||||||
$hostObj->operator = $options[$keys[0]];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$hostObj->operator = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $options;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValueDropdownOptions()
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
$attribute = $hostObj->subcondition;
|
|
||||||
$definitions = $this->listModelAttributeInfo();
|
|
||||||
|
|
||||||
if (!isset($definitions[$attribute])) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$columnType = array_get($definitions[$attribute], 'type');
|
|
||||||
|
|
||||||
if ($columnType != ConditionBase::CAST_RELATION) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$referenceInfo = $this->prepareReferenceListInfo();
|
|
||||||
$referenceModel = $referenceInfo->referenceModel;
|
|
||||||
$nameFrom = $referenceInfo->primaryColumn;
|
|
||||||
$keyFrom = $referenceInfo->primaryKey;
|
|
||||||
|
|
||||||
// Determine if the model uses a tree trait
|
|
||||||
$treeTraits = ['October\Rain\Database\Traits\NestedTree', 'October\Rain\Database\Traits\SimpleTree'];
|
|
||||||
$usesTree = count(array_intersect($treeTraits, class_uses($referenceModel))) > 0;
|
|
||||||
|
|
||||||
$results = $referenceModel->get();
|
|
||||||
|
|
||||||
return $usesTree
|
|
||||||
? $results->listsNested($nameFrom, $keyFrom)
|
|
||||||
: $results->lists($nameFrom, $keyFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Control type
|
|
||||||
//
|
|
||||||
|
|
||||||
protected function evalControlType()
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
$attribute = $hostObj->subcondition;
|
|
||||||
$operator = $hostObj->operator;
|
|
||||||
|
|
||||||
$definitions = $this->listModelAttributeInfo();
|
|
||||||
|
|
||||||
if (!isset($definitions[$attribute])) {
|
|
||||||
return 'text';
|
|
||||||
}
|
|
||||||
|
|
||||||
$columnType = array_get($definitions[$attribute], 'type');
|
|
||||||
|
|
||||||
if ($columnType != ConditionBase::CAST_RELATION) {
|
|
||||||
return 'text';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if ($operator == 'is' || $operator == 'is_not') {
|
|
||||||
return 'dropdown';
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'multi_value';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValueControlType()
|
|
||||||
{
|
|
||||||
if (App::runningInBackend()) {
|
|
||||||
return $this->evalControlType();
|
|
||||||
}
|
|
||||||
|
|
||||||
$hostObj = $this->host;
|
|
||||||
|
|
||||||
if ($controlType = $hostObj->condition_control_type) {
|
|
||||||
return $controlType;
|
|
||||||
}
|
|
||||||
|
|
||||||
$controlType = $this->evalControlType();
|
|
||||||
|
|
||||||
$this->getModelObj()
|
|
||||||
->where('id', $host->id)
|
|
||||||
->update(['condition_control_type' => $controlType]);
|
|
||||||
|
|
||||||
return $hostObj->condition_control_type = $controlType;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Attributes
|
|
||||||
//
|
|
||||||
|
|
||||||
public function listSubconditions()
|
|
||||||
{
|
|
||||||
$attributes = $this->listModelAttributes();
|
|
||||||
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($attributes as $name => $code) {
|
|
||||||
$result[$code] = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the supported attributes by a condition as an array.
|
|
||||||
* The key is the attribute and the value is the label.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function listModelAttributes()
|
|
||||||
{
|
|
||||||
$attributeInfo = $this->listModelAttributeInfo();
|
|
||||||
|
|
||||||
foreach ($attributeInfo as $attribute => $info) {
|
|
||||||
$attributes[$attribute] = array_get($info, 'label');
|
|
||||||
}
|
|
||||||
|
|
||||||
asort($attributes);
|
|
||||||
|
|
||||||
return $attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function listModelAttributeInfo()
|
|
||||||
{
|
|
||||||
if ($this->modelAttributes) {
|
|
||||||
return $this->modelAttributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = $this->makeConfig($this->defineModelAttributes($this->getConditionType()));
|
|
||||||
|
|
||||||
$attributes = $config->attributes ?? [];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set defaults
|
|
||||||
*/
|
|
||||||
foreach ($attributes as $attribute => $info) {
|
|
||||||
if (!isset($info['type'])) {
|
|
||||||
$attributes[$attribute]['type'] = 'string';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->modelAttributes = $attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Relation based attributes
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getReferencePrimaryColumn($record)
|
|
||||||
{
|
|
||||||
$referenceInfo = $this->prepareReferenceListInfo();
|
|
||||||
|
|
||||||
return $record->{$referenceInfo->primaryColumn};
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listSelectedReferenceRecords()
|
|
||||||
{
|
|
||||||
$referenceInfo = $this->prepareReferenceListInfo();
|
|
||||||
$model = $referenceInfo->referenceModel;
|
|
||||||
|
|
||||||
$value = $this->host->value;
|
|
||||||
$keys = strlen($value) ? explode(',', $value) : [];
|
|
||||||
|
|
||||||
if (count($keys)) {
|
|
||||||
$model = $model->whereIn('id', $keys);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$model = $model->whereRaw('id <> id');
|
|
||||||
}
|
|
||||||
|
|
||||||
$orderField = $referenceInfo->primaryColumn;
|
|
||||||
|
|
||||||
return $model->orderBy($orderField)->get();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareReferenceListInfo()
|
|
||||||
{
|
|
||||||
if (!is_null($this->referenceInfo)) {
|
|
||||||
return $this->referenceInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
$model = $this->getModelObj();
|
|
||||||
$attribute = $this->host->subcondition;
|
|
||||||
$definitions = $this->listModelAttributeInfo();
|
|
||||||
$definition = array_get($definitions, $attribute);
|
|
||||||
|
|
||||||
$columns = array_get($definition, 'columns');
|
|
||||||
$primaryColumn = array_get($definition, 'relation.nameFrom', 'name');
|
|
||||||
|
|
||||||
if ($model->hasRelation($attribute)) {
|
|
||||||
$relationType = $model->getRelationType($attribute);
|
|
||||||
$relationModel = $model->makeRelation($attribute);
|
|
||||||
$relationObject = $model->{$attribute}();
|
|
||||||
|
|
||||||
// Some simpler relations can specify a custom local or foreign "other" key,
|
|
||||||
// which can be detected and implemented here automagically.
|
|
||||||
$primaryKey = in_array($relationType, ['hasMany', 'belongsTo', 'hasOne'])
|
|
||||||
? $relationObject->getOtherKey()
|
|
||||||
: $relationModel->getKeyName();
|
|
||||||
}
|
|
||||||
elseif ($relationClass = array_get($definition, 'relation.model')) {
|
|
||||||
$relationModel = new $relationClass;
|
|
||||||
$primaryKey = array_get($definition, 'relation.keyFrom', 'id');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new SystemException(sprintf('Model %s does not contain a relation "%s"', get_class($model), $attribute));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$columns) {
|
|
||||||
$columns = [
|
|
||||||
$primaryColumn => [
|
|
||||||
'label' => array_get($definition, 'relation.label', '?'),
|
|
||||||
'searchable' => true
|
|
||||||
]
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->referenceInfo = [];
|
|
||||||
$this->referenceInfo['referenceModel'] = $relationModel;
|
|
||||||
$this->referenceInfo['primaryKey'] = $primaryKey;
|
|
||||||
$this->referenceInfo['primaryColumn'] = $primaryColumn;
|
|
||||||
$this->referenceInfo['columns'] = $columns;
|
|
||||||
|
|
||||||
return $this->referenceInfo = (object) $this->referenceInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onPreRender($controller, $widget)
|
|
||||||
{
|
|
||||||
$controlType = $this->getValueControlType();
|
|
||||||
|
|
||||||
if ($controlType != 'multi_value') {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$selectionColumn = [
|
|
||||||
'_select_record' => [
|
|
||||||
'label' => '',
|
|
||||||
'sortable' => false,
|
|
||||||
'type' => 'partial',
|
|
||||||
'width' => '10px',
|
|
||||||
'path' => plugins_path('rainlab/notify/classes/modelattributesconditionbase/_column_select_record.htm')
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
$referenceInfo = $this->prepareReferenceListInfo();
|
|
||||||
$filterModel = $referenceInfo->referenceModel;
|
|
||||||
$filterColumns = $selectionColumn + $referenceInfo->columns;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* List widget
|
|
||||||
*/
|
|
||||||
$config = $this->makeConfig();
|
|
||||||
$config->columns = $filterColumns;
|
|
||||||
$config->model = $filterModel;
|
|
||||||
$config->alias = $widget->alias . 'List';
|
|
||||||
$config->showSetup = false;
|
|
||||||
$config->showCheckboxes = false;
|
|
||||||
$config->recordsPerPage = 6;
|
|
||||||
$listWidget = $controller->makeWidget('Backend\Widgets\Lists', $config);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Search widget
|
|
||||||
*/
|
|
||||||
$config = $this->makeConfig();
|
|
||||||
$config->alias = $widget->alias . 'Search';
|
|
||||||
$config->growable = false;
|
|
||||||
$config->prompt = 'backend::lang.list.search_prompt';
|
|
||||||
$searchWidget = $controller->makeWidget('Backend\Widgets\Search', $config);
|
|
||||||
$searchWidget->cssClasses[] = 'condition-filter-search';
|
|
||||||
|
|
||||||
$listWidget->bindToController();
|
|
||||||
$searchWidget->bindToController();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extend list query
|
|
||||||
*/
|
|
||||||
$listWidget->bindEvent('list.extendQueryBefore', function ($query) use ($filterModel) {
|
|
||||||
$this->prepareFilterQuery($query, $filterModel);
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Link the Search Widget to the List Widget
|
|
||||||
*/
|
|
||||||
$listWidget->setSearchTerm($searchWidget->getActiveTerm());
|
|
||||||
|
|
||||||
$searchWidget->bindEvent('search.submit', function () use (&$searchWidget, $listWidget) {
|
|
||||||
$listWidget->setSearchTerm($searchWidget->getActiveTerm());
|
|
||||||
return $listWidget->onRefresh();
|
|
||||||
});
|
|
||||||
|
|
||||||
$controller->vars['listWidget'] = $listWidget;
|
|
||||||
$controller->vars['searchWidget'] = $searchWidget;
|
|
||||||
$controller->vars['filterHostModel'] = $this->host;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prepareFilterQuery($query, $model)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Condition check
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the condition is TRUE for a specified model
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function evalIsTrue($model, $customValue = '__no_eval_value__')
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
|
|
||||||
$operator = $hostObj->operator;
|
|
||||||
$attribute = $hostObj->subcondition;
|
|
||||||
|
|
||||||
$conditionValue = $hostObj->value;
|
|
||||||
$conditionValue = trim(mb_strtolower($conditionValue));
|
|
||||||
|
|
||||||
$controlType = $this->getValueControlType();
|
|
||||||
|
|
||||||
if ($controlType == 'text') {
|
|
||||||
if ($customValue === self::NO_EVAL_VALUE) {
|
|
||||||
$modelValue = trim(mb_strtolower($model->{$attribute}));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$modelValue = trim(mb_strtolower($customValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'is') {
|
|
||||||
return $modelValue == $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'is_not') {
|
|
||||||
return $modelValue != $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'contains') {
|
|
||||||
return mb_strpos($modelValue, $conditionValue) !== false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'does_not_contain') {
|
|
||||||
return mb_strpos($modelValue, $conditionValue) === false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'equals_or_greater') {
|
|
||||||
return $modelValue >= $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'equals_or_less') {
|
|
||||||
return $modelValue <= $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'greater') {
|
|
||||||
return $modelValue > $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'less') {
|
|
||||||
return $modelValue < $conditionValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($controlType == 'dropdown') {
|
|
||||||
if ($customValue === self::NO_EVAL_VALUE) {
|
|
||||||
$modelValue = $model->{$attribute};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$modelValue = $customValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'is') {
|
|
||||||
if ($modelValue == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($modelValue instanceof EloquentModel) {
|
|
||||||
return $modelValue->getKey() == $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
is_array($modelValue) &&
|
|
||||||
count($modelValue) == 1 &&
|
|
||||||
array_key_exists(0, $modelValue)
|
|
||||||
) {
|
|
||||||
return $modelValue[0] == $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($modelValue instanceof EloquentCollection) {
|
|
||||||
if ($modelValue->count() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $modelValue[0]->getKey() == $conditionValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'is_not') {
|
|
||||||
if ($modelValue == null) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($modelValue instanceof EloquentModel) {
|
|
||||||
return $modelValue->getKey() != $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_array($modelValue)) {
|
|
||||||
if (count($modelValue) != 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists(0, $modelValue)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $modelValue[0] != $conditionValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($modelValue instanceof EloquentCollection) {
|
|
||||||
if (!$modelValue->count() || $modelValue->count() > 1) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $modelValue->first()->getKey() != $conditionValue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($controlType == 'multi_value') {
|
|
||||||
if ($customValue === self::NO_EVAL_VALUE) {
|
|
||||||
$modelValue = $model->{$attribute};
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$modelValue = $customValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
(!$modelValue instanceof EloquentCollection) &&
|
|
||||||
(!$modelValue instanceof EloquentModel) &&
|
|
||||||
!is_array($modelValue)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strlen($conditionValue)) {
|
|
||||||
$conditionValues = explode(',', $conditionValue);
|
|
||||||
foreach ($conditionValues as &$value) {
|
|
||||||
$value = trim($value);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$conditionValues = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($modelValue instanceof EloquentCollection) {
|
|
||||||
$modelKeys = array_keys($modelValue->lists('id', 'id'));
|
|
||||||
}
|
|
||||||
elseif ($modelValue instanceof EloquentModel) {
|
|
||||||
$modelKeys = [$modelValue->getKey()];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$modelKeys = $modelValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'is') {
|
|
||||||
$operator = 'one_of';
|
|
||||||
}
|
|
||||||
elseif ($operator == 'is_not') {
|
|
||||||
$operator = 'not_one_of';
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'one_of') {
|
|
||||||
return count(array_intersect($conditionValues, $modelKeys)) ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($operator == 'not_one_of') {
|
|
||||||
return count(array_intersect($conditionValues, $modelKeys)) ? false : true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Helpers
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getModelObj()
|
|
||||||
{
|
|
||||||
if ($this->modelObj === null) {
|
|
||||||
if (array_key_exists($this->modelClass, self::$modelObjCache)) {
|
|
||||||
$this->modelObj = self::$modelObjCache[$this->modelClass];
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->modelObj = self::$modelObjCache[$this->modelClass] = new $this->modelClass;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->modelObj;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,134 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Classes;
|
|
||||||
|
|
||||||
use App;
|
|
||||||
use Queue;
|
|
||||||
use Event;
|
|
||||||
use BackendAuth;
|
|
||||||
use System\Classes\PluginManager;
|
|
||||||
use RainLab\Notify\Models\NotificationRule as NotificationRuleModel;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification manager
|
|
||||||
*
|
|
||||||
* @package rainlab\notify
|
|
||||||
* @author Alexey Bobkov, Samuel Georges
|
|
||||||
*/
|
|
||||||
class Notifier
|
|
||||||
{
|
|
||||||
use \October\Rain\Support\Traits\Singleton;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Cache of registration callbacks.
|
|
||||||
*/
|
|
||||||
protected $callbacks = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool Internal marker to see if callbacks are run.
|
|
||||||
*/
|
|
||||||
protected $registered = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of registered global params in the system
|
|
||||||
*/
|
|
||||||
protected $registeredGlobalParams;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Registers a callback function that defines context variables.
|
|
||||||
* The callback function should register context variables by calling the manager's
|
|
||||||
* `registerGlobalParams` method. The manager instance is passed to the callback
|
|
||||||
* function as an argument. Usage:
|
|
||||||
*
|
|
||||||
* Notifier::registerCallback(function($manager){
|
|
||||||
* $manager->registerGlobalParams([...]);
|
|
||||||
* });
|
|
||||||
*
|
|
||||||
* @param callable $callback A callable function.
|
|
||||||
*/
|
|
||||||
public function registerCallback(callable $callback)
|
|
||||||
{
|
|
||||||
$this->callbacks[] = $callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Helper to process callbacks once and once only.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
protected function processCallbacks()
|
|
||||||
{
|
|
||||||
if ($this->registered) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->callbacks as $callback) {
|
|
||||||
$callback($this);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->registered = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Event binding
|
|
||||||
//
|
|
||||||
|
|
||||||
public static function bindEvents(array $events)
|
|
||||||
{
|
|
||||||
foreach ($events as $event => $class) {
|
|
||||||
self::bindEvent($event, $class);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function bindEvent($systemEventName, $notifyEventClass)
|
|
||||||
{
|
|
||||||
Event::listen($systemEventName, function() use ($notifyEventClass, $systemEventName) {
|
|
||||||
$params = $notifyEventClass::makeParamsFromEvent(func_get_args(), $systemEventName);
|
|
||||||
|
|
||||||
self::instance()->queueEvent($notifyEventClass, $params);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function queueEvent($eventClass, array $params)
|
|
||||||
{
|
|
||||||
$params += $this->getContextVars();
|
|
||||||
|
|
||||||
// Use queue
|
|
||||||
if (true) {
|
|
||||||
Queue::push(new EventParams($eventClass, $params));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$this->fireEvent($eventClass, $params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function fireEvent($eventClass, array $params)
|
|
||||||
{
|
|
||||||
$models = NotificationRuleModel::listRulesForEvent($eventClass);
|
|
||||||
|
|
||||||
foreach ($models as $model) {
|
|
||||||
$model->setParams($params);
|
|
||||||
$model->triggerRule();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function registerGlobalParams(array $params)
|
|
||||||
{
|
|
||||||
if (!$this->registeredGlobalParams) {
|
|
||||||
$this->registeredGlobalParams = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->registeredGlobalParams = $params + $this->registeredGlobalParams;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getContextVars()
|
|
||||||
{
|
|
||||||
$this->processCallbacks();
|
|
||||||
|
|
||||||
$globals = $this->registeredGlobalParams ?: [];
|
|
||||||
|
|
||||||
return [
|
|
||||||
'isBackend' => App::runningInBackend() ? 1 : 0,
|
|
||||||
'isConsole' => App::runningInConsole() ? 1 : 0,
|
|
||||||
'appLocale' => App::getLocale(),
|
|
||||||
'sender' => null // unsafe:BackendAuth::getUser()
|
|
||||||
] + $globals;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
condition_type:
|
|
||||||
label: Condition type
|
|
||||||
span: auto
|
|
||||||
type: dropdown
|
|
||||||
|
|
||||||
condition:
|
|
||||||
label: Required value
|
|
||||||
span: auto
|
|
||||||
type: dropdown
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
class="nolink"
|
|
||||||
data-record-key="<?= e($record->getKey()) ?>"
|
|
||||||
data-record-value="<?= e($filterHostModel->getReferencePrimaryColumn($record)) ?>"
|
|
||||||
data-multivalue-add-record>
|
|
||||||
<span class="list-badge badge-success">
|
|
||||||
<i class="icon-plus"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
|
|
@ -1,107 +0,0 @@
|
||||||
<?php
|
|
||||||
$attribute = $formModel->subcondition;
|
|
||||||
$controlType = $formModel->getValueControlType();
|
|
||||||
?>
|
|
||||||
<?php if ($controlType == 'text'): ?>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="<?= $field->getName() ?>"
|
|
||||||
id="<?= $field->getId() ?>"
|
|
||||||
value="<?= e($field->value) ?>"
|
|
||||||
class="form-control"
|
|
||||||
autocomplete="off"
|
|
||||||
maxlength="255"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<?php elseif ($controlType == 'dropdown'): ?>
|
|
||||||
<?php
|
|
||||||
$fieldOptions = $formModel->getValueDropdownOptions();
|
|
||||||
?>
|
|
||||||
<select
|
|
||||||
id="<?= $field->getId() ?>"
|
|
||||||
name="<?= $field->getName() ?>"
|
|
||||||
class="form-control custom-select">
|
|
||||||
<?php foreach ($fieldOptions as $value => $option): ?>
|
|
||||||
<option
|
|
||||||
<?= $field->isSelected($value) ? 'selected="selected"' : '' ?>
|
|
||||||
value="<?= $value ?>"><?= e(trans($option)) ?></option>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</select>
|
|
||||||
|
|
||||||
<?php elseif ($controlType == 'multi_value'): ?>
|
|
||||||
<?php
|
|
||||||
$selectedRecords = $formModel->listSelectedReferenceRecords();
|
|
||||||
$hasData = $selectedRecords->count();
|
|
||||||
?>
|
|
||||||
<div
|
|
||||||
class="condition-multi-value"
|
|
||||||
data-control="condition-multivalue"
|
|
||||||
data-data-locker="#<?= $field->getId() ?>">
|
|
||||||
|
|
||||||
<div class="filter-list list-flush">
|
|
||||||
<?= $searchWidget->render() ?>
|
|
||||||
<?= $listWidget->render() ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<label>Selected Records</label>
|
|
||||||
<div class="added-filter-list list-preview">
|
|
||||||
<div class="control-list">
|
|
||||||
<table class="table data">
|
|
||||||
<tbody data-added-records>
|
|
||||||
<?php if ($hasData): ?>
|
|
||||||
<?php foreach ($selectedRecords as $record): ?>
|
|
||||||
<tr data-record-key="<?= e($record->getKey()) ?>">
|
|
||||||
<td style="width: 10px">
|
|
||||||
<a href="javascript:;" data-multivalue-remove-record>
|
|
||||||
<span class="list-badge badge-default">
|
|
||||||
<i class="icon-minus"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<?= e($formModel->getReferencePrimaryColumn($record)) ?>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<?php endforeach ?>
|
|
||||||
<?php endif ?>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
name="<?= $field->getName() ?>"
|
|
||||||
id="<?= $field->getId() ?>"
|
|
||||||
value="<?= e($field->value) ?>"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<script type="text/template" data-empty-record-template>
|
|
||||||
<tr class="no-data" data-no-record-data>
|
|
||||||
<td colspan="100" class="nolink">
|
|
||||||
<p class="no-data">
|
|
||||||
No records added
|
|
||||||
</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script type="text/template" data-record-template>
|
|
||||||
<tr data-record-key="{{ key }}">
|
|
||||||
<td style="width: 10px">
|
|
||||||
<a href="javascript:;" data-multivalue-remove-record>
|
|
||||||
<span class="list-badge badge-default">
|
|
||||||
<i class="icon-minus"></i>
|
|
||||||
</span>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{value}}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
subcondition:
|
|
||||||
label: Attribute
|
|
||||||
span: auto
|
|
||||||
type: dropdown
|
|
||||||
|
|
||||||
operator:
|
|
||||||
label: Operator
|
|
||||||
span: auto
|
|
||||||
type: dropdown
|
|
||||||
dependsOn: subcondition
|
|
||||||
|
|
||||||
value:
|
|
||||||
label: Value
|
|
||||||
dependsOn: [subcondition, operator]
|
|
||||||
type: partial
|
|
||||||
path: field_value
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
{
|
|
||||||
"name": "rainlab/notify-plugin",
|
|
||||||
"type": "october-plugin",
|
|
||||||
"description": "Notify plugin for October CMS",
|
|
||||||
"homepage": "https://octobercms.com/plugin/rainlab-pages",
|
|
||||||
"keywords": ["october", "octobercms", "pages"],
|
|
||||||
"license": "MIT",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Alexey Bobkov",
|
|
||||||
"email": "aleksey.bobkov@gmail.com",
|
|
||||||
"role": "Co-founder"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Samuel Georges",
|
|
||||||
"email": "daftspunky@gmail.com",
|
|
||||||
"role": "Co-founder"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": ">=5.5.9",
|
|
||||||
"composer/installers": "~1.0"
|
|
||||||
},
|
|
||||||
"minimum-stability": "dev"
|
|
||||||
}
|
|
||||||
|
|
@ -1,137 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Controllers;
|
|
||||||
|
|
||||||
use Str;
|
|
||||||
use Lang;
|
|
||||||
use File;
|
|
||||||
use Mail;
|
|
||||||
use Flash;
|
|
||||||
use Backend;
|
|
||||||
use Redirect;
|
|
||||||
use BackendMenu;
|
|
||||||
use Backend\Classes\Controller;
|
|
||||||
use RainLab\Notify\Models\NotificationRule;
|
|
||||||
use System\Classes\SettingsManager;
|
|
||||||
use RainLab\Notify\Classes\EventBase;
|
|
||||||
use ApplicationException;
|
|
||||||
use Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification rules controller
|
|
||||||
*
|
|
||||||
* @package rainlab\notify
|
|
||||||
* @author Alexey Bobkov, Samuel Georges
|
|
||||||
*/
|
|
||||||
class Notifications extends Controller
|
|
||||||
{
|
|
||||||
public $implement = [
|
|
||||||
\Backend\Behaviors\FormController::class,
|
|
||||||
\Backend\Behaviors\ListController::class
|
|
||||||
];
|
|
||||||
|
|
||||||
public $requiredPermissions = ['rainlab.notify.manage_notifications'];
|
|
||||||
|
|
||||||
public $listConfig = 'config_list.yaml';
|
|
||||||
public $formConfig = 'config_form.yaml';
|
|
||||||
|
|
||||||
public $eventAlias;
|
|
||||||
protected $eventClass;
|
|
||||||
|
|
||||||
public function __construct()
|
|
||||||
{
|
|
||||||
parent::__construct();
|
|
||||||
|
|
||||||
BackendMenu::setContext('October.System', 'system', 'settings');
|
|
||||||
SettingsManager::setContext('RainLab.Notify', 'notifications');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function index()
|
|
||||||
{
|
|
||||||
NotificationRule::syncAll();
|
|
||||||
$this->asExtension('ListController')->index();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function create($eventAlias = null)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (!$eventAlias) {
|
|
||||||
throw new ApplicationException('Missing a rule code');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->eventAlias = $eventAlias;
|
|
||||||
$this->bodyClass = 'compact-container breadcrumb-fancy';
|
|
||||||
$this->asExtension('FormController')->create();
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function update($recordId = null, $context = null)
|
|
||||||
{
|
|
||||||
$this->bodyClass = 'compact-container breadcrumb-fancy';
|
|
||||||
$this->asExtension('FormController')->update($recordId, $context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function formExtendModel($model)
|
|
||||||
{
|
|
||||||
if (!$model->exists) {
|
|
||||||
$model->applyEventClass($this->getEventClass());
|
|
||||||
$model->name = $model->getEventDescription();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $model;
|
|
||||||
}
|
|
||||||
|
|
||||||
// public function formBeforeSave($model)
|
|
||||||
// {
|
|
||||||
// $model->is_custom = 1;
|
|
||||||
// }
|
|
||||||
|
|
||||||
public function index_onLoadRuleGroupForm()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$groups = EventBase::findEventGroups();
|
|
||||||
$this->vars['eventGroups'] = $groups;
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makePartial('add_rule_group_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This handler requires the group code passed from `onLoadRuleGroupForm`
|
|
||||||
*/
|
|
||||||
public function index_onLoadRuleEventForm()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if (!$code = post('code')) {
|
|
||||||
throw new ApplicationException('Missing event group code');
|
|
||||||
}
|
|
||||||
|
|
||||||
$events = EventBase::findEventsByGroup($code);
|
|
||||||
$this->vars['events'] = $events;
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makePartial('add_rule_event_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getEventClass()
|
|
||||||
{
|
|
||||||
$alias = post('event_alias', $this->eventAlias);
|
|
||||||
|
|
||||||
if ($this->eventClass !== null) {
|
|
||||||
return $this->eventClass;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$event = EventBase::findEventByIdentifier($alias)) {
|
|
||||||
throw new ApplicationException('Unable to find event with alias: '. $alias);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->eventClass = get_class($event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
<?= Form::open(['id' => 'addRuleEventForm']) ?>
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
|
||||||
<h4 class="modal-title"><?= e(trans('rainlab.notify::lang.notifications.add_notification_rule')) ?></h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<?php if ($this->fatalError): ?>
|
|
||||||
<p class="flash-message static error"><?= $fatalError ?></p>
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="list-preview">
|
|
||||||
<div class="control-simplelist is-selectable is-scrollable size-large" data-control="simplelist">
|
|
||||||
<ul>
|
|
||||||
<?php foreach ($events as $event): ?>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a href="<?= Backend::url('rainlab/notify/notifications/create/'.$event->getEventIdentifier()) ?>">
|
|
||||||
<h5 class="heading"><?= e(trans($event->getEventName())) ?></h5>
|
|
||||||
<p class="description"><?= e(trans($event->getEventDescription())) ?></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<?php endforeach ?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<?= Form::close() ?>
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?= Form::open(['id' => 'addRuleGroupForm']) ?>
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
|
||||||
<h4 class="modal-title"><?= e(trans('rainlab.notify::lang.notifications.add_notification_rule')) ?></h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<?php if ($this->fatalError): ?>
|
|
||||||
<p class="flash-message static error"><?= $fatalError ?></p>
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="list-preview">
|
|
||||||
<div class="control-simplelist is-selectable-box is-scrollable size-large" data-control="simplelist">
|
|
||||||
<ul>
|
|
||||||
<?php foreach ($eventGroups as $code => $group): ?>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
data-control="popup"
|
|
||||||
data-handler="onLoadRuleEventForm"
|
|
||||||
data-request-data="code: '<?= e($code) ?>'"
|
|
||||||
data-dismiss="popup"
|
|
||||||
>
|
|
||||||
<div class="box">
|
|
||||||
<div class="image"><i class="<?= e(array_get($group, 'icon')) ?>"></i></div>
|
|
||||||
</div>
|
|
||||||
<h5 class="heading"><?= e(trans(array_get($group, 'label'))) ?></h5>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<?php endforeach ?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<?= Form::close() ?>
|
|
||||||
|
|
@ -1,49 +0,0 @@
|
||||||
<?php
|
|
||||||
$isCreate = $this->formGetContext() == 'create';
|
|
||||||
$pageUrl = isset($pageUrl) ? $pageUrl : null;
|
|
||||||
?>
|
|
||||||
<div class="form-buttons loading-indicator-container">
|
|
||||||
|
|
||||||
<!-- Save -->
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
class="btn btn-primary oc-icon-check save"
|
|
||||||
data-request="onSave"
|
|
||||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>"
|
|
||||||
data-request-before-update="$(this).trigger('unchange.oc.changeMonitor')"
|
|
||||||
<?php if (!$isCreate): ?>data-request-data="redirect:0"<?php endif ?>
|
|
||||||
data-hotkey="ctrl+s, cmd+s">
|
|
||||||
<?= e(trans('backend::lang.form.save')) ?>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<?php if (!$isCreate): ?>
|
|
||||||
<!-- Save and Close -->
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
class="btn btn-primary oc-icon-check save"
|
|
||||||
data-request-before-update="$(this).trigger('unchange.oc.changeMonitor')"
|
|
||||||
data-request="onSave"
|
|
||||||
data-load-indicator="<?= e(trans('backend::lang.form.saving')) ?>">
|
|
||||||
<?= e(trans('backend::lang.form.save_and_close')) ?>
|
|
||||||
</a>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<!-- Preview -->
|
|
||||||
<a
|
|
||||||
href="<?= URL::to($pageUrl) ?>"
|
|
||||||
target="_blank"
|
|
||||||
class="btn btn-primary oc-icon-crosshairs <?php if (!false): ?>hide<?php endif ?>"
|
|
||||||
data-control="preview-button">
|
|
||||||
<?= e(trans('backend::lang.form.preview_title')) ?>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<?php if (!$isCreate): ?>
|
|
||||||
<!-- Delete -->
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default empty oc-icon-trash-o"
|
|
||||||
data-request="onDelete"
|
|
||||||
data-request-confirm="Delete this notification rule?"
|
|
||||||
data-control="delete-button"></button>
|
|
||||||
<?php endif ?>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
<div data-control="toolbar">
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
data-control="popup"
|
|
||||||
data-handler="onLoadRuleGroupForm"
|
|
||||||
class="btn btn-primary oc-icon-plus">
|
|
||||||
New notification rule
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Form Behavior Config
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
name: rainlab.notify::lang.notifications.notification_rule
|
|
||||||
form: $/rainlab/notify/models/notificationrule/fields.yaml
|
|
||||||
modelClass: RainLab\Notify\Models\NotificationRule
|
|
||||||
defaultRedirect: rainlab/notify/notifications
|
|
||||||
|
|
||||||
create:
|
|
||||||
redirect: rainlab/notify/notifications/update/:id
|
|
||||||
redirectClose: rainlab/notify/notifications
|
|
||||||
|
|
||||||
update:
|
|
||||||
redirect: rainlab/notify/notifications
|
|
||||||
redirectClose: rainlab/notify/notifications
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# List Behavior Config
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
title: rainlab.notify::lang.notifications.menu_label
|
|
||||||
list: $/rainlab/notify/models/notificationrule/columns.yaml
|
|
||||||
modelClass: RainLab\Notify\Models\NotificationRule
|
|
||||||
recordUrl: rainlab/notify/notifications/update/:id
|
|
||||||
noRecordsMessage: backend::lang.list.no_records
|
|
||||||
recordsPerPage: 30
|
|
||||||
showSetup: true
|
|
||||||
showCheckboxes: true
|
|
||||||
defaultSort:
|
|
||||||
column: count
|
|
||||||
direction: desc
|
|
||||||
|
|
||||||
toolbar:
|
|
||||||
buttons: list_toolbar
|
|
||||||
search:
|
|
||||||
prompt: backend::lang.list.search_prompt
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php Block::put('breadcrumb') ?>
|
|
||||||
<ul>
|
|
||||||
<li><a href="<?= Backend::url('rainlab/notify/notifications') ?>"><?= e(trans('rainlab.notify::lang.notifications.menu_label')) ?></a></li>
|
|
||||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
|
||||||
</ul>
|
|
||||||
<?php Block::endPut() ?>
|
|
||||||
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
|
|
||||||
<div class="layout fancy-layout">
|
|
||||||
<?= Form::open([
|
|
||||||
'class' => 'layout',
|
|
||||||
'data-change-monitor' => 'true',
|
|
||||||
'data-window-close-confirm' => e(trans('rainlab.notify::lang.notifications.close_confirm')),
|
|
||||||
'id' => 'post-form'
|
|
||||||
]) ?>
|
|
||||||
<input type="hidden" name="event_alias" value="<?= $this->eventAlias ?>" />
|
|
||||||
|
|
||||||
<?= $this->formRender() ?>
|
|
||||||
|
|
||||||
<?= Form::close() ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="padded-container">
|
|
||||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
|
||||||
<p><a href="<?= Backend::url('rainlab/notify/notifications') ?>" class="btn btn-default"><?= e(trans('rainlab.notify::lang.notifications.return')) ?></a></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
<?php Block::put('breadcrumb') ?>
|
|
||||||
<ul>
|
|
||||||
<li><a href="<?= Backend::url('rainlab/notify/notifications') ?>"><?= e(trans('rainlab.notify::lang.notifications.menu_label')) ?></a></li>
|
|
||||||
<li><?= e(trans($this->pageTitle)) ?></li>
|
|
||||||
</ul>
|
|
||||||
<?php Block::endPut() ?>
|
|
||||||
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
|
|
||||||
<div class="layout fancy-layout">
|
|
||||||
<?= Form::open([
|
|
||||||
'class' => 'layout',
|
|
||||||
'data-change-monitor' => 'true',
|
|
||||||
'data-window-close-confirm' => e(trans('rainlab.notify::lang.notifications.close_confirm')),
|
|
||||||
'id' => 'post-form'
|
|
||||||
]) ?>
|
|
||||||
|
|
||||||
<?= $this->formRender() ?>
|
|
||||||
|
|
||||||
<?= Form::close() ?>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="padded-container">
|
|
||||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
|
||||||
<p><a href="<?= Backend::url('rainlab/notify/notifications') ?>" class="btn btn-default"><?= e(trans('rainlab.notify::lang.notifications.return')) ?></a></p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
@ -1,350 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\FormWidgets;
|
|
||||||
|
|
||||||
use Backend\Classes\FormField;
|
|
||||||
use Backend\Classes\FormWidgetBase;
|
|
||||||
use RainLab\Notify\Classes\ActionBase;
|
|
||||||
use ApplicationException;
|
|
||||||
use ValidationException;
|
|
||||||
use Exception;
|
|
||||||
use Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Action builder
|
|
||||||
*/
|
|
||||||
class ActionBuilder extends FormWidgetBase
|
|
||||||
{
|
|
||||||
use \Backend\Traits\FormModelWidget;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Configurable properties
|
|
||||||
//
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Object properties
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var mixed Actions cache
|
|
||||||
*/
|
|
||||||
protected $actionsCache = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Backend\Widgets\Form
|
|
||||||
*/
|
|
||||||
protected $actionFormWidget;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function init()
|
|
||||||
{
|
|
||||||
// $this->fillFromConfig([
|
|
||||||
// ]);
|
|
||||||
|
|
||||||
if ($widget = $this->makeActionFormWidget()) {
|
|
||||||
$widget->bindToController();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
protected function loadAssets()
|
|
||||||
{
|
|
||||||
$this->addJs('js/actions.js', 'RainLab.Notify');
|
|
||||||
$this->addCss('css/actions.css', 'RainLab.Notify');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
$this->prepareVars();
|
|
||||||
|
|
||||||
return $this->makePartial('actions_container');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the list data
|
|
||||||
*/
|
|
||||||
public function prepareVars()
|
|
||||||
{
|
|
||||||
$this->vars['formModel'] = $this->model;
|
|
||||||
$this->vars['actions'] = $this->getActions();
|
|
||||||
$this->vars['actionFormWidget'] = $this->actionFormWidget;
|
|
||||||
$this->vars['availableTags'] = $this->getAvailableTags();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function getSaveValue($value)
|
|
||||||
{
|
|
||||||
$this->model->bindEvent('model.afterSave', function() {
|
|
||||||
$this->processSave();
|
|
||||||
});
|
|
||||||
|
|
||||||
return FormField::NO_SAVE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function processSave()
|
|
||||||
{
|
|
||||||
$cache = $this->getCacheActionDataPayload();
|
|
||||||
|
|
||||||
foreach ($cache as $id => $data) {
|
|
||||||
$action = $this->findActionObj($id);
|
|
||||||
|
|
||||||
if ($attributes = $this->getCacheActionAttributes($action)) {
|
|
||||||
$action->fill($attributes);
|
|
||||||
}
|
|
||||||
|
|
||||||
$action->save(null, $this->sessionKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// AJAX
|
|
||||||
//
|
|
||||||
|
|
||||||
public function onLoadCreateActionForm()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$actions = ActionBase::findActions();
|
|
||||||
$this->vars['actions'] = $actions;
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makePartial('create_action_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onSaveAction()
|
|
||||||
{
|
|
||||||
$this->restoreCacheActionDataPayload();
|
|
||||||
|
|
||||||
$action = $this->findActionObj();
|
|
||||||
|
|
||||||
$data = post('Action', []);
|
|
||||||
$action->fill($data);
|
|
||||||
$action->validate();
|
|
||||||
$action->action_text = $action->getActionObject()->getText();
|
|
||||||
|
|
||||||
$action->applyCustomData();
|
|
||||||
|
|
||||||
$this->setCacheActionData($action);
|
|
||||||
|
|
||||||
return $this->renderActions($action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onLoadActionSetup()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$action = $this->findActionObj();
|
|
||||||
|
|
||||||
$data = $this->getCacheActionAttributes($action);
|
|
||||||
|
|
||||||
$this->actionFormWidget->setFormValues($data);
|
|
||||||
|
|
||||||
$this->prepareVars();
|
|
||||||
$this->vars['action'] = $action;
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makePartial('action_settings_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onCreateAction()
|
|
||||||
{
|
|
||||||
if (!$className = post('action_class')) {
|
|
||||||
throw new ApplicationException('Please specify an action');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->restoreCacheActionDataPayload();
|
|
||||||
|
|
||||||
$newAction = $this->getRelationModel();
|
|
||||||
$newAction->class_name = $className;
|
|
||||||
$newAction->save();
|
|
||||||
|
|
||||||
$this->model->rule_actions()->add($newAction, post('_session_key'));
|
|
||||||
|
|
||||||
$this->vars['newActionId'] = $newAction->id;
|
|
||||||
|
|
||||||
return $this->renderActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onDeleteAction()
|
|
||||||
{
|
|
||||||
$action = $this->findActionObj();
|
|
||||||
|
|
||||||
$this->model->rule_actions()->remove($action, post('_session_key'));
|
|
||||||
|
|
||||||
return $this->renderActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onCancelActionSettings()
|
|
||||||
{
|
|
||||||
$action = $this->findActionObj(post('new_action_id'));
|
|
||||||
|
|
||||||
$action->delete();
|
|
||||||
|
|
||||||
return $this->renderActions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Postback deferring
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getCacheActionAttributes($action)
|
|
||||||
{
|
|
||||||
return array_get($this->getCacheActionData($action), 'attributes');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheActionTitle($action)
|
|
||||||
{
|
|
||||||
return array_get($this->getCacheActionData($action), 'title');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheActionText($action)
|
|
||||||
{
|
|
||||||
return array_get($this->getCacheActionData($action), 'text');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheActionData($action, $default = null)
|
|
||||||
{
|
|
||||||
$cache = post('action_data', []);
|
|
||||||
|
|
||||||
if (is_array($cache) && array_key_exists($action->id, $cache)) {
|
|
||||||
return json_decode($cache[$action->id], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($default === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makeCacheActionData($action);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function makeCacheActionData($action)
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'attributes' => $action->config_data,
|
|
||||||
'title' => $action->getTitle(),
|
|
||||||
'text' => $action->getText(),
|
|
||||||
];
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCacheActionData($action)
|
|
||||||
{
|
|
||||||
$cache = post('action_data', []);
|
|
||||||
|
|
||||||
$cache[$action->id] = json_encode($this->makeCacheActionData($action));
|
|
||||||
|
|
||||||
Request::merge([
|
|
||||||
'action_data' => $cache
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function restoreCacheActionDataPayload()
|
|
||||||
{
|
|
||||||
Request::merge([
|
|
||||||
'action_data' => json_decode(post('current_action_data'), true)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheActionDataPayload()
|
|
||||||
{
|
|
||||||
return post('action_data', []);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Helpers
|
|
||||||
//
|
|
||||||
|
|
||||||
protected function getAvailableTags()
|
|
||||||
{
|
|
||||||
$tags = [];
|
|
||||||
|
|
||||||
if ($this->model->methodExists('defineParams')) {
|
|
||||||
$params = $this->model->defineParams();
|
|
||||||
|
|
||||||
foreach ($params as $param => $definition) {
|
|
||||||
$tags[$param] = array_get($definition, 'label');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $tags;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the primary rule actions container
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function renderActions()
|
|
||||||
{
|
|
||||||
$this->prepareVars();
|
|
||||||
|
|
||||||
return [
|
|
||||||
'#'.$this->getId() => $this->makePartial('actions')
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function makeActionFormWidget()
|
|
||||||
{
|
|
||||||
if ($this->actionFormWidget !== null) {
|
|
||||||
return $this->actionFormWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$model = $this->findActionObj(null, false)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$model->hasFieldConfig()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = $model->getFieldConfig();
|
|
||||||
$config->model = $model;
|
|
||||||
$config->alias = $this->alias . 'Form';
|
|
||||||
$config->arrayName = 'Action';
|
|
||||||
|
|
||||||
$widget = $this->makeWidget('Backend\Widgets\Form', $config);
|
|
||||||
|
|
||||||
return $this->actionFormWidget = $widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getActions()
|
|
||||||
{
|
|
||||||
if ($this->actionsCache !== false) {
|
|
||||||
return $this->actionsCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
$relationObject = $this->getRelationObject();
|
|
||||||
$actions = $relationObject->withDeferred($this->sessionKey)->get();
|
|
||||||
|
|
||||||
return $this->actionsCache = $actions ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findActionObj($actionId = null, $throw = true)
|
|
||||||
{
|
|
||||||
$actionId = $actionId ? $actionId : post('current_action_id');
|
|
||||||
|
|
||||||
$action = null;
|
|
||||||
|
|
||||||
if (strlen($actionId)) {
|
|
||||||
$action = $this->getRelationModel()->find($actionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($throw && !$action) {
|
|
||||||
throw new ApplicationException('Action not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $action;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,454 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\FormWidgets;
|
|
||||||
|
|
||||||
use Backend\Classes\FormField;
|
|
||||||
use Backend\Classes\FormWidgetBase;
|
|
||||||
use RainLab\Notify\Classes\ConditionBase;
|
|
||||||
use ApplicationException;
|
|
||||||
use ValidationException;
|
|
||||||
use Exception;
|
|
||||||
use Request;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Condition builder
|
|
||||||
*/
|
|
||||||
class ConditionBuilder extends FormWidgetBase
|
|
||||||
{
|
|
||||||
use \Backend\Traits\FormModelWidget;
|
|
||||||
use \Backend\Traits\CollapsableWidget;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Configurable properties
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string Rule type.
|
|
||||||
*/
|
|
||||||
public $conditionsRuleType = ConditionBase::TYPE_ANY;
|
|
||||||
|
|
||||||
//
|
|
||||||
// Object properties
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public $defaultAlias = 'ruleconditions';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var mixed Root condition
|
|
||||||
*/
|
|
||||||
protected $conditionsRoot = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var Backend\Widgets\Form
|
|
||||||
*/
|
|
||||||
protected $conditionFormWidget;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function init()
|
|
||||||
{
|
|
||||||
$this->fillFromConfig([
|
|
||||||
'conditionsRuleType',
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($widget = $this->makeConditionFormWidget()) {
|
|
||||||
$widget->bindToController();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->initRootCondition();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
protected function loadAssets()
|
|
||||||
{
|
|
||||||
$this->addJs('js/conditions.js', 'RainLab.Notify');
|
|
||||||
$this->addJs('js/conditions.multivalue.js', 'RainLab.Notify');
|
|
||||||
$this->addCss('css/conditions.css', 'RainLab.Notify');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
public function render()
|
|
||||||
{
|
|
||||||
$this->prepareVars();
|
|
||||||
|
|
||||||
return $this->makePartial('conditions_container');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Prepares the list data
|
|
||||||
*/
|
|
||||||
public function prepareVars()
|
|
||||||
{
|
|
||||||
$this->vars['rootCondition'] = $this->getConditionsRoot();
|
|
||||||
$this->vars['conditionFormWidget'] = $this->conditionFormWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initRootCondition()
|
|
||||||
{
|
|
||||||
if ($this->getConditionsRoot()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$relationObject = $this->getRelationObject();
|
|
||||||
|
|
||||||
$rootRule = $this->getRelationModel();
|
|
||||||
$rootRule->rule_host_type = $this->conditionsRuleType;
|
|
||||||
$rootRule->class_name = $rootRule->getRootConditionClass();
|
|
||||||
$rootRule->save();
|
|
||||||
|
|
||||||
$relationObject->add($rootRule, $this->sessionKey);
|
|
||||||
|
|
||||||
$this->conditionsRoot = $rootRule;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isRootCondition($condition)
|
|
||||||
{
|
|
||||||
if ($root = $this->getConditionsRoot()) {
|
|
||||||
return $condition->id === $root->id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConditionsRoot()
|
|
||||||
{
|
|
||||||
if ($this->conditionsRoot !== false) {
|
|
||||||
return $this->conditionsRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
$relationObject = $this->getRelationObject();
|
|
||||||
$rootCondition = $relationObject->withDeferred($this->sessionKey)->first();
|
|
||||||
|
|
||||||
return $this->conditionsRoot = $rootCondition ?: null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
public function getSaveValue($value)
|
|
||||||
{
|
|
||||||
$this->model->bindEvent('model.afterSave', function() {
|
|
||||||
$this->processSave();
|
|
||||||
});
|
|
||||||
|
|
||||||
return FormField::NO_SAVE_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function processSave()
|
|
||||||
{
|
|
||||||
$cache = $this->getCacheConditionDataPayload();
|
|
||||||
|
|
||||||
foreach ($cache as $id => $data) {
|
|
||||||
$condition = $this->findConditionObj($id);
|
|
||||||
$attributes = $this->getCacheConditionAttributes($condition);
|
|
||||||
$condition->fill($attributes);
|
|
||||||
$condition->save(null, $this->sessionKey.'_'.$condition->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// AJAX
|
|
||||||
//
|
|
||||||
|
|
||||||
public function onLoadConditionSetup()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$condition = $this->findConditionObj();
|
|
||||||
|
|
||||||
$this->prepareVars();
|
|
||||||
|
|
||||||
$this->vars['condition'] = $condition;
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makePartial('condition_settings_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onLoadCreateChildCondition()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$condition = $this->findConditionObj();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up parents
|
|
||||||
*/
|
|
||||||
$parents = [$condition->id];
|
|
||||||
$parentsArray = post('condition_parent_id', []);
|
|
||||||
$currentId = $condition->id;
|
|
||||||
|
|
||||||
while (array_key_exists($currentId, $parentsArray) && $parentsArray[$currentId]) {
|
|
||||||
$parents[] = $currentId = $parentsArray[$currentId];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Custom rules provided by model
|
|
||||||
*/
|
|
||||||
$extraRules = [];
|
|
||||||
if ($this->model->methodExists('getExtraConditionRules')) {
|
|
||||||
$extraRules = $this->model->getExtraConditionRules();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Look up conditions
|
|
||||||
*/
|
|
||||||
$options = $condition->getChildOptions([
|
|
||||||
'ruleType' => $this->conditionsRuleType,
|
|
||||||
'parentIds' => $parents,
|
|
||||||
'extraRules' => $extraRules
|
|
||||||
]);
|
|
||||||
|
|
||||||
$this->prepareVars();
|
|
||||||
$this->vars['condition'] = $condition;
|
|
||||||
$this->vars['options'] = $options;
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
$this->handleError($ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makePartial('create_child_form');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onSaveCondition()
|
|
||||||
{
|
|
||||||
$this->restoreCacheConditionDataPayload();
|
|
||||||
|
|
||||||
$condition = $this->findConditionObj();
|
|
||||||
|
|
||||||
$data = post('Condition', []);
|
|
||||||
$condition->fill($data);
|
|
||||||
$condition->validate();
|
|
||||||
$condition->condition_text = $condition->getConditionObject()->getText();
|
|
||||||
|
|
||||||
$condition->applyCustomData();
|
|
||||||
|
|
||||||
$this->setCacheConditionData($condition);
|
|
||||||
|
|
||||||
return $this->renderConditions($condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onCreateCondition()
|
|
||||||
{
|
|
||||||
if (!$className = post('condition_class')) {
|
|
||||||
throw new ValidationException(['condition_class' => 'Please specify a condition']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->restoreCacheConditionDataPayload();
|
|
||||||
|
|
||||||
$subcondition = null;
|
|
||||||
|
|
||||||
$parts = explode(':', $className);
|
|
||||||
if (count($parts) > 1) {
|
|
||||||
$subcondition = $parts[1];
|
|
||||||
$className = $parts[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
$parentCondition = $this->findConditionObj();
|
|
||||||
|
|
||||||
$newCondition = $this->getRelationModel();
|
|
||||||
$newCondition->class_name = $className;
|
|
||||||
$newCondition->rule_host_type = $parentCondition->rule_host_type;
|
|
||||||
|
|
||||||
if ($subcondition) {
|
|
||||||
$newCondition->subcondition = $subcondition;
|
|
||||||
}
|
|
||||||
|
|
||||||
$newCondition->save();
|
|
||||||
|
|
||||||
$parentCondition->children()->add($newCondition, post('_session_key').'_'.$parentCondition->id);
|
|
||||||
|
|
||||||
$this->vars['newConditionId'] = $newCondition->id;
|
|
||||||
|
|
||||||
return $this->renderConditions($parentCondition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onDeleteCondition()
|
|
||||||
{
|
|
||||||
$parentCondition = null;
|
|
||||||
|
|
||||||
$condition = $this->findConditionObj();
|
|
||||||
|
|
||||||
if ($parentId = $this->getParentIdFromCondition($condition)) {
|
|
||||||
$parentCondition = $this->findConditionObj($parentId);
|
|
||||||
|
|
||||||
if ($parentCondition) {
|
|
||||||
$parentCondition->children()->remove($condition, post('_session_key').'_'.$parentCondition->id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->renderConditions($parentCondition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function onCancelConditionSettings()
|
|
||||||
{
|
|
||||||
$condition = $this->findConditionObj(post('new_condition_id'));
|
|
||||||
|
|
||||||
$condition->delete();
|
|
||||||
|
|
||||||
return $this->renderConditions();
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Postback deferring
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getCacheConditionAttributes($condition)
|
|
||||||
{
|
|
||||||
return array_get($this->getCacheConditionData($condition), 'attributes');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheConditionText($condition)
|
|
||||||
{
|
|
||||||
return array_get($this->getCacheConditionData($condition), 'text');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheConditionJoinText($condition)
|
|
||||||
{
|
|
||||||
return array_get($this->getCacheConditionData($condition), 'joinText');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheConditionData($condition, $default = null)
|
|
||||||
{
|
|
||||||
$cache = post('condition_data', []);
|
|
||||||
|
|
||||||
if (is_array($cache) && array_key_exists($condition->id, $cache)) {
|
|
||||||
return json_decode($cache[$condition->id], true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($default === false) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->makeCacheConditionData($condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function makeCacheConditionData($condition)
|
|
||||||
{
|
|
||||||
$data = [
|
|
||||||
'attributes' => $condition->config_data,
|
|
||||||
'text' => $condition->getText()
|
|
||||||
];
|
|
||||||
|
|
||||||
if ($condition->isCompound()) {
|
|
||||||
$data['joinText'] = $condition->getJoinText();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setCacheConditionData($condition)
|
|
||||||
{
|
|
||||||
$cache = post('condition_data', []);
|
|
||||||
|
|
||||||
$cache[$condition->id] = json_encode($this->makeCacheConditionData($condition));
|
|
||||||
|
|
||||||
Request::merge([
|
|
||||||
'condition_data' => $cache
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function restoreCacheConditionDataPayload()
|
|
||||||
{
|
|
||||||
Request::merge([
|
|
||||||
'condition_data' => json_decode(post('current_condition_data', []), true)
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getCacheConditionDataPayload()
|
|
||||||
{
|
|
||||||
return post('condition_data');
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Helpers
|
|
||||||
//
|
|
||||||
|
|
||||||
public function getParentIdFromCondition($condition)
|
|
||||||
{
|
|
||||||
if ($parentId = post('current_parent_id')) {
|
|
||||||
return $parentId;
|
|
||||||
}
|
|
||||||
|
|
||||||
$parentIds = post('condition_parent_id', []);
|
|
||||||
|
|
||||||
if (isset($parentIds[$condition->id])) {
|
|
||||||
return $parentIds[$condition->id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the primary rule conditions container
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function renderConditions($currentCondition = null)
|
|
||||||
{
|
|
||||||
if ($currentCondition && $this->isRootCondition($currentCondition)) {
|
|
||||||
$condition = $currentCondition;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$condition = $this->getConditionsRoot();
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'#'.$this->getId() => $this->makePartial('conditions', ['condition' => $condition])
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function makeConditionFormWidget()
|
|
||||||
{
|
|
||||||
if ($this->conditionFormWidget !== null) {
|
|
||||||
return $this->conditionFormWidget;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$model = $this->findConditionObj(null, false)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
$config = $model->getFieldConfig();
|
|
||||||
$config->model = $model;
|
|
||||||
$config->alias = $this->alias . 'Form';
|
|
||||||
$config->arrayName = 'Condition';
|
|
||||||
|
|
||||||
$widget = $this->makeWidget('Backend\Widgets\Form', $config);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set form values based on postback or cached attributes
|
|
||||||
*/
|
|
||||||
if (!$data = post('Condition')) {
|
|
||||||
$data = $this->getCacheConditionAttributes($model);
|
|
||||||
}
|
|
||||||
|
|
||||||
$widget->setFormValues($data);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Allow conditions to register their own widgets
|
|
||||||
*/
|
|
||||||
$model->onPreRender($this->controller, $this);
|
|
||||||
|
|
||||||
return $this->conditionFormWidget = $widget;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function findConditionObj($conditionId = null, $throw = true)
|
|
||||||
{
|
|
||||||
$conditionId = $conditionId ? $conditionId : post('current_condition_id');
|
|
||||||
|
|
||||||
$condition = null;
|
|
||||||
|
|
||||||
if (strlen($conditionId)) {
|
|
||||||
$condition = $this->getRelationModel()->find($conditionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($throw && !$condition) {
|
|
||||||
throw new ApplicationException('Condition not found');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $condition;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,227 +0,0 @@
|
||||||
.action-set {
|
|
||||||
margin-top: 10px;
|
|
||||||
}
|
|
||||||
.action-set ol {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
.action-set ol > li {
|
|
||||||
-webkit-transition: width 1s;
|
|
||||||
transition: width 1s;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: normal;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > a,
|
|
||||||
.action-set ol > li > div div.content {
|
|
||||||
color: #2b3e50;
|
|
||||||
padding: 10px 45px 10px 91px;
|
|
||||||
display: block;
|
|
||||||
line-height: 150%;
|
|
||||||
text-decoration: none;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div span.icon {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
left: 20px;
|
|
||||||
top: 15px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 22px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div span.icon > i {
|
|
||||||
line-height: 22px;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 22px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover,
|
|
||||||
.action-set ol > li > div.popover-highlight {
|
|
||||||
background-color: #4ea5e0 !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover span.icon > i,
|
|
||||||
.action-set ol > li > div.popover-highlight span.icon > i {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover > a,
|
|
||||||
.action-set ol > li > div.popover-highlight > a {
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover:before,
|
|
||||||
.action-set ol > li > div.popover-highlight:before {
|
|
||||||
background-position: 0px -80px;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover:after,
|
|
||||||
.action-set ol > li > div.popover-highlight:after {
|
|
||||||
top: 0 !important;
|
|
||||||
bottom: 0 !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover span,
|
|
||||||
.action-set ol > li > div.popover-highlight span {
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):hover span.drag-handle,
|
|
||||||
.action-set ol > li > div.popover-highlight span.drag-handle {
|
|
||||||
cursor: move;
|
|
||||||
opacity: 1;
|
|
||||||
filter: alpha(opacity=100);
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):active {
|
|
||||||
background-color: #3498db !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:not(.no-hover):active > a {
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div span.icon:first-child {
|
|
||||||
font-size: 11px;
|
|
||||||
color: #ccc;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div span.icon:first-child > i {
|
|
||||||
color: #ccc;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div span.icon:last-child {
|
|
||||||
left: 52px;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div span.comment {
|
|
||||||
display: block;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #95a5a6;
|
|
||||||
font-size: 13px;
|
|
||||||
margin-top: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > .subpanel {
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 200;
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > ul.submenu {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
z-index: 200;
|
|
||||||
height: 100%;
|
|
||||||
display: none;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > ul.submenu li {
|
|
||||||
font-size: 12px;
|
|
||||||
height: 100%;
|
|
||||||
display: inline-block;
|
|
||||||
background: #2581b8;
|
|
||||||
border-right: 1px solid #328ec8;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > ul.submenu li p {
|
|
||||||
display: table;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > ul.submenu li p a {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 20px;
|
|
||||||
font-size: 13px;
|
|
||||||
-webkit-box-sizing: border-box;
|
|
||||||
-moz-box-sizing: border-box;
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #ffffff;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div > ul.submenu li p a i.control-icon {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div:hover > ul.submenu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div .checkbox {
|
|
||||||
position: absolute;
|
|
||||||
top: -2px;
|
|
||||||
right: 0;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div .checkbox label {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div .checkbox label:before {
|
|
||||||
border-color: #cccccc;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div.popover-highlight {
|
|
||||||
background-color: #4ea5e0 !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div.popover-highlight:before {
|
|
||||||
background-position: 0px -80px;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div.popover-highlight > a {
|
|
||||||
color: #ffffff !important;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div.popover-highlight span {
|
|
||||||
color: #ffffff !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li > div.popover-highlight > ul.submenu,
|
|
||||||
.action-set ol > li > div.popover-highlight > span.drag-handle {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
.action-set ol > li.active > div {
|
|
||||||
background: #dddddd;
|
|
||||||
}
|
|
||||||
.action-set ol > li.active > div:after {
|
|
||||||
position: absolute;
|
|
||||||
width: 4px;
|
|
||||||
left: 0;
|
|
||||||
top: -1px;
|
|
||||||
bottom: -1px;
|
|
||||||
background: #e67e22;
|
|
||||||
display: block;
|
|
||||||
content: ' ';
|
|
||||||
}
|
|
||||||
.action-set ol > li.active > div > span.comment,
|
|
||||||
.action-set ol > li.active > div > span.expand {
|
|
||||||
color: #8f8f8f;
|
|
||||||
}
|
|
||||||
.action-set a.menu-control {
|
|
||||||
display: block;
|
|
||||||
margin: 20px;
|
|
||||||
padding: 13px 15px;
|
|
||||||
border: dotted 2px #ebebeb;
|
|
||||||
color: #bdc3c7;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 600;
|
|
||||||
text-transform: uppercase;
|
|
||||||
border-radius: 5px;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
.action-set a.menu-control:hover,
|
|
||||||
.action-set a.menu-control:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: #4ea5e0;
|
|
||||||
color: #ffffff;
|
|
||||||
border: none;
|
|
||||||
padding: 15px 17px;
|
|
||||||
}
|
|
||||||
.action-set a.menu-control:active {
|
|
||||||
background: #3498db;
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
.action-set a.menu-control i {
|
|
||||||
margin-right: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
/*
|
|
||||||
* Global helpers
|
|
||||||
*/
|
|
||||||
function showActionSettings(id) {
|
|
||||||
var $control = $('[data-action-id='+id+']').closest('[data-control="ruleactions"]')
|
|
||||||
|
|
||||||
$control.ruleActions('onShowNewActionSettings', id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Plugin definition
|
|
||||||
*/
|
|
||||||
+function ($) { "use strict";
|
|
||||||
var Base = $.oc.foundation.base,
|
|
||||||
BaseProto = Base.prototype
|
|
||||||
|
|
||||||
var RuleActions = function (element, options) {
|
|
||||||
this.$el = $(element)
|
|
||||||
this.options = options || {}
|
|
||||||
|
|
||||||
$.oc.foundation.controlUtils.markDisposable(element)
|
|
||||||
Base.call(this)
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.prototype = Object.create(BaseProto)
|
|
||||||
RuleActions.prototype.constructor = RuleActions
|
|
||||||
|
|
||||||
RuleActions.prototype.init = function() {
|
|
||||||
this.$el.on('click', '[data-actions-settings]', this.proxy(this.onShowSettings))
|
|
||||||
this.$el.on('click', '[data-actions-delete]', this.proxy(this.onDeleteAction))
|
|
||||||
this.$el.one('dispose-control', this.proxy(this.dispose))
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.prototype.dispose = function() {
|
|
||||||
this.$el.off('click', '[data-actions-settings]', this.proxy(this.onShowSettings))
|
|
||||||
this.$el.off('click', '[data-actions-delete]', this.proxy(this.onDeleteAction))
|
|
||||||
this.$el.off('dispose-control', this.proxy(this.dispose))
|
|
||||||
this.$el.removeData('oc.ruleActions')
|
|
||||||
|
|
||||||
this.$el = null
|
|
||||||
|
|
||||||
// In some cases options could contain callbacks,
|
|
||||||
// so it's better to clean them up too.
|
|
||||||
this.options = null
|
|
||||||
|
|
||||||
BaseProto.dispose.call(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.prototype.onDeleteAction = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
actionId = getActionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.request(this.options.deleteHandler, {
|
|
||||||
data: { current_action_id: actionId },
|
|
||||||
confirm: 'Do you really want to delete this action?'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.prototype.onShowNewActionSettings = function(actionId) {
|
|
||||||
var $el = $('[data-action-id='+actionId+']')
|
|
||||||
|
|
||||||
// Action does not use settings
|
|
||||||
if ($el.hasClass('no-form')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
$el.popup({
|
|
||||||
handler: this.options.settingsHandler,
|
|
||||||
extraData: { current_action_id: actionId },
|
|
||||||
size: 'giant'
|
|
||||||
})
|
|
||||||
|
|
||||||
// This will not fire on successful save because the target element
|
|
||||||
// is replaced by the time the popup loader has finished to call it
|
|
||||||
$el.one('hide.oc.popup', this.proxy(this.onCancelAction))
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.prototype.onCancelAction = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
actionId = getActionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.request(this.options.cancelHandler, {
|
|
||||||
data: { new_action_id: actionId }
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.prototype.onShowSettings = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
actionId = getActionIdFromElement($el)
|
|
||||||
|
|
||||||
// Action does not use settings
|
|
||||||
if ($el.closest('li.action-item').hasClass('no-form')) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
$el.popup({
|
|
||||||
handler: this.options.settingsHandler,
|
|
||||||
extraData: { current_action_id: actionId },
|
|
||||||
size: 'giant'
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function getActionIdFromElement($el) {
|
|
||||||
var $item = $el.closest('li.action-item')
|
|
||||||
|
|
||||||
return $item.data('action-id')
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleActions.DEFAULTS = {
|
|
||||||
settingsHandler: null,
|
|
||||||
deleteHandler: null,
|
|
||||||
cancelHandler: null,
|
|
||||||
createHandler: null
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUGIN DEFINITION
|
|
||||||
// ============================
|
|
||||||
|
|
||||||
var old = $.fn.ruleActions
|
|
||||||
|
|
||||||
$.fn.ruleActions = function (option) {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 1), items, result
|
|
||||||
|
|
||||||
items = this.each(function () {
|
|
||||||
var $this = $(this)
|
|
||||||
var data = $this.data('oc.ruleActions')
|
|
||||||
var options = $.extend({}, RuleActions.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
|
||||||
if (!data) $this.data('oc.ruleActions', (data = new RuleActions(this, options)))
|
|
||||||
if (typeof option == 'string') result = data[option].apply(data, args)
|
|
||||||
if (typeof result != 'undefined') return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return result ? result : items
|
|
||||||
}
|
|
||||||
|
|
||||||
$.fn.ruleActions.Constructor = RuleActions
|
|
||||||
|
|
||||||
$.fn.ruleActions.noConflict = function () {
|
|
||||||
$.fn.ruleActions = old
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add this only if required
|
|
||||||
$(document).render(function (){
|
|
||||||
$('[data-control="ruleactions"]').ruleActions()
|
|
||||||
})
|
|
||||||
|
|
||||||
}(window.jQuery);
|
|
||||||
|
|
@ -1,273 +0,0 @@
|
||||||
@import "../../../../../../../modules/backend/assets/less/core/boot.less";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Actions
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
@color-actions-item-bg: #ffffff;
|
|
||||||
@color-actions-item-title: #2b3e50;
|
|
||||||
@color-actions-item-comment: #95a5a6;
|
|
||||||
@color-actions-control: #bdc3c7;
|
|
||||||
@color-actions-hover-bg: @highlight-hover-bg;
|
|
||||||
@color-actions-hover-text: @highlight-hover-text;
|
|
||||||
@color-actions-active-bg: @highlight-active-bg;
|
|
||||||
@color-actions-active-text: @highlight-active-text;
|
|
||||||
@color-actions-item-active-comment: #8f8f8f;
|
|
||||||
@color-actions-submenu-text: #ffffff;
|
|
||||||
@color-actions-light-submenu-bg: #2581b8;
|
|
||||||
@color-actions-light-submenu-border: #328ec8;
|
|
||||||
|
|
||||||
.action-set {
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
ol {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
> li {
|
|
||||||
.transition(width 1s);
|
|
||||||
|
|
||||||
> div {
|
|
||||||
font-size: @font-size-base;
|
|
||||||
font-weight: normal;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> a, div.content {
|
|
||||||
color: @color-actions-item-title;
|
|
||||||
padding: 10px 45px 10px 91px;
|
|
||||||
display: block;
|
|
||||||
line-height: 150%;
|
|
||||||
text-decoration: none;
|
|
||||||
.box-sizing(border-box);
|
|
||||||
}
|
|
||||||
|
|
||||||
span.icon {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
width: 22px;
|
|
||||||
height: 22px;
|
|
||||||
left: 20px;
|
|
||||||
top: 15px;
|
|
||||||
text-align: center;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 22px;
|
|
||||||
color: #999;
|
|
||||||
|
|
||||||
> i {
|
|
||||||
line-height: 22px;
|
|
||||||
font-weight: normal;
|
|
||||||
font-size: 22px;
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.no-hover):hover, &.popover-highlight {
|
|
||||||
background-color: @color-actions-hover-bg !important;
|
|
||||||
|
|
||||||
span.icon > i {
|
|
||||||
color: #fff !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: @color-actions-hover-text !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background-position: 0px -80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
top: 0 !important;
|
|
||||||
bottom: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: @color-actions-hover-text !important;
|
|
||||||
|
|
||||||
&.drag-handle {
|
|
||||||
cursor: move;
|
|
||||||
.opacity(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:not(.no-hover):active {
|
|
||||||
background-color: @color-actions-active-bg !important;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: @color-actions-active-text !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
span.icon:first-child {
|
|
||||||
font-size: 11px;
|
|
||||||
color: #ccc;
|
|
||||||
|
|
||||||
> i {
|
|
||||||
color: #ccc;
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
span.icon:last-child {
|
|
||||||
left: 52px;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.comment {
|
|
||||||
display: block;
|
|
||||||
font-weight: 400;
|
|
||||||
color: @color-actions-item-comment;
|
|
||||||
font-size: @font-size-base - 1;
|
|
||||||
margin-top: 2px;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .subpanel {
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 200;
|
|
||||||
padding: 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> ul.submenu {
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style: none;
|
|
||||||
z-index: 200;
|
|
||||||
height: 100%;
|
|
||||||
display: none;
|
|
||||||
margin: 0;
|
|
||||||
font-size: 0;
|
|
||||||
|
|
||||||
li {
|
|
||||||
font-size: @font-size-base - 2;
|
|
||||||
height: 100%;
|
|
||||||
display: inline-block;
|
|
||||||
background: @color-actions-light-submenu-bg;
|
|
||||||
border-right: 1px solid @color-actions-light-submenu-border;
|
|
||||||
|
|
||||||
p {
|
|
||||||
display: table;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
|
|
||||||
a {
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
height: 100%;
|
|
||||||
padding: 0 20px;
|
|
||||||
font-size: @font-size-base - 1;
|
|
||||||
.box-sizing(border-box);
|
|
||||||
color: @color-actions-submenu-text;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
i.control-icon {
|
|
||||||
font-size: 22px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
> ul.submenu {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.checkbox {
|
|
||||||
position: absolute;
|
|
||||||
top: -2px;
|
|
||||||
right: 0;
|
|
||||||
|
|
||||||
label {
|
|
||||||
margin-right: 0;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
border-color: @color-filelist-cb-border;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.popover-highlight {
|
|
||||||
background-color: @color-actions-hover-bg !important;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
background-position: 0px -80px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: @color-actions-hover-text !important;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
color: @color-actions-hover-text !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
> ul.submenu, > span.drag-handle {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
> div {
|
|
||||||
background: @color-list-active;
|
|
||||||
|
|
||||||
&:after {
|
|
||||||
position: absolute;
|
|
||||||
width: 4px;
|
|
||||||
left: 0;
|
|
||||||
top: -1px;
|
|
||||||
bottom: -1px;
|
|
||||||
background: @color-list-active-border;
|
|
||||||
display: block;
|
|
||||||
content: ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
> span.comment, > span.expand {
|
|
||||||
color: @color-actions-item-active-comment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.menu-control {
|
|
||||||
display: block;
|
|
||||||
margin: 20px;
|
|
||||||
padding: 13px 15px;
|
|
||||||
border: dotted 2px #ebebeb;
|
|
||||||
color: #bdc3c7;
|
|
||||||
font-size: @font-size-base - 2;
|
|
||||||
font-weight: 600;
|
|
||||||
text-transform: uppercase;
|
|
||||||
border-radius: 5px;
|
|
||||||
vertical-align: middle;
|
|
||||||
|
|
||||||
&:hover, &:focus {
|
|
||||||
text-decoration: none;
|
|
||||||
background-color: @color-actions-hover-bg;
|
|
||||||
color: @color-actions-hover-text;
|
|
||||||
border: none;
|
|
||||||
padding: 15px 17px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: @color-actions-active-bg;
|
|
||||||
color: @color-actions-active-text;
|
|
||||||
}
|
|
||||||
|
|
||||||
i {
|
|
||||||
margin-right: 10px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<li
|
|
||||||
id="<?= 'action'.$action->id ?>"
|
|
||||||
data-action-id="<?= $action->id ?>"
|
|
||||||
class="action-item <?= $action->hasFieldConfig() ? '' : 'no-form' ?>">
|
|
||||||
<div>
|
|
||||||
<div class="icons">
|
|
||||||
<span class="icon"><i class="icon-bolt"></i></span>
|
|
||||||
<span class="icon"><i class="<?= e($action->getActionIcon()) ?>"></i></span>
|
|
||||||
</div>
|
|
||||||
<a href="javascript:;" data-actions-settings>
|
|
||||||
<span class="title"><?= e($this->getCacheActionTitle($action)) ?></span>
|
|
||||||
<span class="comment"><?= e($this->getCacheActionText($action)) ?></span>
|
|
||||||
</a>
|
|
||||||
<ul class="submenu">
|
|
||||||
<li>
|
|
||||||
<p>
|
|
||||||
<a href="javascript:;" data-actions-delete>
|
|
||||||
<i class="icon-trash-o control-icon"></i>
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
name="action_data[<?= $action->id ?>]"
|
|
||||||
value="<?= e(json_encode($this->getCacheActionData($action))) ?>" />
|
|
||||||
</li>
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
||||||
<?= Form::open(['id' => 'propertyForm']) ?>
|
|
||||||
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
|
||||||
<h4 class="modal-title">
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
<?= e($action->getTitle()) ?>
|
|
||||||
<?php else: ?>
|
|
||||||
Action
|
|
||||||
<?php endif ?>
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
|
|
||||||
<input type="hidden" name="current_action_id" value="<?= $action->id ?>" />
|
|
||||||
<input type="hidden" name="current_action_data" value="<?= e(json_encode($this->getCacheActionDataPayload())) ?>" />
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-md-8">
|
|
||||||
<?= $actionFormWidget->render() ?>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-4">
|
|
||||||
<?= $this->makePartial('available_tags') ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-request="<?= $this->getEventHandler('onSaveAction') ?>"
|
|
||||||
data-hotkey="ctrl+s, cmd+s"
|
|
||||||
data-popup-load-indicator
|
|
||||||
class="btn btn-primary">
|
|
||||||
<u>S</u>ave
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="oc-icon-trash-o btn-icon danger pull-right"
|
|
||||||
data-request="<?= $this->getEventHandler('onDeleteAction') ?>"
|
|
||||||
data-popup-load-indicator
|
|
||||||
data-request-confirm="Do you really want to delete this action?">
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.close')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<?php Form::close() ?>
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<div class="action-set">
|
|
||||||
<ol>
|
|
||||||
<li>
|
|
||||||
<div class="no-hover">
|
|
||||||
<div class="icons">
|
|
||||||
<span class="icon">ON</span>
|
|
||||||
<span class="icon"><i class="icon-user"></i></span>
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<span class="title"><?= e($formModel->getEventName()) ?></span>
|
|
||||||
<span class="comment"><?= e($formModel->getEventDescription()) ?></span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<?php foreach ($actions as $action): ?>
|
|
||||||
<?= $this->makePartial('action', ['action' => $action]) ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
data-control="popup"
|
|
||||||
data-handler="<?= $this->getEventHandler('onLoadCreateActionForm') ?>"
|
|
||||||
class="menu-control">
|
|
||||||
<i class="icon-plus"></i> Add action
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if (isset($newActionId)): ?>
|
|
||||||
<script> showActionSettings('<?= e($newActionId) ?>') </script>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<div class="actions-container">
|
|
||||||
<div
|
|
||||||
id="<?= $this->getId() ?>"
|
|
||||||
class="control-ruleactions"
|
|
||||||
data-settings-handler="<?= $this->getEventHandler('onLoadActionSetup') ?>"
|
|
||||||
data-delete-handler="<?= $this->getEventHandler('onDeleteAction') ?>"
|
|
||||||
data-cancel-handler="<?= $this->getEventHandler('onCancelActionSettings') ?>"
|
|
||||||
data-create-handler="<?= $this->getEventHandler('onLoadCreateChildAction') ?>"
|
|
||||||
data-control="ruleactions">
|
|
||||||
<?= $this->makePartial('actions', ['actions' => $actions]) ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,23 +0,0 @@
|
||||||
<?php if ($availableTags): ?>
|
|
||||||
<div class="form-preview">
|
|
||||||
<p>These variables are available:</p>
|
|
||||||
<div class="control-balloon-selector">
|
|
||||||
<ul>
|
|
||||||
<?php foreach ($availableTags as $tag => $description): ?>
|
|
||||||
<li
|
|
||||||
title="<?= $description ?>"
|
|
||||||
data-control="dragvalue"
|
|
||||||
data-drag-click="true"
|
|
||||||
data-text-value="{{ <?= $tag ?> }}">
|
|
||||||
{{ <?= $tag ?> }}
|
|
||||||
</li>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="small"><em>Click or drag these in to the content area</em></div>
|
|
||||||
</div>
|
|
||||||
<?php else: ?>
|
|
||||||
<div class="form-preview">
|
|
||||||
<div>This action does not provide any variables.</div>
|
|
||||||
</div>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
<?= Form::open(['id' => 'addRuleActionForm']) ?>
|
|
||||||
|
|
||||||
<input type="hidden" name="current_action_data" value="<?= e(json_encode($this->getCacheActionDataPayload())) ?>" />
|
|
||||||
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
|
||||||
<h4 class="modal-title"><?= e(trans('rainlab.notify::lang.action.add_notification_action')) ?></h4>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
|
|
||||||
<?php if ($this->fatalError): ?>
|
|
||||||
<p class="flash-message static error"><?= $fatalError ?></p>
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="list-preview">
|
|
||||||
<div class="control-simplelist is-selectable is-scrollable size-large" data-control="simplelist">
|
|
||||||
<ul>
|
|
||||||
<?php foreach ($actions as $class => $action): ?>
|
|
||||||
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
data-request="<?= $this->getEventHandler('onCreateAction') ?>"
|
|
||||||
data-request-data="action_class: '<?= addslashes($class) ?>'"
|
|
||||||
data-popup-load-indicator>
|
|
||||||
<h5 class="heading"><?= e(trans($action->getActionName())) ?></h5>
|
|
||||||
<p class="description"><?= e(trans($action->getActionDescription())) ?></p>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
|
|
||||||
<?php endforeach ?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<?= Form::close() ?>
|
|
||||||
|
|
@ -1,227 +0,0 @@
|
||||||
ul.condition-set {
|
|
||||||
padding: 5px 0 0;
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
ul.condition-set ul {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
ul.condition-set li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item {
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-root {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.collapsed .compound-content {
|
|
||||||
border-left-color: transparent !important;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.collapsed .condition-set {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.collapsed.is-inner .compound-add-item {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item .condition-delete {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
right: 7px;
|
|
||||||
top: 7px;
|
|
||||||
}
|
|
||||||
ul.condition-set a.condition-collapse {
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
top: 2px;
|
|
||||||
}
|
|
||||||
ul.condition-set a.condition-collapse > i {
|
|
||||||
-webkit-transition: transform 0.3s;
|
|
||||||
transition: transform 0.3s;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
color: #bdc3c7;
|
|
||||||
font-size: 12px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
ul.condition-set a.condition-collapse:hover > i {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
ul.condition-set li.collapsed a.condition-collapse > i {
|
|
||||||
-webkit-transform: scale(1, -1);
|
|
||||||
-ms-transform: scale(1, -1);
|
|
||||||
transform: scale(1, -1);
|
|
||||||
}
|
|
||||||
ul.condition-set .compound-join {
|
|
||||||
text-align: center;
|
|
||||||
padding: 3px 0 2px 0;
|
|
||||||
}
|
|
||||||
ul.condition-set .compound-join a {
|
|
||||||
color: #333333;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
ul.condition-set .compound-join a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single {
|
|
||||||
padding: 8px 20px 9px 24px;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single:before {
|
|
||||||
font-family: FontAwesome;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
text-decoration: inherit;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
*margin-right: .3em;
|
|
||||||
content: "\f126";
|
|
||||||
line-height: 100%;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #bdc3c7;
|
|
||||||
position: absolute;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
left: 12px;
|
|
||||||
top: 11px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single .condition-text {
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single .condition-text a {
|
|
||||||
color: #333333;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single .condition-text a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single .condition-text a span.operator {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-single a.condition-delete {
|
|
||||||
right: 12px;
|
|
||||||
top: 9px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-content {
|
|
||||||
position: relative;
|
|
||||||
border-left: 1px solid #dbdee0;
|
|
||||||
margin-left: 5px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-content:before {
|
|
||||||
color: #bdc3c7;
|
|
||||||
font-family: FontAwesome;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
text-decoration: inherit;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
*margin-right: .3em;
|
|
||||||
content: "\f111";
|
|
||||||
font-size: 8px;
|
|
||||||
position: absolute;
|
|
||||||
left: -4px;
|
|
||||||
top: -2px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-content h4 {
|
|
||||||
padding: 0 30px 5px 5px;
|
|
||||||
margin: 0;
|
|
||||||
position: relative;
|
|
||||||
top: -5px;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 130%;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-content h4 a.condition-text {
|
|
||||||
color: #333333;
|
|
||||||
padding-left: 10px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-content h4 a.condition-text:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-content .condition-set {
|
|
||||||
padding-left: 15px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item {
|
|
||||||
position: relative;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 20px;
|
|
||||||
border: 2px dotted #e0e0e0;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:before {
|
|
||||||
color: #bdc3c7;
|
|
||||||
font-family: FontAwesome;
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
text-decoration: inherit;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
*margin-right: .3em;
|
|
||||||
content: "\f067";
|
|
||||||
font-size: 16px;
|
|
||||||
position: absolute;
|
|
||||||
left: -23px;
|
|
||||||
top: -11px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item > a {
|
|
||||||
color: #bdc3c7;
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 13px 15px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: 12px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:hover,
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:focus {
|
|
||||||
background-color: #4ea5e0;
|
|
||||||
border-color: #4ea5e0;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:hover:before,
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:focus:before {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:hover > a,
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:focus > a {
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:active {
|
|
||||||
background: #3498db;
|
|
||||||
border-color: #3498db;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound .compound-add-item:active > a {
|
|
||||||
color: #ffffff;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound.is-inner {
|
|
||||||
padding-right: 20px;
|
|
||||||
}
|
|
||||||
ul.condition-set .condition-item.is-compound.is-inner a.condition-delete-compound {
|
|
||||||
right: -7px;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
.condition-multi-value .condition-filter-search {
|
|
||||||
background-position: right -81px !important;
|
|
||||||
border-top: none !important;
|
|
||||||
border-left: none !important;
|
|
||||||
border-right: none !important;
|
|
||||||
border-radius: 0;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
.condition-multi-value .filter-list {
|
|
||||||
margin: 0 -20px;
|
|
||||||
}
|
|
||||||
.condition-multi-value .filter-list .list-footer {
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
.condition-multi-value .added-filter-list {
|
|
||||||
margin: 0 -20px;
|
|
||||||
}
|
|
||||||
|
|
@ -1,184 +0,0 @@
|
||||||
/*
|
|
||||||
* Global helpers
|
|
||||||
*/
|
|
||||||
function showConditionSettings(id) {
|
|
||||||
var $control = $('[data-condition-id='+id+']').closest('[data-control="ruleconditions"]')
|
|
||||||
|
|
||||||
$control.ruleConditions('onShowNewConditionSettings', id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Plugin definition
|
|
||||||
*/
|
|
||||||
+function ($) { "use strict";
|
|
||||||
var Base = $.oc.foundation.base,
|
|
||||||
BaseProto = Base.prototype
|
|
||||||
|
|
||||||
var RuleConditions = function (element, options) {
|
|
||||||
this.$el = $(element)
|
|
||||||
this.options = options || {}
|
|
||||||
|
|
||||||
$.oc.foundation.controlUtils.markDisposable(element)
|
|
||||||
Base.call(this)
|
|
||||||
this.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype = Object.create(BaseProto)
|
|
||||||
RuleConditions.prototype.constructor = RuleConditions
|
|
||||||
|
|
||||||
RuleConditions.prototype.init = function() {
|
|
||||||
this.$el.on('click', '[data-conditions-collapse]', this.proxy(this.onConditionsToggle))
|
|
||||||
this.$el.on('click', '[data-conditions-settings]', this.proxy(this.onShowSettings))
|
|
||||||
this.$el.on('click', '[data-conditions-create]', this.proxy(this.onCreateChildCondition))
|
|
||||||
this.$el.on('click', '[data-conditions-delete]', this.proxy(this.onDeleteCondition))
|
|
||||||
this.$el.one('dispose-control', this.proxy(this.dispose))
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.dispose = function() {
|
|
||||||
this.$el.off('click', '[data-conditions-collapse]', this.proxy(this.onConditionsToggle))
|
|
||||||
this.$el.off('click', '[data-conditions-settings]', this.proxy(this.onShowSettings))
|
|
||||||
this.$el.off('click', '[data-conditions-create]', this.proxy(this.onCreateChildCondition))
|
|
||||||
this.$el.off('click', '[data-conditions-delete]', this.proxy(this.onDeleteCondition))
|
|
||||||
this.$el.off('dispose-control', this.proxy(this.dispose))
|
|
||||||
this.$el.removeData('oc.ruleConditions')
|
|
||||||
|
|
||||||
this.$el = null
|
|
||||||
|
|
||||||
// In some cases options could contain callbacks,
|
|
||||||
// so it's better to clean them up too.
|
|
||||||
this.options = null
|
|
||||||
|
|
||||||
BaseProto.dispose.call(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.onDeleteCondition = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
conditionId = getConditionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.request(this.options.deleteHandler, {
|
|
||||||
data: { current_condition_id: conditionId },
|
|
||||||
confirm: 'Do you really want to delete this condition?'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.onCreateChildCondition = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
conditionId = getConditionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.popup({
|
|
||||||
handler: this.options.createHandler,
|
|
||||||
extraData: { current_condition_id: conditionId },
|
|
||||||
size: 'large'
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.onConditionsToggle = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
$item = $el.closest('li'),
|
|
||||||
newStatusValue = $item.hasClass('collapsed') ? 0 : 1,
|
|
||||||
conditionId = getConditionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.request(this.options.collapseHandler, {
|
|
||||||
data: {
|
|
||||||
status: newStatusValue,
|
|
||||||
group: conditionId
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if (newStatusValue) {
|
|
||||||
$el.parents('li:first').addClass('collapsed');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$el.parents('li:first').removeClass('collapsed');
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.onShowNewConditionSettings = function(conditionId) {
|
|
||||||
var $el = $('[data-condition-id='+conditionId+']')
|
|
||||||
|
|
||||||
$el.popup({
|
|
||||||
handler: this.options.settingsHandler,
|
|
||||||
extraData: { current_condition_id: conditionId },
|
|
||||||
size: 'large'
|
|
||||||
})
|
|
||||||
|
|
||||||
// This will not fire on successful save because the target element
|
|
||||||
// is replaced by the time the popup loader has finished to call it
|
|
||||||
$el.one('hide.oc.popup', this.proxy(this.onCancelCondition))
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.onCancelCondition = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
conditionId = getConditionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.request(this.options.cancelHandler, {
|
|
||||||
data: { new_condition_id: conditionId }
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.prototype.onShowSettings = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
conditionId = getConditionIdFromElement($el)
|
|
||||||
|
|
||||||
$el.popup({
|
|
||||||
handler: this.options.settingsHandler,
|
|
||||||
extraData: { current_condition_id: conditionId },
|
|
||||||
size: 'large'
|
|
||||||
})
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
function getConditionIdFromElement($el) {
|
|
||||||
var $item = $el.closest('li.condition-item')
|
|
||||||
|
|
||||||
return $item.data('condition-id')
|
|
||||||
}
|
|
||||||
|
|
||||||
RuleConditions.DEFAULTS = {
|
|
||||||
collapseHandler: null,
|
|
||||||
settingsHandler: null,
|
|
||||||
deleteHandler: null,
|
|
||||||
cancelHandler: null,
|
|
||||||
createHandler: null
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUGIN DEFINITION
|
|
||||||
// ============================
|
|
||||||
|
|
||||||
var old = $.fn.ruleConditions
|
|
||||||
|
|
||||||
$.fn.ruleConditions = function (option) {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 1), items, result
|
|
||||||
|
|
||||||
items = this.each(function () {
|
|
||||||
var $this = $(this)
|
|
||||||
var data = $this.data('oc.ruleConditions')
|
|
||||||
var options = $.extend({}, RuleConditions.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
|
||||||
if (!data) $this.data('oc.ruleConditions', (data = new RuleConditions(this, options)))
|
|
||||||
if (typeof option == 'string') result = data[option].apply(data, args)
|
|
||||||
if (typeof result != 'undefined') return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return result ? result : items
|
|
||||||
}
|
|
||||||
|
|
||||||
$.fn.ruleConditions.Constructor = RuleConditions
|
|
||||||
|
|
||||||
$.fn.ruleConditions.noConflict = function () {
|
|
||||||
$.fn.ruleConditions = old
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add this only if required
|
|
||||||
$(document).render(function (){
|
|
||||||
$('[data-control="ruleconditions"]').ruleConditions()
|
|
||||||
})
|
|
||||||
|
|
||||||
}(window.jQuery);
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
||||||
/*
|
|
||||||
* Plugin definition
|
|
||||||
*/
|
|
||||||
+function ($) { "use strict";
|
|
||||||
var Base = $.oc.foundation.base,
|
|
||||||
BaseProto = Base.prototype
|
|
||||||
|
|
||||||
var ConditionMultiValue = function (element, options) {
|
|
||||||
this.$el = $(element)
|
|
||||||
this.options = options || {}
|
|
||||||
this.$template = $('[data-record-template]', this.$el)
|
|
||||||
this.$emptyTemplate = $('[data-empty-record-template]', this.$el)
|
|
||||||
this.$addedRecords = $('[data-added-records]', this.$el)
|
|
||||||
|
|
||||||
$.oc.foundation.controlUtils.markDisposable(element)
|
|
||||||
Base.call(this)
|
|
||||||
|
|
||||||
this.init()
|
|
||||||
this.recompileData()
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype = Object.create(BaseProto)
|
|
||||||
ConditionMultiValue.prototype.constructor = ConditionMultiValue
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.init = function() {
|
|
||||||
this.$el.on('click', '[data-multivalue-add-record]', this.proxy(this.onAddRecord))
|
|
||||||
this.$el.on('click', '[data-multivalue-remove-record]', this.proxy(this.onRemoveRecord))
|
|
||||||
this.$el.one('dispose-control', this.proxy(this.dispose))
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.dispose = function() {
|
|
||||||
this.$el.off('click', '[data-multivalue-add-record]', this.proxy(this.onAddRecord))
|
|
||||||
this.$el.off('click', '[data-multivalue-remove-record]', this.proxy(this.onRemoveRecord))
|
|
||||||
this.$el.off('dispose-control', this.proxy(this.dispose))
|
|
||||||
this.$el.removeData('oc.conditionMultiValue')
|
|
||||||
|
|
||||||
this.$el = null
|
|
||||||
|
|
||||||
// In some cases options could contain callbacks,
|
|
||||||
// so it's better to clean them up too.
|
|
||||||
this.options = null
|
|
||||||
|
|
||||||
BaseProto.dispose.call(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.onAddRecord = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
recordId = $el.closest('[data-record-key]').data('record-key'),
|
|
||||||
recordValue = $el.closest('a').data('record-value')
|
|
||||||
|
|
||||||
if (!!$('[data-record-key='+recordId+']', this.$addedRecords).length) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.$addedRecords.append(this.renderTemplate({
|
|
||||||
key: recordId,
|
|
||||||
value: recordValue
|
|
||||||
}))
|
|
||||||
|
|
||||||
this.recompileData()
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.onRemoveRecord = function(event) {
|
|
||||||
var $el = $(event.target),
|
|
||||||
recordId = $el.closest('[data-record-key]').data('record-key')
|
|
||||||
|
|
||||||
$('[data-record-key='+recordId+']', this.$addedRecords).remove()
|
|
||||||
|
|
||||||
this.recompileData()
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.recompileData = function(params) {
|
|
||||||
var $recordElements = $('[data-record-key]', this.$addedRecords),
|
|
||||||
hasData = !!$recordElements.length
|
|
||||||
|
|
||||||
if (hasData) {
|
|
||||||
$('[data-no-record-data]', this.$addedRecords).remove()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
this.$addedRecords.append(this.renderEmptyTemplate())
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.options.dataLocker) {
|
|
||||||
var $locker = $(this.options.dataLocker),
|
|
||||||
selectedIds = []
|
|
||||||
|
|
||||||
$recordElements.each(function(key, record) {
|
|
||||||
selectedIds.push($(record).data('record-key'))
|
|
||||||
})
|
|
||||||
|
|
||||||
$locker.val(selectedIds.join(','))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.renderTemplate = function(params) {
|
|
||||||
return Mustache.render(this.$template.html(), params)
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.prototype.renderEmptyTemplate = function() {
|
|
||||||
return this.$emptyTemplate.html()
|
|
||||||
}
|
|
||||||
|
|
||||||
ConditionMultiValue.DEFAULTS = {
|
|
||||||
dataLocker: null
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUGIN DEFINITION
|
|
||||||
// ============================
|
|
||||||
|
|
||||||
var old = $.fn.conditionMultiValue
|
|
||||||
|
|
||||||
$.fn.conditionMultiValue = function (option) {
|
|
||||||
var args = Array.prototype.slice.call(arguments, 1), items, result
|
|
||||||
|
|
||||||
items = this.each(function () {
|
|
||||||
var $this = $(this)
|
|
||||||
var data = $this.data('oc.conditionMultiValue')
|
|
||||||
var options = $.extend({}, ConditionMultiValue.DEFAULTS, $this.data(), typeof option == 'object' && option)
|
|
||||||
if (!data) $this.data('oc.conditionMultiValue', (data = new ConditionMultiValue(this, options)))
|
|
||||||
if (typeof option == 'string') result = data[option].apply(data, args)
|
|
||||||
if (typeof result != 'undefined') return false
|
|
||||||
})
|
|
||||||
|
|
||||||
return result ? result : items
|
|
||||||
}
|
|
||||||
|
|
||||||
$.fn.conditionMultiValue.Constructor = ConditionMultiValue
|
|
||||||
|
|
||||||
$.fn.conditionMultiValue.noConflict = function () {
|
|
||||||
$.fn.conditionMultiValue = old
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add this only if required
|
|
||||||
$(document).render(function (){
|
|
||||||
$('[data-control="condition-multivalue"]').conditionMultiValue()
|
|
||||||
})
|
|
||||||
|
|
||||||
}(window.jQuery);
|
|
||||||
|
|
@ -1,286 +0,0 @@
|
||||||
@import "../../../../../../../modules/backend/assets/less/core/boot.less";
|
|
||||||
|
|
||||||
//
|
|
||||||
// Conditions
|
|
||||||
// --------------------------------------------------
|
|
||||||
|
|
||||||
ul.condition-set {
|
|
||||||
padding: 5px 0 0;
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
|
|
||||||
ul {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
list-style: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-item {
|
|
||||||
border-radius: 4px;
|
|
||||||
|
|
||||||
&.is-root {
|
|
||||||
border-radius: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-inner {}
|
|
||||||
|
|
||||||
&.collapsed {
|
|
||||||
.compound-content {
|
|
||||||
border-left-color: transparent !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-set {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.is-inner .compound-add-item {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-delete {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
width: 10px;
|
|
||||||
height: 10px;
|
|
||||||
right: 7px;
|
|
||||||
top: 7px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Collapse
|
|
||||||
//
|
|
||||||
|
|
||||||
a.condition-collapse {
|
|
||||||
text-decoration: none;
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
right: 8px;
|
|
||||||
top: 2px;
|
|
||||||
|
|
||||||
> i {
|
|
||||||
.transition(~'transform 0.3s');
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
color: #bdc3c7;
|
|
||||||
font-size: 12px;
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
> i {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
li.collapsed a.condition-collapse {
|
|
||||||
> i {
|
|
||||||
.transform(scale(1,-1));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Joins
|
|
||||||
//
|
|
||||||
|
|
||||||
.compound-join {
|
|
||||||
text-align: center;
|
|
||||||
padding: 3px 0 2px 0;
|
|
||||||
a {
|
|
||||||
color: #333333;
|
|
||||||
text-decoration: none;
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Single
|
|
||||||
//
|
|
||||||
|
|
||||||
.condition-item.is-single {
|
|
||||||
padding: 8px 20px 9px 24px;
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid #eee;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
.icon(@code-fork);
|
|
||||||
line-height: 100%;
|
|
||||||
font-size: 16px;
|
|
||||||
color: #bdc3c7;
|
|
||||||
|
|
||||||
position: absolute;
|
|
||||||
width: 15px;
|
|
||||||
height: 15px;
|
|
||||||
left: 12px;
|
|
||||||
top: 11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-text {
|
|
||||||
padding-left: 10px;
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #333333;
|
|
||||||
text-decoration: none;
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
span.operator {
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
a.condition-delete {
|
|
||||||
right: 12px;
|
|
||||||
top: 9px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Compound
|
|
||||||
//
|
|
||||||
|
|
||||||
.condition-item.is-compound {
|
|
||||||
.compound-content {
|
|
||||||
position: relative;
|
|
||||||
border-left: 1px solid #dbdee0;
|
|
||||||
margin-left: 5px;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
color: #bdc3c7;
|
|
||||||
.icon(@circle);
|
|
||||||
font-size: 8px;
|
|
||||||
position: absolute;
|
|
||||||
left: -4px;
|
|
||||||
top: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
padding: 0 30px 5px 5px;
|
|
||||||
margin: 0;
|
|
||||||
position: relative;
|
|
||||||
top: -5px;
|
|
||||||
font-size: 13px;
|
|
||||||
line-height: 130%;
|
|
||||||
font-weight: 400;
|
|
||||||
color: #666;
|
|
||||||
a.condition-text {
|
|
||||||
color: #333333;
|
|
||||||
padding-left: 10px;
|
|
||||||
&:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-set {
|
|
||||||
padding-left: 15px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.condition-item.is-compound {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.compound-add-item {
|
|
||||||
position: relative;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-left: 20px;
|
|
||||||
border: 2px dotted #e0e0e0;
|
|
||||||
border-radius: 5px;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
color: #bdc3c7;
|
|
||||||
.icon(@plus);
|
|
||||||
font-size: 16px;
|
|
||||||
position: absolute;
|
|
||||||
left: -23px;
|
|
||||||
top: -11px;
|
|
||||||
}
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: #bdc3c7;
|
|
||||||
text-align: center;
|
|
||||||
display: block;
|
|
||||||
text-decoration: none;
|
|
||||||
padding: 13px 15px;
|
|
||||||
text-transform: uppercase;
|
|
||||||
font-weight: 600;
|
|
||||||
font-size: @font-size-base - 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover, &:focus {
|
|
||||||
background-color: @highlight-hover-bg;
|
|
||||||
border-color: @highlight-hover-bg;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
color: #999;
|
|
||||||
}
|
|
||||||
|
|
||||||
> a {
|
|
||||||
color: @highlight-hover-text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: @highlight-active-bg;
|
|
||||||
border-color: @highlight-active-bg;
|
|
||||||
> a {
|
|
||||||
color: @highlight-active-text;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Compound (Inner)
|
|
||||||
//
|
|
||||||
|
|
||||||
.condition-item.is-compound.is-inner {
|
|
||||||
padding-right: 20px;
|
|
||||||
|
|
||||||
a.condition-delete-compound {
|
|
||||||
right: -7px;
|
|
||||||
top: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Multi value
|
|
||||||
//
|
|
||||||
|
|
||||||
.condition-multi-value {
|
|
||||||
.condition-filter-search {
|
|
||||||
background-position: right -81px !important;
|
|
||||||
border-top: none !important;
|
|
||||||
border-left: none !important;
|
|
||||||
border-right: none !important;
|
|
||||||
border-radius: 0;
|
|
||||||
padding-left: 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.filter-list {
|
|
||||||
margin: 0 -20px;
|
|
||||||
|
|
||||||
.list-footer {
|
|
||||||
padding-top: 0;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.added-filter-list {
|
|
||||||
margin: 0 -20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,99 +0,0 @@
|
||||||
<?php
|
|
||||||
$isCompound = $condition->isCompound();
|
|
||||||
$isRoot = $treeLevel == 0;
|
|
||||||
$collapsed = $this->getCollapseStatus($condition->id, false);
|
|
||||||
?>
|
|
||||||
<li
|
|
||||||
id="<?= 'condition'.$condition->id ?>"
|
|
||||||
data-condition-id="<?= $condition->id ?>"
|
|
||||||
class="condition-item <?= $isCompound ? 'is-compound' : 'is-single' ?> <?= $isRoot ? 'is-root' : 'is-inner' ?> <?= $collapsed ? 'collapsed' : null ?>">
|
|
||||||
|
|
||||||
<?php if ($isCompound): ?>
|
|
||||||
|
|
||||||
<div class="compound-content">
|
|
||||||
<h4>
|
|
||||||
<a
|
|
||||||
class="condition-collapse"
|
|
||||||
href="javascript:;"
|
|
||||||
title="Collapse / Expand"
|
|
||||||
data-conditions-collapse>
|
|
||||||
<i class="icon-chevron-up"></i>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
class="condition-text"
|
|
||||||
data-conditions-settings>
|
|
||||||
<?= e($this->getCacheConditionText($condition)) ?>
|
|
||||||
</a>
|
|
||||||
<?php if (!$isRoot): ?>
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
title="Delete condition"
|
|
||||||
class="condition-delete condition-delete-compound close"
|
|
||||||
data-conditions-delete>
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</a>
|
|
||||||
<?php endif ?>
|
|
||||||
</h4>
|
|
||||||
<ul class="condition-set">
|
|
||||||
<?php
|
|
||||||
$children = $condition->children()->withDeferred($this->sessionKey.'_'.$condition->id)->get();
|
|
||||||
$lastIndex = $children->count() - 1;
|
|
||||||
?>
|
|
||||||
<?php foreach ($children as $index => $childCondition): ?>
|
|
||||||
<?= $this->makePartial('condition', [
|
|
||||||
'condition' => $childCondition,
|
|
||||||
'treeLevel' => $treeLevel + 1,
|
|
||||||
'parentCondition' => $condition
|
|
||||||
]) ?>
|
|
||||||
<?php if ($index < $lastIndex): ?>
|
|
||||||
<li class="compound-join">
|
|
||||||
<a href="javascript:;" data-conditions-settings>
|
|
||||||
<?= e($this->getCacheConditionJoinText($condition)) ?>
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<?php endif ?>
|
|
||||||
<?php endforeach?>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="compound-add-item loading-indicator-container indicator-center">
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
data-conditions-create
|
|
||||||
data-request="onLoadConditionChildSelector">
|
|
||||||
Add condition
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="condition-text">
|
|
||||||
<a href="javascript:;" data-conditions-settings>
|
|
||||||
<?= $this->getCacheConditionText($condition) ?>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href="javascript:;"
|
|
||||||
title="Delete condition"
|
|
||||||
class="condition-delete close"
|
|
||||||
data-conditions-delete>
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
name="condition_data[<?= $condition->id ?>]"
|
|
||||||
value="<?= e(json_encode($this->getCacheConditionData($condition))) ?>" />
|
|
||||||
|
|
||||||
<?php if (isset($parentCondition)): ?>
|
|
||||||
<input
|
|
||||||
type="hidden"
|
|
||||||
name="condition_parent_id[<?= $condition->id ?>]"
|
|
||||||
value="<?= $parentCondition->id ?>" />
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
</li>
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
<?= Form::open(['id' => 'propertyForm']) ?>
|
|
||||||
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
|
||||||
<h4 class="modal-title">
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
<?= e($condition->getTitle()) ?>
|
|
||||||
<?php else: ?>
|
|
||||||
Condition
|
|
||||||
<?php endif ?>
|
|
||||||
</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
|
|
||||||
<input type="hidden" name="current_parent_id" value="<?= $this->getParentIdFromCondition($condition) ?>" />
|
|
||||||
<input type="hidden" name="current_condition_id" value="<?= $condition->id ?>" />
|
|
||||||
<input type="hidden" name="current_condition_data" value="<?= e(json_encode($this->getCacheConditionDataPayload())) ?>" />
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<?= $conditionFormWidget->render() ?>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-request="<?= $this->getEventHandler('onSaveCondition') ?>"
|
|
||||||
data-hotkey="ctrl+s, cmd+s"
|
|
||||||
data-popup-load-indicator
|
|
||||||
class="btn btn-primary">
|
|
||||||
<u>S</u>ave
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<?php if (!$this->isRootCondition($condition)): ?>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="oc-icon-trash-o btn-icon danger pull-right"
|
|
||||||
data-request="<?= $this->getEventHandler('onDeleteCondition') ?>"
|
|
||||||
data-popup-load-indicator
|
|
||||||
data-request-confirm="Do you really want to delete this condition?">
|
|
||||||
</button>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.close')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<?php Form::close() ?>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
<ul class="condition-set">
|
|
||||||
<?= $this->makePartial('condition', [
|
|
||||||
'condition' => $condition,
|
|
||||||
'treeLevel' => 0
|
|
||||||
]) ?>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
<?php if (isset($newConditionId)): ?>
|
|
||||||
<script> showConditionSettings('<?= e($newConditionId) ?>') </script>
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
<div class="conditions-container">
|
|
||||||
<div
|
|
||||||
id="<?= $this->getId() ?>"
|
|
||||||
class="control-ruleconditions"
|
|
||||||
data-collapse-handler="<?= $this->getEventHandler('onSetCollapseStatus') ?>"
|
|
||||||
data-settings-handler="<?= $this->getEventHandler('onLoadConditionSetup') ?>"
|
|
||||||
data-delete-handler="<?= $this->getEventHandler('onDeleteCondition') ?>"
|
|
||||||
data-cancel-handler="<?= $this->getEventHandler('onCancelConditionSettings') ?>"
|
|
||||||
data-create-handler="<?= $this->getEventHandler('onLoadCreateChildCondition') ?>"
|
|
||||||
data-control="ruleconditions">
|
|
||||||
<?= $this->makePartial('conditions', ['condition' => $rootCondition]) ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
<?= Form::open(['id' => 'propertyForm']) ?>
|
|
||||||
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
|
||||||
<h4 class="modal-title">Condition</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php if (!$this->fatalError): ?>
|
|
||||||
|
|
||||||
<input type="hidden" name="current_condition_id" value="<?= $condition->id ?>"/>
|
|
||||||
<input type="hidden" name="current_condition_data" value="<?= e(json_encode($this->getCacheConditionDataPayload())) ?>" />
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="form-group condition-class">
|
|
||||||
<label>Condition</label>
|
|
||||||
<select
|
|
||||||
class="form-control custom-select"
|
|
||||||
data-placeholder="Please select a condition"
|
|
||||||
name="condition_class">
|
|
||||||
<option value=""></option>
|
|
||||||
<?php foreach ($options as $name => $class): ?>
|
|
||||||
<?php if (!is_array($class)): ?>
|
|
||||||
<option value="<?= $class ?>"><?= e($name) ?></option>
|
|
||||||
<?php else: ?>
|
|
||||||
<optgroup label="<?= e($name) ?>">
|
|
||||||
<?php foreach ($class as $subName => $subClass): ?>
|
|
||||||
<option value="<?= $subClass ?>"><?= e($subName) ?></option>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</optgroup>
|
|
||||||
<?php endif ?>
|
|
||||||
<?php endforeach ?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
class="btn btn-primary"
|
|
||||||
data-request="<?= $this->getEventHandler('onCreateCondition') ?>"
|
|
||||||
data-popup-load-indicator
|
|
||||||
class="btn btn-primary">
|
|
||||||
Create
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.cancel')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php else: ?>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<p class="flash-message static error"><?= e(trans($this->fatalError)) ?></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-default"
|
|
||||||
data-dismiss="popup">
|
|
||||||
<?= e(trans('backend::lang.form.close')) ?>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<?php endif ?>
|
|
||||||
|
|
||||||
<?= Form::close() ?>
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Interfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This contract represents a notification action.
|
|
||||||
*/
|
|
||||||
interface Action
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns a action text summary when displaying to the user.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getText();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a action title for displaying in the action settings form.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns information about this action, including name and description.
|
|
||||||
*/
|
|
||||||
public function actionDetails();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers this action.
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function triggerAction($params);
|
|
||||||
}
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Interfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This contract represents a Compound Condition rule.
|
|
||||||
*/
|
|
||||||
interface CompoundCondition
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns the text to use when joining two rules within.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getJoinText();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of condition types (`ConditionBase::TYPE_*` constants)
|
|
||||||
* that can be added to this compound condition
|
|
||||||
*/
|
|
||||||
public function getAllowedSubtypes();
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Interfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This contract represents a Compound Condition rule.
|
|
||||||
*/
|
|
||||||
interface Condition
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns a condition text summary when displaying to the user.
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getText();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a condition title for displaying in the condition settings form
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getTitle();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of options supported beneth this condition.
|
|
||||||
*
|
|
||||||
* Options can contain these keys:
|
|
||||||
* - ruleType: Rule type as specified by ConditionBase::TYPE_* constants
|
|
||||||
* - parentIds: An array of parent ids to constrain child conditions
|
|
||||||
* - extraRules: An array of additional condition classes to use
|
|
||||||
*
|
|
||||||
* @param array $options
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getChildOptions(array $options);
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Interfaces;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This contract represents a notification event.
|
|
||||||
*/
|
|
||||||
interface Event
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Returns information about this event, including name and description.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function eventDetails();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates event parameters based on arguments from the triggering system event.
|
|
||||||
* @param array $args
|
|
||||||
* @param string $eventName
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function makeParamsFromEvent(array $args, $eventName = null);
|
|
||||||
}
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'plugin' => [
|
|
||||||
'name' => 'Notify',
|
|
||||||
'description' => 'Notification services',
|
|
||||||
],
|
|
||||||
'notifications' => [
|
|
||||||
'menu_label' => 'Notification rules',
|
|
||||||
'menu_description' => 'Manage the events and actions that trigger notifications.',
|
|
||||||
'name' => 'Name',
|
|
||||||
'code' => 'Code',
|
|
||||||
'notification_rule' => 'Notification rule',
|
|
||||||
'add_notification_rule' => 'Add notification rule',
|
|
||||||
],
|
|
||||||
'action' => [
|
|
||||||
'add_notification_action' => 'Add notification action',
|
|
||||||
],
|
|
||||||
'permissions' => [
|
|
||||||
'manage_notifications' => 'Notifications management',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'plugin' => [
|
|
||||||
'name' => 'Notificari',
|
|
||||||
'description' => 'Servicii notificari',
|
|
||||||
],
|
|
||||||
'notifications' => [
|
|
||||||
'menu_label' => 'Reguli notificari',
|
|
||||||
'menu_description' => 'Gestionati evenimentele si actiunile care declanșează notificari',
|
|
||||||
'name' => 'Nume',
|
|
||||||
'code' => 'Cod',
|
|
||||||
'notification_rule' => 'Regula notificare',
|
|
||||||
'add_notification_rule' => 'Adauga o regula pentru notificare',
|
|
||||||
],
|
|
||||||
'action' => [
|
|
||||||
'add_notification_action' => 'Adauga o actiune pentru notificare',
|
|
||||||
],
|
|
||||||
'permissions' => [
|
|
||||||
'manage_notifications' => 'Managementul notificarilor',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'plugin' => [
|
|
||||||
'name' => 'Уведомления',
|
|
||||||
'description' => 'Службы уведомлений',
|
|
||||||
],
|
|
||||||
'notifications' => [
|
|
||||||
'menu_label' => 'Правила уведомлений',
|
|
||||||
'menu_description' => 'Управление событиями и действиями, которые вызывают уведомления.',
|
|
||||||
'name' => 'Название',
|
|
||||||
'code' => 'Код',
|
|
||||||
'notification_rule' => 'Правило уведомления',
|
|
||||||
'add_notification_rule' => 'Добавить правило',
|
|
||||||
],
|
|
||||||
'action' => [
|
|
||||||
'add_notification_action' => 'Добавить действие',
|
|
||||||
],
|
|
||||||
'permissions' => [
|
|
||||||
'manage_notifications' => 'Управление уведомлениями',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'plugin' => [
|
|
||||||
'name' => 'Obvestila',
|
|
||||||
'description' => 'Storitve obveščanja',
|
|
||||||
],
|
|
||||||
'notifications' => [
|
|
||||||
'menu_label' => 'Nastavitve obveščanja',
|
|
||||||
'menu_description' => 'Upravljanje dogodkov in dejanj, ki prožijo obvestila.',
|
|
||||||
'name' => 'Ime',
|
|
||||||
'code' => 'Koda',
|
|
||||||
'notification_rule' => 'Pravilo obveščanja',
|
|
||||||
'add_notification_rule' => 'Dodaj pravilo obveščanja',
|
|
||||||
],
|
|
||||||
'action' => [
|
|
||||||
'add_notification_action' => 'Dodaj dejanje obveščanja',
|
|
||||||
],
|
|
||||||
'permissions' => [
|
|
||||||
'manage_notifications' => 'Upravljanje z nastavitvami obveščanja',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'plugin' => [
|
|
||||||
'name' => 'Bildirim',
|
|
||||||
'description' => 'Bildirim Servisi',
|
|
||||||
],
|
|
||||||
'notifications' => [
|
|
||||||
'menu_label' => 'Bildirim kuralları',
|
|
||||||
'menu_description' => 'Bildirimleri tetikleyen olayları ve eylemleri yönetin.',
|
|
||||||
'name' => 'İsim',
|
|
||||||
'code' => 'Kod',
|
|
||||||
'notification_rule' => 'Bildirim kuralı',
|
|
||||||
'add_notification_rule' => 'Bildirim kuralı ekle',
|
|
||||||
],
|
|
||||||
'action' => [
|
|
||||||
'add_notification_action' => 'Bildirim eylemi ekle',
|
|
||||||
],
|
|
||||||
'permissions' => [
|
|
||||||
'manage_notifications' => 'Bildirim yönetimi',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
<?php
|
|
||||||
|
|
||||||
return [
|
|
||||||
'plugin' => [
|
|
||||||
'name' => '通知',
|
|
||||||
'description' => '通知系統',
|
|
||||||
],
|
|
||||||
'notifications' => [
|
|
||||||
'menu_label' => '通知規則',
|
|
||||||
'menu_description' => '管理觸發通知的事件及動作。',
|
|
||||||
'name' => '名稱',
|
|
||||||
'code' => '代碼',
|
|
||||||
'notification_rule' => '通知規則',
|
|
||||||
'add_notification_rule' => '新增通知規則',
|
|
||||||
],
|
|
||||||
'action' => [
|
|
||||||
'add_notification_action' => '新增通知動作',
|
|
||||||
],
|
|
||||||
'permissions' => [
|
|
||||||
'manage_notifications' => '管理通知功能',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
@ -1,249 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Models;
|
|
||||||
|
|
||||||
use Guzzle\Http\Url;
|
|
||||||
use Model;
|
|
||||||
use Markdown;
|
|
||||||
use TPS\Birzha\Events\MessageReceivedEvent;
|
|
||||||
use TPS\Birzha\Events\PaymentGiftedEvent;
|
|
||||||
use TPS\Birzha\Events\PaymentReviewedEvent;
|
|
||||||
use TPS\Birzha\Events\ProductReviewedEvent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification Model stored in the database
|
|
||||||
*/
|
|
||||||
class Notification extends Model
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Indicates if the IDs are auto-incrementing.
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
public $incrementing = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string The database table used by the model.
|
|
||||||
*/
|
|
||||||
public $table = 'rainlab_notify_notifications';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Guarded fields
|
|
||||||
*/
|
|
||||||
protected $guarded = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Fillable fields
|
|
||||||
*/
|
|
||||||
protected $fillable = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of attribute names which are json encoded and decoded from the database.
|
|
||||||
*/
|
|
||||||
protected $jsonable = ['data'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of datetime attributes to convert to an instance of Carbon/DateTime objects.
|
|
||||||
*/
|
|
||||||
protected $dates = ['read_at'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The accessors to append to the model's array form.
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
protected $appends = ['parsed_body'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Relations
|
|
||||||
*/
|
|
||||||
public $morphTo = [
|
|
||||||
'notifiable' => [],
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark the notification as read.
|
|
||||||
*
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function markAsRead()
|
|
||||||
{
|
|
||||||
if (is_null($this->read_at)) {
|
|
||||||
$this->forceFill(['read_at' => $this->freshTimestamp()])->save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a notification has been read.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function read()
|
|
||||||
{
|
|
||||||
return $this->read_at !== null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Determine if a notification has not been read.
|
|
||||||
*
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function unread()
|
|
||||||
{
|
|
||||||
return $this->read_at === null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the entity's unread notifications.
|
|
||||||
*/
|
|
||||||
public function scopeApplyUnread($query)
|
|
||||||
{
|
|
||||||
return $query->whereNull('read_at');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the entity's read notifications.
|
|
||||||
*/
|
|
||||||
public function scopeApplyRead($query)
|
|
||||||
{
|
|
||||||
return $query->whereNotNull('read_at');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the parsed body of the announcement.
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getParsedBodyAttribute()
|
|
||||||
{
|
|
||||||
return Markdown::parse($this->body);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the description of the notification
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDescriptionAttribute()
|
|
||||||
{
|
|
||||||
$e = new $this->event_type;
|
|
||||||
|
|
||||||
if($e instanceof MessageReceivedEvent) {
|
|
||||||
|
|
||||||
return trans('validation.new_message');
|
|
||||||
|
|
||||||
} elseif($e instanceof ProductReviewedEvent) {
|
|
||||||
|
|
||||||
return trans('validation.product_reviewed');
|
|
||||||
|
|
||||||
} elseif($e instanceof PaymentReviewedEvent) {
|
|
||||||
|
|
||||||
return trans('validation.payment_reviewed');
|
|
||||||
} elseif($e instanceof PaymentGiftedEvent) {
|
|
||||||
|
|
||||||
return trans('validation.payment_gifted');
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Unknown type notification';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the localized description of the notification for api
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getDescriptionForApiAttribute()
|
|
||||||
{
|
|
||||||
$e = new $this->event_type;
|
|
||||||
|
|
||||||
if($e instanceof MessageReceivedEvent) {
|
|
||||||
|
|
||||||
return [
|
|
||||||
'ru' => trans('validation.new_message', [], 'ru'),
|
|
||||||
'en' => trans('validation.new_message', [], 'en'),
|
|
||||||
'tm' => trans('validation.new_message', [], 'tm'),
|
|
||||||
];
|
|
||||||
|
|
||||||
} elseif($e instanceof ProductReviewedEvent) {
|
|
||||||
|
|
||||||
return [
|
|
||||||
'ru' => trans('validation.product_reviewed', [], 'ru'),
|
|
||||||
'en' => trans('validation.product_reviewed', [], 'en'),
|
|
||||||
'tm' => trans('validation.product_reviewed', [], 'tm'),
|
|
||||||
];
|
|
||||||
|
|
||||||
} elseif($e instanceof PaymentReviewedEvent) {
|
|
||||||
|
|
||||||
return [
|
|
||||||
'ru' => trans('validation.payment_reviewed', [], 'ru'),
|
|
||||||
'en' => trans('validation.payment_reviewed', [], 'en'),
|
|
||||||
'tm' => trans('validation.payment_reviewed', [], 'tm'),
|
|
||||||
];
|
|
||||||
} elseif($e instanceof PaymentGiftedEvent) {
|
|
||||||
|
|
||||||
return [
|
|
||||||
'ru' => trans('validation.payment_gifted', [], 'ru'),
|
|
||||||
'en' => trans('validation.payment_gifted', [], 'en'),
|
|
||||||
'tm' => trans('validation.payment_gifted', [], 'tm'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'Unknown type notification';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the screen where to redirect when clicking on the notification
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getRedirectToScreenForApiAttribute()
|
|
||||||
{
|
|
||||||
$e = new $this->event_type;
|
|
||||||
|
|
||||||
if($e instanceof MessageReceivedEvent) {
|
|
||||||
|
|
||||||
return 'messages_screen';
|
|
||||||
|
|
||||||
} elseif($e instanceof ProductReviewedEvent) {
|
|
||||||
|
|
||||||
return 'my_posts_screen';
|
|
||||||
|
|
||||||
} elseif($e instanceof PaymentReviewedEvent) {
|
|
||||||
|
|
||||||
return 'balance_history_screen';
|
|
||||||
|
|
||||||
} elseif($e instanceof PaymentGiftedEvent) {
|
|
||||||
|
|
||||||
return 'balance_history_screen';
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 'main_screen';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the link where to redirect when the notification is clicked
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
public function getLinkAttribute()
|
|
||||||
{
|
|
||||||
$e = new $this->event_type;
|
|
||||||
|
|
||||||
if($e instanceof MessageReceivedEvent) {
|
|
||||||
|
|
||||||
return \Url::to('/messages');
|
|
||||||
|
|
||||||
} elseif($e instanceof ProductReviewedEvent) {
|
|
||||||
|
|
||||||
return \Url::to('/my-posts');
|
|
||||||
|
|
||||||
} elseif($e instanceof PaymentReviewedEvent) {
|
|
||||||
|
|
||||||
return \Url::to('/balans-taryhy');
|
|
||||||
} elseif($e instanceof PaymentGiftedEvent) {
|
|
||||||
|
|
||||||
return \Url::to('/balans-taryhy');
|
|
||||||
}
|
|
||||||
|
|
||||||
return \Url::to('/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,289 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Models;
|
|
||||||
|
|
||||||
use Lang;
|
|
||||||
use Model;
|
|
||||||
use RainLab\Notify\Classes\EventBase;
|
|
||||||
use RainLab\Notify\Classes\ConditionBase;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Notification rule
|
|
||||||
*
|
|
||||||
* @package rainlab\notify
|
|
||||||
* @author Alexey Bobkov, Samuel Georges
|
|
||||||
*/
|
|
||||||
class NotificationRule extends Model
|
|
||||||
{
|
|
||||||
use \October\Rain\Database\Traits\Purgeable;
|
|
||||||
use \October\Rain\Database\Traits\Validation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string The database table used by the model.
|
|
||||||
*/
|
|
||||||
protected $table = 'rainlab_notify_notification_rules';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Guarded fields
|
|
||||||
*/
|
|
||||||
protected $guarded = ['config_data'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Fillable fields
|
|
||||||
*/
|
|
||||||
protected $fillable = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of attribute names which should not be saved to the database.
|
|
||||||
*/
|
|
||||||
protected $purgeable = ['event_name'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array The rules to be applied to the data.
|
|
||||||
*/
|
|
||||||
public $rules = [
|
|
||||||
'name' => 'required'
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Relations
|
|
||||||
*/
|
|
||||||
public $hasMany = [
|
|
||||||
'rule_conditions' => [
|
|
||||||
RuleCondition::class,
|
|
||||||
'key' => 'rule_host_id',
|
|
||||||
'conditions' => 'rule_parent_id is null',
|
|
||||||
'delete' => true
|
|
||||||
],
|
|
||||||
'rule_actions' => [
|
|
||||||
RuleAction::class,
|
|
||||||
'key' => 'rule_host_id',
|
|
||||||
'delete' => true
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Kicks off this notification rule, fires the event to obtain its parameters,
|
|
||||||
* checks the rule conditions evaluate as true, then spins over each action.
|
|
||||||
*/
|
|
||||||
public function triggerRule()
|
|
||||||
{
|
|
||||||
$params = $this->getEventObject()->getParams();
|
|
||||||
$rootCondition = $this->rule_conditions->first();
|
|
||||||
|
|
||||||
if ($rootCondition && !$rootCondition->getConditionObject()->isTrue($params)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->rule_actions as $action) {
|
|
||||||
$action->setRelation('notification_rule', $this);
|
|
||||||
$action->triggerAction($params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns extra conditions provided by the event.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function getExtraConditionRules()
|
|
||||||
{
|
|
||||||
$rules = [];
|
|
||||||
|
|
||||||
$classes = $this->getEventObject()->defineConditions();
|
|
||||||
|
|
||||||
foreach ($classes as $class) {
|
|
||||||
$rules[$class] = new $class;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $rules;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends this class with the event class
|
|
||||||
* @param string $class Class name
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function applyEventClass($class = null)
|
|
||||||
{
|
|
||||||
if (!$class) {
|
|
||||||
$class = $this->class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$class) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->isClassExtendedWith($class)) {
|
|
||||||
$this->extendClassWith($class);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->class_name = $class;
|
|
||||||
$this->event_name = Lang::get(array_get($this->eventDetails(), 'name', 'Unknown'));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the event class extension object.
|
|
||||||
* @return \RainLab\Notify\Classes\NotificationEvent
|
|
||||||
*/
|
|
||||||
public function getEventObject()
|
|
||||||
{
|
|
||||||
$this->applyEventClass();
|
|
||||||
|
|
||||||
return $this->asExtension($this->getEventClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getEventClass()
|
|
||||||
{
|
|
||||||
return $this->class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Events
|
|
||||||
//
|
|
||||||
|
|
||||||
public function afterFetch()
|
|
||||||
{
|
|
||||||
$this->applyEventClass();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function beforeValidate()
|
|
||||||
{
|
|
||||||
if (!$this->applyEventClass()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Scopes
|
|
||||||
//
|
|
||||||
|
|
||||||
public function scopeApplyEnabled($query)
|
|
||||||
{
|
|
||||||
return $query->where('is_enabled', true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function scopeApplyClass($query, $class)
|
|
||||||
{
|
|
||||||
if (!is_string($class)) {
|
|
||||||
$class = get_class($class);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $query->where('class_name', $class);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Presets
|
|
||||||
//
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of rule codes and descriptions.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function listRulesForEvent($eventClass)
|
|
||||||
{
|
|
||||||
$results = [];
|
|
||||||
|
|
||||||
$dbRules = self::applyClass($eventClass)->get();
|
|
||||||
$presets = (array) EventBase::findEventPresetsByClass($eventClass);
|
|
||||||
|
|
||||||
foreach ($dbRules as $dbRule) {
|
|
||||||
if ($dbRule->code) {
|
|
||||||
unset($presets[$dbRule->code]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($dbRule->is_enabled) {
|
|
||||||
$results[] = $dbRule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($presets as $code => $preset) {
|
|
||||||
if ($newPreset = self::createFromPreset($code, $preset)) {
|
|
||||||
$results[] = $newPreset;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $results;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Syncronise all file-based presets to the database.
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public static function syncAll()
|
|
||||||
{
|
|
||||||
$presets = (array) EventBase::findEventPresets();
|
|
||||||
$dbRules = self::where('code', '!=', '')->whereNotNull('code')->lists('is_custom', 'code');
|
|
||||||
$newRules = array_diff_key($presets, $dbRules);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Clean up non-customized templates
|
|
||||||
*/
|
|
||||||
foreach ($dbRules as $code => $isCustom) {
|
|
||||||
if ($isCustom) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!array_key_exists($code, $presets) && ($record = self::whereCode($code)->first())) {
|
|
||||||
$record->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Create new rules
|
|
||||||
*/
|
|
||||||
foreach ($newRules as $code => $preset) {
|
|
||||||
self::createFromPreset($code, $preset);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function createFromPreset($code, $preset)
|
|
||||||
{
|
|
||||||
$actions = array_get($preset, 'items');
|
|
||||||
if (!$actions || !is_array($actions)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$newRule = new self;
|
|
||||||
$newRule->code = $code;
|
|
||||||
$newRule->is_enabled = 1;
|
|
||||||
$newRule->is_custom = 0;
|
|
||||||
$newRule->name = array_get($preset, 'name');
|
|
||||||
$newRule->class_name = array_get($preset, 'event');
|
|
||||||
$newRule->forceSave();
|
|
||||||
|
|
||||||
// Add the actions
|
|
||||||
foreach ($actions as $action) {
|
|
||||||
$params = array_except($action, 'action');
|
|
||||||
|
|
||||||
$newAction = new RuleAction;
|
|
||||||
$newAction->class_name = array_get($action, 'action');
|
|
||||||
$newAction->notification_rule = $newRule;
|
|
||||||
$newAction->fill($params);
|
|
||||||
$newAction->forceSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add the conditions
|
|
||||||
$conditions = array_get($preset, 'conditions');
|
|
||||||
if (!$conditions || !is_array($conditions)) {
|
|
||||||
return $newRule;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the root condition
|
|
||||||
$rootCondition = new RuleCondition();
|
|
||||||
$rootCondition->rule_host_type = ConditionBase::TYPE_ANY;
|
|
||||||
$rootCondition->class_name = $rootCondition->getRootConditionClass();
|
|
||||||
$rootCondition->notification_rule = $newRule;
|
|
||||||
$rootCondition->save();
|
|
||||||
|
|
||||||
// Add the sub conditions
|
|
||||||
foreach ($conditions as $condition) {
|
|
||||||
$params = array_except($condition, 'condition');
|
|
||||||
$newCondition = new RuleCondition();
|
|
||||||
$newCondition->class_name = array_get($condition, 'condition');
|
|
||||||
$newCondition->parent = $rootCondition;
|
|
||||||
$newCondition->fill($params);
|
|
||||||
$newCondition->forceSave();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $newRule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,164 +0,0 @@
|
||||||
<?php namespace Rainlab\Notify\Models;
|
|
||||||
|
|
||||||
use Model;
|
|
||||||
use Exception;
|
|
||||||
use SystemException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* RuleAction Model
|
|
||||||
*/
|
|
||||||
class RuleAction extends Model
|
|
||||||
{
|
|
||||||
use \October\Rain\Database\Traits\Validation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string The database table used by the model.
|
|
||||||
*/
|
|
||||||
public $table = 'rainlab_notify_rule_actions';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Guarded fields
|
|
||||||
*/
|
|
||||||
protected $guarded = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Fillable fields
|
|
||||||
*/
|
|
||||||
protected $fillable = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array The rules to be applied to the data.
|
|
||||||
*/
|
|
||||||
public $rules = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of attribute names which are json encoded and decoded from the database.
|
|
||||||
*/
|
|
||||||
protected $jsonable = ['config_data'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Relations
|
|
||||||
*/
|
|
||||||
public $belongsTo = [
|
|
||||||
'notification_rule' => [NotificationRule::class, 'key' => 'rule_host_id'],
|
|
||||||
];
|
|
||||||
|
|
||||||
public function triggerAction($params)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$this->getActionObject()->triggerAction($params);
|
|
||||||
}
|
|
||||||
catch (Exception $ex) {
|
|
||||||
// We could log the error here, for now we should suppress
|
|
||||||
// any exceptions to let other actions proceed as normal
|
|
||||||
traceLog('Error with ' . $this->getActionClass());
|
|
||||||
traceLog($ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends this model with the action class
|
|
||||||
* @param string $class Class name
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function applyActionClass($class = null)
|
|
||||||
{
|
|
||||||
if (!$class) {
|
|
||||||
$class = $this->class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$class) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->isClassExtendedWith($class)) {
|
|
||||||
$this->extendClassWith($class);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->class_name = $class;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function beforeSave()
|
|
||||||
{
|
|
||||||
$this->setCustomData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function afterSave()
|
|
||||||
{
|
|
||||||
// Make sure that this record is removed from the DB after being removed from a rule
|
|
||||||
$removedFromRule = $this->rule_host_id === null && $this->getOriginal('rule_host_id');
|
|
||||||
if ($removedFromRule && !$this->notification_rule()->withDeferred(post('_session_key'))->exists()) {
|
|
||||||
$this->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function applyCustomData()
|
|
||||||
{
|
|
||||||
$this->setCustomData();
|
|
||||||
$this->loadCustomData();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadCustomData()
|
|
||||||
{
|
|
||||||
$this->setRawAttributes((array) $this->getAttributes() + (array) $this->config_data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function setCustomData()
|
|
||||||
{
|
|
||||||
if (!$actionObj = $this->getActionObject()) {
|
|
||||||
throw new SystemException(sprintf('Unable to find action object [%s]', $this->getActionClass()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Spin over each field and add it to config_data
|
|
||||||
*/
|
|
||||||
$config = $actionObj->getFieldConfig();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Action class has no fields
|
|
||||||
*/
|
|
||||||
if (!isset($config->fields)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$staticAttributes = ['action_text'];
|
|
||||||
|
|
||||||
$fieldAttributes = array_merge($staticAttributes, array_keys($config->fields));
|
|
||||||
|
|
||||||
$dynamicAttributes = array_only($this->getAttributes(), $fieldAttributes);
|
|
||||||
|
|
||||||
$this->config_data = $dynamicAttributes;
|
|
||||||
|
|
||||||
$this->setRawAttributes(array_except($this->getAttributes(), $fieldAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function afterFetch()
|
|
||||||
{
|
|
||||||
$this->applyActionClass();
|
|
||||||
$this->loadCustomData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
if (strlen($this->action_text)) {
|
|
||||||
return $this->action_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($actionObj = $this->getActionObject()) {
|
|
||||||
return $actionObj->getText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActionObject()
|
|
||||||
{
|
|
||||||
$this->applyActionClass();
|
|
||||||
|
|
||||||
return $this->asExtension($this->getActionClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActionClass()
|
|
||||||
{
|
|
||||||
return $this->class_name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,172 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Models;
|
|
||||||
|
|
||||||
use Model;
|
|
||||||
use RainLab\Notify\Classes\CompoundCondition;
|
|
||||||
use RainLab\Notify\Interfaces\CompoundCondition as CompoundConditionInterface;
|
|
||||||
use SystemException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ConditionRule Model
|
|
||||||
*/
|
|
||||||
class RuleCondition extends Model
|
|
||||||
{
|
|
||||||
use \October\Rain\Database\Traits\Validation;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string The database table used by the model.
|
|
||||||
*/
|
|
||||||
public $table = 'rainlab_notify_rule_conditions';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Guarded fields
|
|
||||||
*/
|
|
||||||
protected $guarded = [];
|
|
||||||
/**
|
|
||||||
* @var array Fillable fields
|
|
||||||
*/
|
|
||||||
protected $fillable = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array The rules to be applied to the data.
|
|
||||||
*/
|
|
||||||
public $rules = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array List of attribute names which are json encoded and decoded from the database.
|
|
||||||
*/
|
|
||||||
protected $jsonable = ['config_data'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var array Relations
|
|
||||||
*/
|
|
||||||
public $hasMany = [
|
|
||||||
'children' => [self::class, 'key' => 'rule_parent_id', 'delete' => true],
|
|
||||||
];
|
|
||||||
|
|
||||||
public $belongsTo = [
|
|
||||||
'parent' => [self::class, 'key' => 'rule_parent_id'],
|
|
||||||
'notification_rule' => [NotificationRule::class, 'key'=>'rule_host_id']
|
|
||||||
];
|
|
||||||
|
|
||||||
public function filterFields($fields, $context)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Let the condition contribute
|
|
||||||
*/
|
|
||||||
$this->getConditionObject()->setFormFields($fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends this model with the condition class
|
|
||||||
* @param string $class Class name
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function applyConditionClass($class = null)
|
|
||||||
{
|
|
||||||
if (!$class) {
|
|
||||||
$class = $this->class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$class) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->isClassExtendedWith($class)) {
|
|
||||||
$this->extendClassWith($class);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->class_name = $class;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function beforeSave()
|
|
||||||
{
|
|
||||||
$this->setCustomData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function applyCustomData()
|
|
||||||
{
|
|
||||||
$this->setCustomData();
|
|
||||||
$this->loadCustomData();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function loadCustomData()
|
|
||||||
{
|
|
||||||
$this->setRawAttributes((array) $this->getAttributes() + (array) $this->config_data, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function setCustomData()
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Let the condition contribute
|
|
||||||
*/
|
|
||||||
$this->getConditionObject()->setCustomData($this);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Spin over each field and add it to config_data
|
|
||||||
*/
|
|
||||||
$config = $this->getFieldConfig();
|
|
||||||
|
|
||||||
if (!isset($config->fields)) {
|
|
||||||
throw new SystemException('Condition class has no fields.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$staticAttributes = ['condition_text'];
|
|
||||||
|
|
||||||
$fieldAttributes = array_merge($staticAttributes, array_keys($config->fields));
|
|
||||||
|
|
||||||
$dynamicAttributes = array_only($this->getAttributes(), $fieldAttributes);
|
|
||||||
|
|
||||||
$this->config_data = $dynamicAttributes;
|
|
||||||
|
|
||||||
$this->setRawAttributes(array_except($this->getAttributes(), $fieldAttributes));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function afterFetch()
|
|
||||||
{
|
|
||||||
$this->applyConditionClass();
|
|
||||||
$this->loadCustomData();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function afterSave()
|
|
||||||
{
|
|
||||||
// Make sure that this record is removed from the DB after being removed from a rule
|
|
||||||
$removedFromRule = $this->rule_parent_id === null && $this->getOriginal('rule_parent_id');
|
|
||||||
if ($removedFromRule && !$this->notification_rule()->withDeferred(post('_session_key'))->exists()) {
|
|
||||||
$this->delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
if (strlen($this->condition_text)) {
|
|
||||||
return $this->condition_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($conditionObj = $this->getConditionObject()) {
|
|
||||||
return $conditionObj->getText();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function isCompound()
|
|
||||||
{
|
|
||||||
return $this->getConditionObject() instanceof CompoundConditionInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConditionObject()
|
|
||||||
{
|
|
||||||
$this->applyConditionClass();
|
|
||||||
|
|
||||||
return $this->asExtension($this->getConditionClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getConditionClass()
|
|
||||||
{
|
|
||||||
return $this->class_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRootConditionClass()
|
|
||||||
{
|
|
||||||
return CompoundCondition::class;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Column Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
columns:
|
|
||||||
|
|
||||||
name:
|
|
||||||
label: rainlab.notify::lang.notifications.name
|
|
||||||
searchable: true
|
|
||||||
|
|
||||||
code:
|
|
||||||
label: rainlab.notify::lang.notifications.code
|
|
||||||
searchable: true
|
|
||||||
|
|
@ -1,47 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
name:
|
|
||||||
label: Name
|
|
||||||
placeholder: New notification rule name
|
|
||||||
attributes:
|
|
||||||
autofocus: 1
|
|
||||||
|
|
||||||
toolbar:
|
|
||||||
type: partial
|
|
||||||
path: form_toolbar
|
|
||||||
cssClass: collapse-visible
|
|
||||||
|
|
||||||
tabs:
|
|
||||||
stretch: true
|
|
||||||
cssClass: master-area
|
|
||||||
paneCssClass:
|
|
||||||
'Actions': 'pane-compact'
|
|
||||||
|
|
||||||
fields:
|
|
||||||
rule_actions:
|
|
||||||
type: RainLab\Notify\FormWidgets\ActionBuilder
|
|
||||||
tab: Actions
|
|
||||||
|
|
||||||
rule_conditions:
|
|
||||||
type: RainLab\Notify\FormWidgets\ConditionBuilder
|
|
||||||
tab: Conditions
|
|
||||||
|
|
||||||
is_enabled:
|
|
||||||
label: Active
|
|
||||||
type: checkbox
|
|
||||||
tab: Settings
|
|
||||||
default: true
|
|
||||||
|
|
||||||
description:
|
|
||||||
label: Description
|
|
||||||
type: textarea
|
|
||||||
size: tiny
|
|
||||||
tab: Settings
|
|
||||||
|
|
||||||
code:
|
|
||||||
label: API Code
|
|
||||||
span: auto
|
|
||||||
tab: Settings
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# List Column Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
columns:
|
|
||||||
id:
|
|
||||||
label: ID
|
|
||||||
searchable: true
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Form Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
id:
|
|
||||||
label: ID
|
|
||||||
disabled: true
|
|
||||||
|
|
@ -1,136 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\NotifyRules;
|
|
||||||
|
|
||||||
use Cms\Classes\Theme;
|
|
||||||
use RainLab\Notify\Classes\ConditionBase;
|
|
||||||
|
|
||||||
class ExecutionContextCondition extends ConditionBase
|
|
||||||
{
|
|
||||||
protected $operators = [
|
|
||||||
'is' => 'is',
|
|
||||||
'is_not' => 'is not',
|
|
||||||
];
|
|
||||||
|
|
||||||
public function getName()
|
|
||||||
{
|
|
||||||
return 'Event is triggered from environment';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
return 'Execution context';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
$host = $this->host;
|
|
||||||
$value = $host->value;
|
|
||||||
$attribute = $host->subcondition;
|
|
||||||
$subconditions = $this->getSubconditionOptions();
|
|
||||||
|
|
||||||
$result = array_get($subconditions, $attribute, 'Execution context');
|
|
||||||
$result .= ' <span class="operator">'.array_get($this->operators, $host->operator, $host->operator).'</span> ';
|
|
||||||
|
|
||||||
if ($attribute == 'locale' || $attribute == 'environment') {
|
|
||||||
$result .= strtolower($value) ?: '?';
|
|
||||||
}
|
|
||||||
elseif ($value) {
|
|
||||||
$options = $this->getValueOptions();
|
|
||||||
$result .= strtolower(array_get($options, $value));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$result .= '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a title to use for grouping subconditions
|
|
||||||
* in the Create Condition drop-down menu
|
|
||||||
*/
|
|
||||||
public function getGroupingTitle()
|
|
||||||
{
|
|
||||||
return 'Execution context';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listSubconditions()
|
|
||||||
{
|
|
||||||
return array_flip($this->getSubconditionOptions());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function initConfigData($host)
|
|
||||||
{
|
|
||||||
$host->operator = 'is';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setFormFields($fields)
|
|
||||||
{
|
|
||||||
$attribute = $fields->subcondition->value;
|
|
||||||
|
|
||||||
if ($attribute == 'locale' || $attribute == 'environment') {
|
|
||||||
$fields->value->type = 'text';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$fields->value->type = 'dropdown';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getValueOptions()
|
|
||||||
{
|
|
||||||
$attribute = $this->host->subcondition;
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
if ($attribute == 'context') {
|
|
||||||
$result = [
|
|
||||||
'backend' => 'Back-end area',
|
|
||||||
'front' => 'Front-end website',
|
|
||||||
'console' => 'Command line interface',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($attribute == 'theme') {
|
|
||||||
foreach (Theme::all() as $theme) {
|
|
||||||
$result[$theme->getDirName()] = $theme->getDirName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSubconditionOptions()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'environment' => 'Application environment',
|
|
||||||
'context' => 'Request context',
|
|
||||||
'theme' => 'Active theme',
|
|
||||||
'locale' => 'Visitor locale',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getOperatorOptions()
|
|
||||||
{
|
|
||||||
return $this->operators;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks whether the condition is TRUE for specified parameters
|
|
||||||
* @param array $params
|
|
||||||
* @return bool
|
|
||||||
*/
|
|
||||||
public function isTrue(&$params)
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
$attribute = $hostObj->subcondition;
|
|
||||||
|
|
||||||
$conditionValue = $hostObj->value;
|
|
||||||
$conditionValue = trim(mb_strtolower($conditionValue));
|
|
||||||
|
|
||||||
if ($attribute == 'locale') {
|
|
||||||
return array_get($params, 'appLocale') == $conditionValue;
|
|
||||||
} else if ($attribute === 'environment') {
|
|
||||||
return $conditionValue === \App::environment();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,125 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\NotifyRules;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Ramsey\Uuid\Uuid;
|
|
||||||
use RainLab\Notify\Classes\ActionBase;
|
|
||||||
use Illuminate\Database\Eloquent\Model as EloquentModel;
|
|
||||||
use ApplicationException;
|
|
||||||
use Illuminate\Support\Arr;
|
|
||||||
use RainLab\User\Models\User;
|
|
||||||
|
|
||||||
class SaveDatabaseAction extends ActionBase
|
|
||||||
{
|
|
||||||
protected $tableDefinitions = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns information about this event, including name and description.
|
|
||||||
*/
|
|
||||||
public function actionDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Store in database',
|
|
||||||
'description' => 'Log event data in the notifications activity log',
|
|
||||||
'icon' => 'icon-database'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
if ($this->host->related_object) {
|
|
||||||
$label = array_get($this->getRelatedObjectOptions(), $this->host->related_object);
|
|
||||||
|
|
||||||
return 'Log event in the '.$label.' log';
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers this action.
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function triggerAction($params)
|
|
||||||
{
|
|
||||||
if (
|
|
||||||
(!$definition = array_get($this->tableDefinitions, $this->host->related_object)) ||
|
|
||||||
(!$param = array_get($definition, 'param', 'user')) ||
|
|
||||||
(!$value = array_get($params, $param))
|
|
||||||
) {
|
|
||||||
throw new ApplicationException('Error evaluating the save database action: the related object is not found in the action parameters.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$value instanceof EloquentModel) {
|
|
||||||
// @todo Perhaps value is an ID or a model array,
|
|
||||||
// look up model $definition[class] from ID ...
|
|
||||||
$model = array_get($definition,'class', User::class);
|
|
||||||
$value = $model::find($value);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
$rule = $this->host->notification_rule;
|
|
||||||
$relation = array_get($definition, 'relation', 'notifications');
|
|
||||||
|
|
||||||
$value->$relation()->create([
|
|
||||||
'id' => Uuid::uuid4()->toString(),
|
|
||||||
'event_type' => $rule->getEventClass(),
|
|
||||||
'icon' => $this->host->icon,
|
|
||||||
'type' => $this->host->type,
|
|
||||||
'body' => $this->host->body,
|
|
||||||
'data' => $this->getData($params),
|
|
||||||
'read_at' => null,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the data for the notification.
|
|
||||||
*
|
|
||||||
* @param array $notifiable
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
protected function getData($params)
|
|
||||||
{
|
|
||||||
// This should check for params that cannot be jsonable.
|
|
||||||
return $params;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRelatedObjectOptions()
|
|
||||||
{
|
|
||||||
$result = [];
|
|
||||||
|
|
||||||
foreach ($this->tableDefinitions as $key => $definition) {
|
|
||||||
$result[$key] = array_get($definition, 'label');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTableDefinitions()
|
|
||||||
{
|
|
||||||
return $this->tableDefinitions;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addTableDefinition($options)
|
|
||||||
{
|
|
||||||
if (!$className = array_get($options, 'class')) {
|
|
||||||
throw new ApplicationException('Missing class name from table definition.');
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = array_merge([
|
|
||||||
'label' => 'Undefined table',
|
|
||||||
'class' => null,
|
|
||||||
'param' => null,
|
|
||||||
'relation' => 'notifications',
|
|
||||||
], $options);
|
|
||||||
|
|
||||||
$keyName = $className . '@' . array_get($options, 'relation');
|
|
||||||
|
|
||||||
$this->tableDefinitions[$keyName] = $options;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\NotifyRules;
|
|
||||||
|
|
||||||
use Illuminate\Support\Facades\Log;
|
|
||||||
use Mail;
|
|
||||||
use Lang;
|
|
||||||
use Config;
|
|
||||||
use System\Models\MailTemplate;
|
|
||||||
use RainLab\Notify\Classes\ActionBase;
|
|
||||||
use Backend\Models\User as AdminUserModel;
|
|
||||||
use Backend\Models\UserGroup as AdminGroupModel;
|
|
||||||
use ApplicationException;
|
|
||||||
|
|
||||||
class SendMailTemplateAction extends ActionBase
|
|
||||||
{
|
|
||||||
public $recipientModes = [
|
|
||||||
'system' => 'System default',
|
|
||||||
'user' => 'User email address (if applicable)',
|
|
||||||
'sender' => 'Sender user email address (if applicable)',
|
|
||||||
'admin' => 'Back-end administrators',
|
|
||||||
'custom' => 'Specific email address',
|
|
||||||
];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns information about this event, including name and description.
|
|
||||||
*/
|
|
||||||
public function actionDetails()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'name' => 'Compose a mail message',
|
|
||||||
'description' => 'Send a message to a recipient',
|
|
||||||
'icon' => 'icon-envelope'
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Triggers this action.
|
|
||||||
* @param array $params
|
|
||||||
* @return void
|
|
||||||
*/
|
|
||||||
public function triggerAction($params)
|
|
||||||
{
|
|
||||||
if($this->host->send_to_mode == 'user' && $params['user']) {
|
|
||||||
if(!$params['user']['email_verified'])
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$template = $this->host->mail_template;
|
|
||||||
|
|
||||||
$recipient = $this->getRecipientAddress($params);
|
|
||||||
|
|
||||||
$replyTo = $this->getReplyToAddress($params);
|
|
||||||
|
|
||||||
if (!$recipient || !$template) {
|
|
||||||
throw new ApplicationException('Missing valid recipient or mail template');
|
|
||||||
}
|
|
||||||
|
|
||||||
Mail::sendTo($recipient, $template, $params, function($message) use ($replyTo) {
|
|
||||||
if ($replyTo) {
|
|
||||||
$message->replyTo($replyTo);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Field configuration for the action.
|
|
||||||
*/
|
|
||||||
public function defineFormFields()
|
|
||||||
{
|
|
||||||
return 'fields.yaml';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines validation rules for the custom fields.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function defineValidationRules()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'mail_template' => 'required',
|
|
||||||
'send_to_mode' => 'required',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTitle()
|
|
||||||
{
|
|
||||||
if ($this->isAdminMode()) {
|
|
||||||
return 'Compose mail to administrators';
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::getTitle();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getActionIcon()
|
|
||||||
{
|
|
||||||
if ($this->isAdminMode()) {
|
|
||||||
return 'icon-envelope-square';
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::getActionIcon();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getText()
|
|
||||||
{
|
|
||||||
$hostObj = $this->host;
|
|
||||||
|
|
||||||
$recipient = array_get($this->recipientModes, $hostObj->send_to_mode);
|
|
||||||
|
|
||||||
if ($this->isAdminMode()) {
|
|
||||||
if ($groupId = $this->host->send_to_admin) {
|
|
||||||
if ($group = AdminGroupModel::find($groupId)) {
|
|
||||||
$adminText = $group->name;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$adminText = '?';
|
|
||||||
}
|
|
||||||
|
|
||||||
$adminText .= ' admin group';
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$adminText = 'all admins';
|
|
||||||
}
|
|
||||||
return sprintf(
|
|
||||||
'Send a message to %s using template %s',
|
|
||||||
$adminText,
|
|
||||||
$hostObj->mail_template
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($hostObj->mail_template) {
|
|
||||||
return sprintf(
|
|
||||||
'Send a message to %s using template %s',
|
|
||||||
mb_strtolower($recipient),
|
|
||||||
$hostObj->mail_template
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::getText();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSendToAdminOptions()
|
|
||||||
{
|
|
||||||
$options = ['' => '- All administrators -'];
|
|
||||||
|
|
||||||
$groups = AdminGroupModel::lists('name', 'id');
|
|
||||||
|
|
||||||
return $options + $groups;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getSendToModeOptions()
|
|
||||||
{
|
|
||||||
$modes = $this->recipientModes;
|
|
||||||
|
|
||||||
unset($modes['system']);
|
|
||||||
|
|
||||||
return $modes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getReplyToModeOptions()
|
|
||||||
{
|
|
||||||
$modes = $this->recipientModes;
|
|
||||||
|
|
||||||
unset($modes['admin']);
|
|
||||||
|
|
||||||
return $modes;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getMailTemplateOptions()
|
|
||||||
{
|
|
||||||
$codes = array_keys(MailTemplate::listAllTemplates());
|
|
||||||
$result = array_combine($codes, $codes);
|
|
||||||
return $result;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getReplyToAddress($params)
|
|
||||||
{
|
|
||||||
$mode = $this->host->reply_to_mode;
|
|
||||||
|
|
||||||
if ($mode == 'custom') {
|
|
||||||
return $this->host->reply_to_custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mode == 'user' || $mode == 'sender') {
|
|
||||||
$obj = array_get($params, $mode);
|
|
||||||
return $obj->email;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getRecipientAddress($params)
|
|
||||||
{
|
|
||||||
$mode = $this->host->send_to_mode;
|
|
||||||
|
|
||||||
if ($mode == 'custom') {
|
|
||||||
return $this->host->send_to_custom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mode == 'system') {
|
|
||||||
$name = Config::get('mail.from.name', 'Your Site');
|
|
||||||
$address = Config::get('mail.from.address', 'admin@domain.tld');
|
|
||||||
return [$address => $name];
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mode == 'admin') {
|
|
||||||
if ($groupId = $this->host->send_to_admin) {
|
|
||||||
if (!$group = AdminGroupModel::find($groupId)) {
|
|
||||||
throw new ApplicationException('Unable to find admin group with ID: '.$groupId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $group->users->lists('full_name', 'email');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return AdminUserModel::all()->lists('full_name', 'email');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mode == 'user' || $mode == 'sender') {
|
|
||||||
return array_get($params, $mode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function isAdminMode()
|
|
||||||
{
|
|
||||||
return $this->host->send_to_mode == 'admin';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,21 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
|
|
||||||
subcondition:
|
|
||||||
label: Attribute
|
|
||||||
span: auto
|
|
||||||
type: dropdown
|
|
||||||
|
|
||||||
operator:
|
|
||||||
label: Operator
|
|
||||||
span: auto
|
|
||||||
type: dropdown
|
|
||||||
dependsOn: subcondition
|
|
||||||
|
|
||||||
value:
|
|
||||||
label: Value
|
|
||||||
dependsOn: [subcondition, operator]
|
|
||||||
type: dropdown
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
related_object:
|
|
||||||
label: Related object
|
|
||||||
type: dropdown
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Field Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
fields:
|
|
||||||
mail_template:
|
|
||||||
label: Mail template
|
|
||||||
type: dropdown
|
|
||||||
placeholder: Select template
|
|
||||||
|
|
||||||
send_to_mode:
|
|
||||||
label: Send to
|
|
||||||
type: radio
|
|
||||||
span: left
|
|
||||||
|
|
||||||
send_to_custom:
|
|
||||||
cssClass: radio-align
|
|
||||||
trigger:
|
|
||||||
action: show
|
|
||||||
field: send_to_mode
|
|
||||||
condition: value[custom]
|
|
||||||
|
|
||||||
send_to_admin:
|
|
||||||
label: Send to admin group
|
|
||||||
span: right
|
|
||||||
type: dropdown
|
|
||||||
trigger:
|
|
||||||
action: show
|
|
||||||
field: send_to_mode
|
|
||||||
condition: value[admin]
|
|
||||||
|
|
||||||
reply_to_mode:
|
|
||||||
label: Reply-to address
|
|
||||||
type: radio
|
|
||||||
span: left
|
|
||||||
|
|
||||||
reply_to_custom:
|
|
||||||
cssClass: radio-align
|
|
||||||
trigger:
|
|
||||||
action: show
|
|
||||||
field: reply_to_mode
|
|
||||||
condition: value[custom]
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Updates;
|
|
||||||
|
|
||||||
use Schema;
|
|
||||||
use October\Rain\Database\Updates\Migration;
|
|
||||||
|
|
||||||
class CreateNotificationRulesTable extends Migration
|
|
||||||
{
|
|
||||||
public function up()
|
|
||||||
{
|
|
||||||
Schema::create('rainlab_notify_notification_rules', function ($table) {
|
|
||||||
$table->engine = 'InnoDB';
|
|
||||||
$table->increments('id');
|
|
||||||
$table->string('name')->nullable();
|
|
||||||
$table->string('code')->index()->nullable();
|
|
||||||
$table->string('class_name')->nullable();
|
|
||||||
$table->text('description')->nullable();
|
|
||||||
$table->mediumText('config_data')->nullable();
|
|
||||||
$table->mediumText('condition_data')->nullable();
|
|
||||||
$table->boolean('is_enabled')->default(0);
|
|
||||||
$table->boolean('is_custom')->default(1);
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down()
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('rainlab_notify_notification_rules');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,28 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Updates;
|
|
||||||
|
|
||||||
use Schema;
|
|
||||||
use October\Rain\Database\Schema\Blueprint;
|
|
||||||
use October\Rain\Database\Updates\Migration;
|
|
||||||
|
|
||||||
class CreateNotificationsTable extends Migration
|
|
||||||
{
|
|
||||||
public function up()
|
|
||||||
{
|
|
||||||
Schema::create('rainlab_notify_notifications', function(Blueprint $table) {
|
|
||||||
$table->uuid('id')->primary();
|
|
||||||
$table->string('event_type');
|
|
||||||
$table->morphs('notifiable');
|
|
||||||
$table->string('icon')->nullable();
|
|
||||||
$table->string('type')->nullable();
|
|
||||||
$table->text('body')->nullable();
|
|
||||||
$table->mediumText('data');
|
|
||||||
$table->timestamp('read_at')->nullable();
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down()
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('rainlab_notify_notifications');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,25 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Updates;
|
|
||||||
|
|
||||||
use Schema;
|
|
||||||
use October\Rain\Database\Schema\Blueprint;
|
|
||||||
use October\Rain\Database\Updates\Migration;
|
|
||||||
|
|
||||||
class CreateRuleActionsTable extends Migration
|
|
||||||
{
|
|
||||||
public function up()
|
|
||||||
{
|
|
||||||
Schema::create('rainlab_notify_rule_actions', function(Blueprint $table) {
|
|
||||||
$table->engine = 'InnoDB';
|
|
||||||
$table->increments('id');
|
|
||||||
$table->string('class_name')->nullable();
|
|
||||||
$table->mediumText('config_data')->nullable();
|
|
||||||
$table->integer('rule_host_id')->unsigned()->nullable()->index();
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down()
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('rainlab_notify_rule_actions');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
<?php namespace RainLab\Notify\Updates;
|
|
||||||
|
|
||||||
use Schema;
|
|
||||||
use October\Rain\Database\Schema\Blueprint;
|
|
||||||
use October\Rain\Database\Updates\Migration;
|
|
||||||
|
|
||||||
class CreateConditionsRulesTable extends Migration
|
|
||||||
{
|
|
||||||
public function up()
|
|
||||||
{
|
|
||||||
Schema::create('rainlab_notify_rule_conditions', function(Blueprint $table) {
|
|
||||||
$table->engine = 'InnoDB';
|
|
||||||
$table->increments('id');
|
|
||||||
$table->string('class_name')->nullable();
|
|
||||||
$table->mediumText('config_data')->nullable();
|
|
||||||
$table->string('condition_control_type', 100)->nullable();
|
|
||||||
$table->string('rule_host_type', 100)->nullable();
|
|
||||||
$table->integer('rule_host_id')->unsigned()->nullable()->index();
|
|
||||||
$table->integer('rule_parent_id')->unsigned()->nullable()->index();
|
|
||||||
$table->index(['rule_host_id', 'rule_host_type'], 'host_rule_id_type');
|
|
||||||
$table->timestamps();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public function down()
|
|
||||||
{
|
|
||||||
Schema::dropIfExists('rainlab_notify_rule_conditions');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
v1.0.1:
|
|
||||||
- First version of Notify
|
|
||||||
- create_notifications_table.php
|
|
||||||
- create_notification_rules_table.php
|
|
||||||
- create_rule_conditions_table.php
|
|
||||||
- create_rule_actions_table.php
|
|
||||||
v1.0.2: Fixes crashing bug.
|
|
||||||
v1.0.3: Added Turkish & Russian translations, various bug fixes.
|
|
||||||
v1.1.0: Fixes support for October CMS 2.0
|
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
.phpunit.result.cache
|
||||||
|
composer.lock
|
||||||
|
vendor
|
||||||
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
use App;
|
use App;
|
||||||
use Auth;
|
use Auth;
|
||||||
use Carbon\Carbon;
|
|
||||||
use Event;
|
use Event;
|
||||||
use Backend;
|
use Backend;
|
||||||
use System\Classes\PluginBase;
|
use System\Classes\PluginBase;
|
||||||
|
|
@ -33,7 +32,7 @@ class Plugin extends PluginBase
|
||||||
public function register()
|
public function register()
|
||||||
{
|
{
|
||||||
$alias = AliasLoader::getInstance();
|
$alias = AliasLoader::getInstance();
|
||||||
$alias->alias('Auth', 'RainLab\User\Facades\Auth');
|
$alias->alias('Auth', \RainLab\User\Facades\Auth::class);
|
||||||
|
|
||||||
App::singleton('user.auth', function () {
|
App::singleton('user.auth', function () {
|
||||||
return \RainLab\User\Classes\AuthManager::instance();
|
return \RainLab\User\Classes\AuthManager::instance();
|
||||||
|
|
@ -70,8 +69,8 @@ class Plugin extends PluginBase
|
||||||
public function registerComponents()
|
public function registerComponents()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
\RainLab\User\Components\Session::class => 'session',
|
\RainLab\User\Components\Session::class => 'session',
|
||||||
\RainLab\User\Components\Account::class => 'account',
|
\RainLab\User\Components\Account::class => 'account',
|
||||||
\RainLab\User\Components\ResetPassword::class => 'resetPassword'
|
\RainLab\User\Components\ResetPassword::class => 'resetPassword'
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
@ -116,12 +115,12 @@ class Plugin extends PluginBase
|
||||||
'url' => Backend::url('rainlab/user/users'),
|
'url' => Backend::url('rainlab/user/users'),
|
||||||
'permissions' => ['rainlab.users.access_users']
|
'permissions' => ['rainlab.users.access_users']
|
||||||
],
|
],
|
||||||
// 'usergroups' => [
|
'usergroups' => [
|
||||||
// 'label' => 'rainlab.user::lang.groups.menu_label',
|
'label' => 'rainlab.user::lang.groups.menu_label',
|
||||||
// 'icon' => 'icon-users',
|
'icon' => 'icon-users',
|
||||||
// 'url' => Backend::url('rainlab/user/usergroups'),
|
'url' => Backend::url('rainlab/user/usergroups'),
|
||||||
// 'permissions' => ['rainlab.users.access_groups']
|
'permissions' => ['rainlab.users.access_groups']
|
||||||
// ]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
|
|
@ -134,7 +133,7 @@ class Plugin extends PluginBase
|
||||||
'label' => 'rainlab.user::lang.settings.menu_label',
|
'label' => 'rainlab.user::lang.settings.menu_label',
|
||||||
'description' => 'rainlab.user::lang.settings.menu_description',
|
'description' => 'rainlab.user::lang.settings.menu_description',
|
||||||
'category' => SettingsManager::CATEGORY_USERS,
|
'category' => SettingsManager::CATEGORY_USERS,
|
||||||
'icon' => 'icon-cog',
|
'icon' => class_exists('System') ? 'octo-icon-user-actions-key' : 'icon-cog',
|
||||||
'class' => 'RainLab\User\Models\Settings',
|
'class' => 'RainLab\User\Models\Settings',
|
||||||
'order' => 500,
|
'order' => 500,
|
||||||
'permissions' => ['rainlab.users.access_settings']
|
'permissions' => ['rainlab.users.access_settings']
|
||||||
|
|
@ -191,28 +190,4 @@ class Plugin extends PluginBase
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerListColumnTypes()
|
|
||||||
{
|
|
||||||
return [
|
|
||||||
'email_verified' => [$this, 'emailVerified'],
|
|
||||||
'phone_verified' => [$this, 'phoneVerified'],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function emailVerified($value, $column, $record){
|
|
||||||
switch ($value){
|
|
||||||
case 0 : return '<span class="btn btn-default btn-xs">Not verified</span>';
|
|
||||||
case 1 : return '<span class="btn btn-primary btn-xs">Verified</span>';
|
|
||||||
default : return $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public function phoneVerified($value, $column, $record){
|
|
||||||
switch ($value){
|
|
||||||
case 0 : return '<span class="btn btn-default btn-xs">Not verified</span>';
|
|
||||||
case 1 : return '<span class="btn btn-primary btn-xs">Verified</span>';
|
|
||||||
default : return $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,25 @@
|
||||||
# Front-end user plugin
|
# Front-end user plugin
|
||||||
|
|
||||||
[](https://github.com/rainlab/user-plugin/actions)
|
|
||||||
[](https://github.com/rainlab/user-plugin/blob/master/LICENCE.md)
|
|
||||||
|
|
||||||
Front-end user management for October CMS.
|
Front-end user management for October CMS.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
This plugin requires the [Ajax Framework](https://octobercms.com/docs/cms/ajax) to be included in your layout/page in order to handle form requests.
|
This plugin requires the [Ajax Framework](https://octobercms.com/docs/cms/ajax) to be included in your layout/page in order to handle form requests.
|
||||||
|
|
||||||
|
## Installation Instructions
|
||||||
|
|
||||||
|
Run the following to install this plugin:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan plugin:install RainLab.User
|
||||||
|
```
|
||||||
|
|
||||||
|
To uninstall this plugin:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
php artisan plugin:remove RainLab.User
|
||||||
|
```
|
||||||
|
|
||||||
## Managing users
|
## Managing users
|
||||||
|
|
||||||
Users are managed on the Users tab found in the back-end. Each user provides minimal data fields - **Name**, **Surname**, **Email** and **Password**. The Name can represent either the person's first name or their full name, making the Surname field optional, depending on the complexity of your site.
|
Users are managed on the Users tab found in the back-end. Each user provides minimal data fields - **Name**, **Surname**, **Email** and **Password**. The Name can represent either the person's first name or their full name, making the Surname field optional, depending on the complexity of your site.
|
||||||
|
|
@ -47,7 +58,17 @@ As a security precaution, you may restrict users from having sessions across mul
|
||||||
|
|
||||||
#### Notifications
|
#### Notifications
|
||||||
|
|
||||||
When a user is first activated -- either by registration, email confirmation or administrator approval -- they are sent a welcome email. To disable the welcome email, select "Do not send a notification" from the **Welcome mail template** dropdown. The default message template used is `rainlab.user::mail.welcome` and you can customize this by selecting **Mail > Mail Templates** from the settings menu.
|
This feature is implemented by the Notify plugin. How to use this feature:
|
||||||
|
|
||||||
|
- Install the **RainLab.Notify** plugin
|
||||||
|
- Navigate to **Settings > Notification** rules
|
||||||
|
- Click **New notification rule**
|
||||||
|
- Select **User > Activated**
|
||||||
|
- Click **Add action**
|
||||||
|
- Select **Compose a mail message**
|
||||||
|
- Select **User email address** for the **Send to** field
|
||||||
|
- Here you may select the Mail template previously defined in the user settings.
|
||||||
|
- Click **Save**
|
||||||
|
|
||||||
## Extended features
|
## Extended features
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,12 +53,12 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
BulkActions.prototype.setActiveItem = function($el) {
|
BulkActions.prototype.setActiveItem = function($el) {
|
||||||
this.$toggleBtn.blur()
|
this.$toggleBtn.blur();
|
||||||
this.activeAction = $el.data('action')
|
this.activeAction = $el.data('action');
|
||||||
this.$primaryBtn.text($el.text())
|
this.$primaryBtn.text($el.text());
|
||||||
this.$primaryBtn.attr('class', this.baseCss)
|
this.$primaryBtn.attr('class', this.baseCss);
|
||||||
this.$primaryBtn.addClass($el.attr('class'))
|
this.$primaryBtn.addClass($el.attr('class')).removeClass('dropdown-item');
|
||||||
this.$primaryBtn.data('request-confirm', $el.data('confirm'))
|
this.$primaryBtn.data('request-confirm', $el.data('confirm'));
|
||||||
}
|
}
|
||||||
|
|
||||||
// BULK ACTIONS PLUGIN DEFINITION
|
// BULK ACTIONS PLUGIN DEFINITION
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<?php namespace RainLab\User\Classes;
|
<?php namespace RainLab\User\Classes;
|
||||||
|
|
||||||
|
use Event;
|
||||||
use October\Rain\Auth\Manager as RainAuthManager;
|
use October\Rain\Auth\Manager as RainAuthManager;
|
||||||
use RainLab\User\Models\Settings as UserSettings;
|
use RainLab\User\Models\Settings as UserSettings;
|
||||||
use RainLab\User\Models\UserGroup as UserGroupModel;
|
use RainLab\User\Models\UserGroup as UserGroupModel;
|
||||||
|
|
@ -29,6 +30,9 @@ class AuthManager extends RainAuthManager
|
||||||
public function extendUserQuery($query)
|
public function extendUserQuery($query)
|
||||||
{
|
{
|
||||||
$query->withTrashed();
|
$query->withTrashed();
|
||||||
|
|
||||||
|
// Extensibility
|
||||||
|
Event::fire('rainlab.user.extendUserAuthQuery', [$query]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -43,6 +47,25 @@ class AuthManager extends RainAuthManager
|
||||||
return parent::register($credentials, $activate, $autoLogin);
|
return parent::register($credentials, $activate, $autoLogin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* findUserByEmail finds a user by the email value, which includes
|
||||||
|
* deactivated (trashed) user records.
|
||||||
|
* @param string $email
|
||||||
|
* @return Authenticatable|null
|
||||||
|
*/
|
||||||
|
public function findUserByEmail($email)
|
||||||
|
{
|
||||||
|
if (!$email) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->createUserModelQuery();
|
||||||
|
|
||||||
|
$user = $query->where('email', $email)->first();
|
||||||
|
|
||||||
|
return $this->validateUserModel($user) ? $user : null;
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Guest users
|
// Guest users
|
||||||
//
|
//
|
||||||
|
|
@ -60,10 +83,11 @@ class AuthManager extends RainAuthManager
|
||||||
{
|
{
|
||||||
$query = $this->createUserModelQuery();
|
$query = $this->createUserModelQuery();
|
||||||
|
|
||||||
return $user = $query
|
return $query
|
||||||
->where('email', $email)
|
->where('email', $email)
|
||||||
->where('is_guest', 1)
|
->where('is_guest', 1)
|
||||||
->first();
|
->first()
|
||||||
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -17,8 +17,6 @@ use Cms\Classes\ComponentBase;
|
||||||
use RainLab\User\Models\User as UserModel;
|
use RainLab\User\Models\User as UserModel;
|
||||||
use RainLab\User\Models\Settings as UserSettings;
|
use RainLab\User\Models\Settings as UserSettings;
|
||||||
use Exception;
|
use Exception;
|
||||||
use Throwable;
|
|
||||||
use TPS\Birzha\Classes\SMS;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account component
|
* Account component
|
||||||
|
|
@ -28,11 +26,6 @@ use TPS\Birzha\Classes\SMS;
|
||||||
*/
|
*/
|
||||||
class Account extends ComponentBase
|
class Account extends ComponentBase
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* Validation messages
|
|
||||||
*/
|
|
||||||
public $accountValidationMsgs;
|
|
||||||
|
|
||||||
public function componentDetails()
|
public function componentDetails()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|
@ -56,6 +49,12 @@ class Account extends ComponentBase
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'default' => 'code'
|
'default' => 'code'
|
||||||
],
|
],
|
||||||
|
'activationPage' => [
|
||||||
|
'title' => /* Activation Page */'rainlab.user::lang.account.activation_page',
|
||||||
|
'description' => /* Select a page to use for activating the user account */'rainlab.user::lang.account.activation_page_comment',
|
||||||
|
'type' => 'dropdown',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
'forceSecure' => [
|
'forceSecure' => [
|
||||||
'title' => /*Force secure protocol*/'rainlab.user::lang.account.force_secure',
|
'title' => /*Force secure protocol*/'rainlab.user::lang.account.force_secure',
|
||||||
'description' => /*Always redirect the URL with the HTTPS schema.*/'rainlab.user::lang.account.force_secure_desc',
|
'description' => /*Always redirect the URL with the HTTPS schema.*/'rainlab.user::lang.account.force_secure_desc',
|
||||||
|
|
@ -68,19 +67,28 @@ class Account extends ComponentBase
|
||||||
'type' => 'checkbox',
|
'type' => 'checkbox',
|
||||||
'default' => 0
|
'default' => 0
|
||||||
],
|
],
|
||||||
'view' => [
|
|
||||||
'title' => 'View',
|
|
||||||
'description' => 'Choose view type',
|
|
||||||
'type' => 'dropdown',
|
|
||||||
'options' => ['signin','signup','profile'],
|
|
||||||
'default' => 'signin'
|
|
||||||
]
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getRedirectOptions
|
||||||
|
*/
|
||||||
public function getRedirectOptions()
|
public function getRedirectOptions()
|
||||||
{
|
{
|
||||||
return [''=>'- refresh page -', '0' => '- no redirect -'] + Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
|
return [
|
||||||
|
'' => '- refresh page -',
|
||||||
|
'0' => '- no redirect -'
|
||||||
|
] + Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getActivationPageOptions
|
||||||
|
*/
|
||||||
|
public function getActivationPageOptions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'' => '- current page -',
|
||||||
|
] + Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -111,9 +119,9 @@ class Account extends ComponentBase
|
||||||
/*
|
/*
|
||||||
* Activation code supplied
|
* Activation code supplied
|
||||||
*/
|
*/
|
||||||
// if ($code = $this->activationCode()) {
|
if ($code = $this->activationCode()) {
|
||||||
// $this->onActivate($code);
|
$this->onActivate($code);
|
||||||
// }
|
}
|
||||||
|
|
||||||
$this->prepareVars();
|
$this->prepareVars();
|
||||||
}
|
}
|
||||||
|
|
@ -177,6 +185,23 @@ class Account extends ComponentBase
|
||||||
return UserSettings::get('remember_login', UserSettings::REMEMBER_ALWAYS);
|
return UserSettings::get('remember_login', UserSettings::REMEMBER_ALWAYS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* useRememberLogin returns true if persistent authentication should be used.
|
||||||
|
*/
|
||||||
|
protected function useRememberLogin(): bool
|
||||||
|
{
|
||||||
|
switch ($this->rememberLoginMode()) {
|
||||||
|
case UserSettings::REMEMBER_ALWAYS:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case UserSettings::REMEMBER_NEVER:
|
||||||
|
return false;
|
||||||
|
|
||||||
|
case UserSettings::REMEMBER_ASK:
|
||||||
|
return (bool) post('remember', false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for the activation code from the URL parameter. If nothing
|
* Looks for the activation code from the URL parameter. If nothing
|
||||||
* is found, the GET parameter 'activate' is used instead.
|
* is found, the GET parameter 'activate' is used instead.
|
||||||
|
|
@ -213,7 +238,7 @@ class Account extends ComponentBase
|
||||||
? 'required|between:2,255'
|
? 'required|between:2,255'
|
||||||
: 'required|email|between:6,255';
|
: 'required|email|between:6,255';
|
||||||
|
|
||||||
$rules['password'] = 'required|between:4,255';
|
$rules['password'] = 'required|between:' . UserModel::getMinPasswordLength() . ',255';
|
||||||
|
|
||||||
if (!array_key_exists('login', $data)) {
|
if (!array_key_exists('login', $data)) {
|
||||||
$data['login'] = post('username', post('email'));
|
$data['login'] = post('username', post('email'));
|
||||||
|
|
@ -221,7 +246,13 @@ class Account extends ComponentBase
|
||||||
|
|
||||||
$data['login'] = trim($data['login']);
|
$data['login'] = trim($data['login']);
|
||||||
|
|
||||||
$validation = Validator::make($data, $rules);
|
$validation = Validator::make(
|
||||||
|
$data,
|
||||||
|
$rules,
|
||||||
|
$this->getValidatorMessages(),
|
||||||
|
$this->getCustomAttributes()
|
||||||
|
);
|
||||||
|
|
||||||
if ($validation->fails()) {
|
if ($validation->fails()) {
|
||||||
throw new ValidationException($validation);
|
throw new ValidationException($validation);
|
||||||
}
|
}
|
||||||
|
|
@ -230,31 +261,16 @@ class Account extends ComponentBase
|
||||||
* Authenticate user
|
* Authenticate user
|
||||||
*/
|
*/
|
||||||
$credentials = [
|
$credentials = [
|
||||||
'login' => array_get($data, 'dial_code') . array_get($data, 'login'),
|
'login' => array_get($data, 'login'),
|
||||||
'password' => array_get($data, 'password')
|
'password' => array_get($data, 'password')
|
||||||
];
|
];
|
||||||
|
|
||||||
/*
|
|
||||||
* Login remember mode
|
|
||||||
*/
|
|
||||||
switch ($this->rememberLoginMode()) {
|
|
||||||
case UserSettings::REMEMBER_ALWAYS:
|
|
||||||
$remember = true;
|
|
||||||
break;
|
|
||||||
case UserSettings::REMEMBER_NEVER:
|
|
||||||
$remember = false;
|
|
||||||
break;
|
|
||||||
case UserSettings::REMEMBER_ASK:
|
|
||||||
$remember = (bool) array_get($data, 'remember', false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
Event::fire('rainlab.user.beforeAuthenticate', [$this, $credentials]);
|
Event::fire('rainlab.user.beforeAuthenticate', [$this, $credentials]);
|
||||||
|
|
||||||
$user = Auth::authenticate($credentials, $remember);
|
$user = Auth::authenticate($credentials, $this->useRememberLogin());
|
||||||
if ($user->isBanned()) {
|
if ($user->isBanned()) {
|
||||||
Auth::logout();
|
Auth::logout();
|
||||||
throw new AuthException(/*Sorry, this user is currently not activated. Please contact us for further assistance.*/'rainlab.user::lang.account.banned');
|
throw new AuthException(Lang::get(/*Sorry, this user is currently not activated. Please contact us for further assistance.*/'rainlab.user::lang.account.banned'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -272,12 +288,7 @@ class Account extends ComponentBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception $ex) {
|
catch (Exception $ex) {
|
||||||
if ($ex instanceof AuthException) {
|
if (Request::ajax()) throw $ex;
|
||||||
throw new ValidationException(['no_user' => trans('validation.no_user')]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (Request::ajax()) throw $ex;
|
|
||||||
if (Request::ajax()) info($ex);
|
|
||||||
else Flash::error($ex->getMessage());
|
else Flash::error($ex->getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -305,27 +316,19 @@ class Account extends ComponentBase
|
||||||
$data['password_confirmation'] = post('password');
|
$data['password_confirmation'] = post('password');
|
||||||
}
|
}
|
||||||
|
|
||||||
$rules = array_merge((new UserModel)->rules, [
|
$rules = (new UserModel)->rules;
|
||||||
'username' => [
|
|
||||||
'required',
|
|
||||||
'numeric',
|
|
||||||
'unique' => function($attribute, $value, $fail) use($data) {
|
|
||||||
$u = UserModel::where('username', $data['dial_code'] . $value)->first();
|
|
||||||
if(!is_null($u)) $fail(trans('validation.auth_profile.phone_number_unique'));
|
|
||||||
}
|
|
||||||
],
|
|
||||||
]);
|
|
||||||
|
|
||||||
if ($this->loginAttribute() !== UserSettings::LOGIN_USERNAME) {
|
if ($this->loginAttribute() !== UserSettings::LOGIN_USERNAME) {
|
||||||
unset($rules['username']);
|
unset($rules['username']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$validation = Validator::make($data, $rules, [
|
$validation = Validator::make(
|
||||||
'username.required' => trans('validation.auth_profile.phone_number_required'),
|
$data,
|
||||||
'username.numeric' => trans('validation.auth_profile.phone_number_numeric'),
|
$rules,
|
||||||
'username.digits_between' => trans('validation.auth_profile.phone_number_digits_between'),
|
$this->getValidatorMessages(),
|
||||||
'username.unique' => trans('validation.auth_profile.phone_number_unique'),
|
$this->getCustomAttributes()
|
||||||
]);
|
);
|
||||||
|
|
||||||
if ($validation->fails()) {
|
if ($validation->fails()) {
|
||||||
throw new ValidationException($validation);
|
throw new ValidationException($validation);
|
||||||
}
|
}
|
||||||
|
|
@ -346,9 +349,6 @@ class Account extends ComponentBase
|
||||||
$automaticActivation = UserSettings::get('activate_mode') == UserSettings::ACTIVATE_AUTO;
|
$automaticActivation = UserSettings::get('activate_mode') == UserSettings::ACTIVATE_AUTO;
|
||||||
$userActivation = UserSettings::get('activate_mode') == UserSettings::ACTIVATE_USER;
|
$userActivation = UserSettings::get('activate_mode') == UserSettings::ACTIVATE_USER;
|
||||||
$adminActivation = UserSettings::get('activate_mode') == UserSettings::ACTIVATE_ADMIN;
|
$adminActivation = UserSettings::get('activate_mode') == UserSettings::ACTIVATE_ADMIN;
|
||||||
// $user = Auth::register(array_merge($data, [
|
|
||||||
// 'username' => $data['dial_code'] . $data['username']
|
|
||||||
// ]), $automaticActivation);
|
|
||||||
$user = Auth::register($data, $automaticActivation);
|
$user = Auth::register($data, $automaticActivation);
|
||||||
|
|
||||||
Event::fire('rainlab.user.register', [$user, $data]);
|
Event::fire('rainlab.user.register', [$user, $data]);
|
||||||
|
|
@ -357,12 +357,13 @@ class Account extends ComponentBase
|
||||||
* Activation is by the user, send the email
|
* Activation is by the user, send the email
|
||||||
*/
|
*/
|
||||||
if ($userActivation) {
|
if ($userActivation) {
|
||||||
// $this->sendActivationEmail($user);
|
$this->sendActivationEmail($user);
|
||||||
//
|
|
||||||
// Flash::success(Lang::get(/*An activation email has been sent to your email address.*/'rainlab.user::lang.account.activation_email_sent'));
|
Flash::success(Lang::get(/*An activation email has been sent to your email address.*/'rainlab.user::lang.account.activation_email_sent'));
|
||||||
//todo open activation view
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$intended = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Activation is by the admin, show message
|
* Activation is by the admin, show message
|
||||||
* For automatic email on account activation RainLab.Notify plugin is needed
|
* For automatic email on account activation RainLab.Notify plugin is needed
|
||||||
|
|
@ -375,17 +376,16 @@ class Account extends ComponentBase
|
||||||
* Automatically activated or not required, log the user in
|
* Automatically activated or not required, log the user in
|
||||||
*/
|
*/
|
||||||
if ($automaticActivation || !$requireActivation) {
|
if ($automaticActivation || !$requireActivation) {
|
||||||
Auth::login($user);
|
Auth::login($user, $this->useRememberLogin());
|
||||||
|
$intended = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Redirect to the intended page after successful sign in
|
* Redirect to the intended page after successful sign in
|
||||||
*/
|
*/
|
||||||
// if ($redirect = $this->makeRedirection(true)) {
|
if ($redirect = $this->makeRedirection($intended)) {
|
||||||
// return $redirect;
|
return $redirect;
|
||||||
// }
|
}
|
||||||
|
|
||||||
return \Redirect::to('/profile');
|
|
||||||
}
|
}
|
||||||
catch (Exception $ex) {
|
catch (Exception $ex) {
|
||||||
if (Request::ajax()) throw $ex;
|
if (Request::ajax()) throw $ex;
|
||||||
|
|
@ -393,108 +393,6 @@ class Account extends ComponentBase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Send sms with 6 digits code to user
|
|
||||||
*/
|
|
||||||
public function onSendSmsCode()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
if($this->user()->dial_code == '+993' && !$this->user()->phone_verified) {
|
|
||||||
$code = random_int(1000, 9999);
|
|
||||||
|
|
||||||
$result = SMS::send(str_replace(array('+', ' ', '(' , ')', '-'), '', $this->user()->username), $code);
|
|
||||||
// $result = 0;
|
|
||||||
\Log::info('send sms result');
|
|
||||||
\Log::info($result);
|
|
||||||
|
|
||||||
switch ($result) {
|
|
||||||
case 0:
|
|
||||||
$this->user()->phone_activation_code = $code;
|
|
||||||
$this->user()->save();
|
|
||||||
\Log::info('case 0');
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
return \Redirect::to('/error');
|
|
||||||
\Log::info('case 1');
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
return \Redirect::to('/error');
|
|
||||||
\Log::info('case default');
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(Throwable $th) {
|
|
||||||
\Log::info($th);
|
|
||||||
return \Redirect::to('/error');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check SMS code sent by user
|
|
||||||
*/
|
|
||||||
public function onCheckSmsCode()
|
|
||||||
{
|
|
||||||
$data = post();
|
|
||||||
|
|
||||||
$validator = \Validator::make($data, [
|
|
||||||
'sms_code' => 'required|digits:4',
|
|
||||||
]);
|
|
||||||
if($validator->fails()) {
|
|
||||||
throw new ValidationException($validator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if($this->user()->phone_activation_code == $data['sms_code']) {
|
|
||||||
$this->user()->phone_verified = true;
|
|
||||||
$this->user()->phone_activation_code = null;
|
|
||||||
$this->user()->save();
|
|
||||||
|
|
||||||
Flash::success(Lang::get('rainlab.user::lang.account.phone_verified_message'));
|
|
||||||
|
|
||||||
return \Redirect::to('profile');
|
|
||||||
} else {
|
|
||||||
Flash::error(Lang::get('rainlab.user::lang.account.phone_verification_code_invalid'));
|
|
||||||
|
|
||||||
return \Redirect::to('profile');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send email with the verification link to the user
|
|
||||||
*/
|
|
||||||
public function onSendEmailVerificationLink()
|
|
||||||
{
|
|
||||||
if(!$this->user()->email_verified) {
|
|
||||||
$code = sha1(time());
|
|
||||||
$vars = [
|
|
||||||
'verification_link' => $this->controller->pageUrl('kabinet/verify_email.htm', [
|
|
||||||
'id' => $this->user()->id, 'code' => $code
|
|
||||||
])
|
|
||||||
];
|
|
||||||
|
|
||||||
try {
|
|
||||||
\Mail::queue('tps.birzha::mail.' . app()->getLocale() . '.email_verify', $vars, function($message) {
|
|
||||||
$message->to($this->user()->email, 'Birzha User');
|
|
||||||
$message->subject(\Lang::get('rainlab.user::lang.account.email_verification'));
|
|
||||||
});
|
|
||||||
} catch(Throwable $th) {
|
|
||||||
\Log::info($th);
|
|
||||||
|
|
||||||
Flash::error('Ошибка. Неверный Email.');
|
|
||||||
|
|
||||||
return \Redirect::to('profile');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->user()->email_activation_code = $code;
|
|
||||||
$this->user()->save();
|
|
||||||
|
|
||||||
Flash::success(\Lang::get('rainlab.user::lang.account.email_verification_check_message'));
|
|
||||||
|
|
||||||
return \Redirect::to('profile');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Activate the user
|
* Activate the user
|
||||||
* @param string $code Activation code
|
* @param string $code Activation code
|
||||||
|
|
@ -533,7 +431,7 @@ class Account extends ComponentBase
|
||||||
/*
|
/*
|
||||||
* Sign in the user
|
* Sign in the user
|
||||||
*/
|
*/
|
||||||
Auth::login($user);
|
Auth::login($user, $this->useRememberLogin());
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception $ex) {
|
catch (Exception $ex) {
|
||||||
|
|
@ -551,28 +449,7 @@ class Account extends ComponentBase
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$data = Input::except(['username']);
|
$data = post();
|
||||||
|
|
||||||
$rules = [
|
|
||||||
'email' => 'required|between:6,191|email',
|
|
||||||
'name' => 'required',
|
|
||||||
'surname' => 'required',
|
|
||||||
// 'username' => 'required|digits_between:8,20|numeric',
|
|
||||||
'iu_company' => 'max:191',
|
|
||||||
'iu_about' => 'digits:6|numeric',
|
|
||||||
];
|
|
||||||
|
|
||||||
$validation = Validator::make($data, $rules, [
|
|
||||||
'username.required' => trans('validation.auth_profile.phone_number_required'),
|
|
||||||
'username.numeric' => trans('validation.auth_profile.phone_number_numeric'),
|
|
||||||
'username.digits_between' => trans('validation.auth_profile.phone_number_digits_between'),
|
|
||||||
'username.unique' => trans('validation.auth_profile.phone_number_unique'),
|
|
||||||
'zip.digits' => trans('validation.auth_profile.iu_about_digits'),
|
|
||||||
'company.max' => trans('validation.auth_profile.iu_company_max'),
|
|
||||||
]);
|
|
||||||
if ($validation->fails()) {
|
|
||||||
throw new ValidationException($validation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->updateRequiresPassword()) {
|
if ($this->updateRequiresPassword()) {
|
||||||
if (!$user->checkHashValue('password', $data['password_current'])) {
|
if (!$user->checkHashValue('password', $data['password_current'])) {
|
||||||
|
|
@ -584,11 +461,6 @@ class Account extends ComponentBase
|
||||||
$user->avatar = Input::file('avatar');
|
$user->avatar = Input::file('avatar');
|
||||||
}
|
}
|
||||||
|
|
||||||
if($user->email != $data['email']) {
|
|
||||||
$user->email_verified = false;
|
|
||||||
$user->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$user->fill($data);
|
$user->fill($data);
|
||||||
$user->save();
|
$user->save();
|
||||||
|
|
||||||
|
|
@ -596,9 +468,14 @@ class Account extends ComponentBase
|
||||||
* Password has changed, reauthenticate the user
|
* Password has changed, reauthenticate the user
|
||||||
*/
|
*/
|
||||||
if (array_key_exists('password', $data) && strlen($data['password'])) {
|
if (array_key_exists('password', $data) && strlen($data['password'])) {
|
||||||
Auth::login($user->reload(), true);
|
Auth::login($user->reload(), $this->useRememberLogin());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Update Event to hook into the plugins function
|
||||||
|
*/
|
||||||
|
Event::fire('rainlab.user.update', [$user, $data]);
|
||||||
|
|
||||||
Flash::success(post('flash', Lang::get(/*Settings successfully saved!*/'rainlab.user::lang.account.success_saved')));
|
Flash::success(post('flash', Lang::get(/*Settings successfully saved!*/'rainlab.user::lang.account.success_saved')));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -728,12 +605,13 @@ class Account extends ComponentBase
|
||||||
{
|
{
|
||||||
$method = $intended ? 'intended' : 'to';
|
$method = $intended ? 'intended' : 'to';
|
||||||
|
|
||||||
$property = trim((string) $this->property('redirect'));
|
$property = post('redirect', $this->property('redirect'));
|
||||||
|
|
||||||
// No redirect
|
// No redirect
|
||||||
if ($property === '0') {
|
if ($property === '0') {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Refresh page
|
// Refresh page
|
||||||
if ($property === '') {
|
if ($property === '') {
|
||||||
return Redirect::refresh();
|
return Redirect::refresh();
|
||||||
|
|
@ -741,7 +619,7 @@ class Account extends ComponentBase
|
||||||
|
|
||||||
$redirectUrl = $this->pageUrl($property) ?: $property;
|
$redirectUrl = $this->pageUrl($property) ?: $property;
|
||||||
|
|
||||||
if ($redirectUrl = post('redirect', $redirectUrl)) {
|
if ($redirectUrl) {
|
||||||
return Redirect::$method($redirectUrl);
|
return Redirect::$method($redirectUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -776,4 +654,26 @@ class Account extends ComponentBase
|
||||||
|
|
||||||
return UserModel::isRegisterThrottled(Request::ip());
|
return UserModel::isRegisterThrottled(Request::ip());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getValidatorMessages
|
||||||
|
*/
|
||||||
|
protected function getValidatorMessages(): array
|
||||||
|
{
|
||||||
|
return (array) (new UserModel)->customMessages;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getCustomAttributes
|
||||||
|
*/
|
||||||
|
protected function getCustomAttributes(): array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'login' => $this->loginAttributeLabel(),
|
||||||
|
'password' => Lang::get('rainlab.user::lang.account.password'),
|
||||||
|
'email' => Lang::get('rainlab.user::lang.account.email'),
|
||||||
|
'username' => Lang::get('rainlab.user::lang.user.username'),
|
||||||
|
'name' => Lang::get('rainlab.user::lang.account.full_name')
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,12 @@ use Mail;
|
||||||
use Validator;
|
use Validator;
|
||||||
use ValidationException;
|
use ValidationException;
|
||||||
use ApplicationException;
|
use ApplicationException;
|
||||||
|
use Cms\Classes\Page;
|
||||||
use Cms\Classes\ComponentBase;
|
use Cms\Classes\ComponentBase;
|
||||||
use RainLab\User\Models\User as UserModel;
|
use RainLab\User\Models\User as UserModel;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password reset workflow
|
* ResetPassword controls the password reset workflow
|
||||||
*
|
*
|
||||||
* When a user has forgotten their password, they are able to reset it using
|
* When a user has forgotten their password, they are able to reset it using
|
||||||
* a unique token that, sent to their email address upon request.
|
* a unique token that, sent to their email address upon request.
|
||||||
|
|
@ -33,10 +34,26 @@ class ResetPassword extends ComponentBase
|
||||||
'description' => /*The page URL parameter used for the reset code*/'rainlab.user::lang.reset_password.code_param_desc',
|
'description' => /*The page URL parameter used for the reset code*/'rainlab.user::lang.reset_password.code_param_desc',
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'default' => 'code'
|
'default' => 'code'
|
||||||
]
|
],
|
||||||
|
'resetPage' => [
|
||||||
|
'title' => /* Reset Page */'rainlab.user::lang.account.reset_page',
|
||||||
|
'description' => /* Select a page to use for resetting the account password */'rainlab.user::lang.account.reset_page_comment',
|
||||||
|
'type' => 'dropdown',
|
||||||
|
'default' => ''
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getResetPageOptions
|
||||||
|
*/
|
||||||
|
public function getResetPageOptions()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'' => '- current page -',
|
||||||
|
] + Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Properties
|
// Properties
|
||||||
//
|
//
|
||||||
|
|
@ -74,8 +91,8 @@ class ResetPassword extends ComponentBase
|
||||||
throw new ValidationException($validation);
|
throw new ValidationException($validation);
|
||||||
}
|
}
|
||||||
|
|
||||||
$user = UserModel::findByEmail(post('email'));
|
$user = Auth::findUserByEmail(post('email'));
|
||||||
if (!$user || $user->is_guest) {
|
if (!$user || $user->is_guest || $user->trashed()) {
|
||||||
throw new ApplicationException(Lang::get(/*A user was not found with the given credentials.*/'rainlab.user::lang.account.invalid_user'));
|
throw new ApplicationException(Lang::get(/*A user was not found with the given credentials.*/'rainlab.user::lang.account.invalid_user'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,7 +107,7 @@ class ResetPassword extends ComponentBase
|
||||||
'code' => $code
|
'code' => $code
|
||||||
];
|
];
|
||||||
|
|
||||||
Mail::queue('tps.birzha::mail.' . app()->getLocale() . '.reset_password', $data, function($message) use ($user) {
|
Mail::send('rainlab.user::mail.restore', $data, function($message) use ($user) {
|
||||||
$message->to($user->email, $user->full_name);
|
$message->to($user->email, $user->full_name);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -133,6 +150,11 @@ class ResetPassword extends ComponentBase
|
||||||
if (!$user->attemptResetPassword($code, post('password'))) {
|
if (!$user->attemptResetPassword($code, post('password'))) {
|
||||||
throw new ValidationException($errorFields);
|
throw new ValidationException($errorFields);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check needed for compatibility with legacy systems
|
||||||
|
if (method_exists(\RainLab\User\Classes\AuthManager::class, 'clearThrottleForUserId')) {
|
||||||
|
Auth::clearThrottleForUserId($user->id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -140,7 +162,7 @@ class ResetPassword extends ComponentBase
|
||||||
//
|
//
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a link used to reset the user account.
|
* makeResetUrl returns a link used to reset the user account.
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function makeResetUrl($code)
|
protected function makeResetUrl($code)
|
||||||
|
|
@ -149,10 +171,14 @@ class ResetPassword extends ComponentBase
|
||||||
$this->property('paramCode') => $code
|
$this->property('paramCode') => $code
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// Locate the current page
|
||||||
|
$url = '';
|
||||||
|
|
||||||
if ($pageName = $this->property('resetPage')) {
|
if ($pageName = $this->property('resetPage')) {
|
||||||
$url = $this->pageUrl($pageName, $params);
|
$url = $this->pageUrl($pageName, $params);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if (!$url) {
|
||||||
$url = $this->currentPageUrl($params);
|
$url = $this->currentPageUrl($params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,14 @@ use Auth;
|
||||||
use Event;
|
use Event;
|
||||||
use Flash;
|
use Flash;
|
||||||
use Request;
|
use Request;
|
||||||
use Response;
|
|
||||||
use Redirect;
|
use Redirect;
|
||||||
use Cms\Classes\Page;
|
use Cms\Classes\Page;
|
||||||
use Cms\Classes\ComponentBase;
|
use Cms\Classes\ComponentBase;
|
||||||
use RainLab\User\Models\UserGroup;
|
use RainLab\User\Models\UserGroup;
|
||||||
use ValidationException;
|
use SystemException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User session
|
* Session component
|
||||||
*
|
*
|
||||||
* This will inject the user object to every page and provide the ability for
|
* This will inject the user object to every page and provide the ability for
|
||||||
* the user to sign out. This can also be used to restrict access to pages.
|
* the user to sign out. This can also be used to restrict access to pages.
|
||||||
|
|
@ -62,11 +61,17 @@ class Session extends ComponentBase
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getRedirectOptions
|
||||||
|
*/
|
||||||
public function getRedirectOptions()
|
public function getRedirectOptions()
|
||||||
{
|
{
|
||||||
return [''=>'- none -'] + Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
|
return [''=>'- none -'] + Page::sortBy('baseFileName')->lists('baseFileName', 'baseFileName');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getAllowedUserGroupsOptions
|
||||||
|
*/
|
||||||
public function getAllowedUserGroupsOptions()
|
public function getAllowedUserGroupsOptions()
|
||||||
{
|
{
|
||||||
return UserGroup::lists('name','code');
|
return UserGroup::lists('name','code');
|
||||||
|
|
@ -77,9 +82,12 @@ class Session extends ComponentBase
|
||||||
*/
|
*/
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
if (Request::ajax() && !$this->checkUserSecurity()) {
|
// Inject security logic pre-AJAX
|
||||||
abort(403, 'Access denied');
|
$this->controller->bindEvent('page.init', function() {
|
||||||
}
|
if (Request::ajax() && ($redirect = $this->checkUserSecurityRedirect())) {
|
||||||
|
return ['X_OCTOBER_REDIRECT' => $redirect->getTargetUrl()];
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -87,13 +95,8 @@ class Session extends ComponentBase
|
||||||
*/
|
*/
|
||||||
public function onRun()
|
public function onRun()
|
||||||
{
|
{
|
||||||
if (!$this->checkUserSecurity()) {
|
if ($redirect = $this->checkUserSecurityRedirect()) {
|
||||||
if (empty($this->property('redirect'))) {
|
return $redirect;
|
||||||
throw new \InvalidArgumentException('Redirect property is empty');
|
|
||||||
}
|
|
||||||
|
|
||||||
$redirectUrl = $this->controller->pageUrl($this->property('redirect'));
|
|
||||||
return Redirect::guest($redirectUrl);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->page['user'] = $this->user();
|
$this->page['user'] = $this->user();
|
||||||
|
|
@ -172,13 +175,31 @@ class Session extends ComponentBase
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if the user can access this page based on the security rules
|
* checkUserSecurityRedirect will return a redirect if the user cannot access the page.
|
||||||
* @return bool
|
|
||||||
*/
|
*/
|
||||||
protected function checkUserSecurity()
|
protected function checkUserSecurityRedirect()
|
||||||
|
{
|
||||||
|
// No security layer enabled
|
||||||
|
if ($this->checkUserSecurity()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$this->property('redirect')) {
|
||||||
|
throw new SystemException('Redirect property is empty on Session component.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$redirectUrl = $this->controller->pageUrl($this->property('redirect'));
|
||||||
|
|
||||||
|
return Redirect::guest($redirectUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* checkUserSecurity checks if the user can access this page based on the security rules.
|
||||||
|
*/
|
||||||
|
protected function checkUserSecurity(): bool
|
||||||
{
|
{
|
||||||
$allowedGroup = $this->property('security', self::ALLOW_ALL);
|
$allowedGroup = $this->property('security', self::ALLOW_ALL);
|
||||||
$allowedUserGroups = $this->property('allowedUserGroups', []);
|
$allowedUserGroups = (array) $this->property('allowedUserGroups', []);
|
||||||
$isAuthenticated = Auth::check();
|
$isAuthenticated = Auth::check();
|
||||||
|
|
||||||
if ($isAuthenticated) {
|
if ($isAuthenticated) {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
<div class="pass_mail">
|
|
||||||
<div class="pass_title">
|
|
||||||
{{ 'auth.password_reset_check'|_ }}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,14 +1 @@
|
||||||
<div class="pass_mail">
|
<p>Password reset complete, you may now sign in.</p>
|
||||||
<div class="pass_title">
|
|
||||||
{{ 'auth.password_reset_complete'|_ }}
|
|
||||||
</div>
|
|
||||||
<form
|
|
||||||
class="password_form"
|
|
||||||
action="/"
|
|
||||||
method="get">
|
|
||||||
|
|
||||||
<div class="btn_bg">
|
|
||||||
<button type="submit" class="pass_btn">OK</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
@ -1,12 +1,7 @@
|
||||||
<section class="register active">
|
<div id="partialUserResetForm">
|
||||||
<div class="auto_container">
|
{% if __SELF__.code == null %}
|
||||||
<div class="pass_wrap" id="partialUserResetForm">
|
{% partial __SELF__ ~ '::restore' %}
|
||||||
{% if __SELF__.code == null %}
|
{% else %}
|
||||||
{% partial __SELF__ ~ '::restore' %}
|
{% partial __SELF__ ~ '::reset' %}
|
||||||
{% else %}
|
{% endif %}
|
||||||
{% partial __SELF__ ~ '::reset' %}
|
</div>
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
|
|
@ -1,22 +1,19 @@
|
||||||
<div class="pass_change active">
|
<p class="lead">
|
||||||
<div class="pass_title">
|
Please check your email for the activation code.
|
||||||
{{ 'account.new_password'|_ }}
|
</p>
|
||||||
|
|
||||||
|
<form
|
||||||
|
data-request="{{ __SELF__ }}::onResetPassword"
|
||||||
|
data-request-update="'{{ __SELF__ }}::complete': '#partialUserResetForm'">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="resetCode">Activation Code</label>
|
||||||
|
<input name="code" type="text" class="form-control" id="resetCode" placeholder="Enter the activation code" value="{{ __SELF__.code }}">
|
||||||
</div>
|
</div>
|
||||||
<form
|
|
||||||
class="password_form"
|
|
||||||
data-request="{{ __SELF__ }}::onResetPassword"
|
|
||||||
data-request-update="'{{ __SELF__ }}::complete': '#partialUserResetForm'">
|
|
||||||
<div class="pass_input">
|
|
||||||
<input name="code" type="hidden" class="form-control" id="resetCode" placeholder="{{ 'auth.password_reset_code'|_ }}" value="{{ __SELF__.code }}" required>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="pass_input">
|
<div class="form-group">
|
||||||
<input name="password" type="password" class="form-control" id="resetPassword" placeholder="{{ 'account.new_password'|_ }}" required>
|
<label for="resetPassword">New Password</label>
|
||||||
</div>
|
<input name="password" type="password" class="form-control" id="resetPassword" placeholder="Enter a new password">
|
||||||
|
</div>
|
||||||
<div class="btn_bg">
|
|
||||||
<button type="submit" class="pass_btn" data-attach-loading>{{ 'auth.password_reset_btn'|_ }}</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-default">Reset password</button>
|
||||||
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
<div class="pass_mail">
|
<p class="lead">
|
||||||
<div class="pass_title">
|
<strong>Lost your password?</strong> No problem! Enter your email address to verify your account.
|
||||||
{{ 'auth.password_reset'|_ }}
|
</p>
|
||||||
</div>
|
|
||||||
<form
|
|
||||||
class="password_form"
|
|
||||||
data-request="{{ __SELF__ }}::onRestorePassword"
|
|
||||||
data-request-update="'{{ __SELF__ }}::check': '#partialUserResetForm'">
|
|
||||||
<div class="pass_input">
|
|
||||||
<input name="email" type="email" required class="form-control" id="userRestoreEmail" placeholder="{{'auth.email'|_}}">
|
|
||||||
</div>
|
|
||||||
<div class="btn_bg">
|
|
||||||
<button type="submit" class="pass_btn" data-attach-loading>{{ 'auth.password_restore_btn'|_ }}</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</form>
|
<form
|
||||||
</div>
|
data-request="{{ __SELF__ }}::onRestorePassword"
|
||||||
|
data-request-update="'{{ __SELF__ }}::reset': '#partialUserResetForm'">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="userRestoreEmail">Email</label>
|
||||||
|
<input name="email" type="email" class="form-control" id="userRestoreEmail" placeholder="Enter your email">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-default">Restore password</button>
|
||||||
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,25 @@
|
||||||
{
|
{
|
||||||
"name": "rainlab/user-plugin",
|
"name": "rainlab/user-plugin",
|
||||||
"type": "october-plugin",
|
"type": "october-plugin",
|
||||||
"description": "None",
|
"description": "User plugin for October CMS",
|
||||||
|
"homepage": "https://octobercms.com/plugin/rainlab-user",
|
||||||
|
"keywords": ["october", "octobercms", "user"],
|
||||||
|
"license": "MIT",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Alexey Bobkov",
|
||||||
|
"email": "aleksey.bobkov@gmail.com",
|
||||||
|
"role": "Co-founder"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Samuel Georges",
|
||||||
|
"email": "daftspunky@gmail.com",
|
||||||
|
"role": "Co-founder"
|
||||||
|
}
|
||||||
|
],
|
||||||
"require": {
|
"require": {
|
||||||
|
"php": ">=5.5.9",
|
||||||
"composer/installers": "~1.0"
|
"composer/installers": "~1.0"
|
||||||
}
|
},
|
||||||
|
"minimum-stability": "dev"
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +64,7 @@ return [
|
||||||
|
|
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
'minPasswordLength' => 6,
|
'minPasswordLength' => 8,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
|
|
|
||||||
|
|
@ -279,6 +279,7 @@ class Users extends Controller
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'deactivate':
|
case 'deactivate':
|
||||||
|
$user->clearPersistCode();
|
||||||
$user->delete();
|
$user->delete();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
<?= Form::open(['id' => 'convertGuestForm']) ?>
|
<?= Form::open(['id' => 'convertGuestForm']) ?>
|
||||||
<div class="modal-header">
|
<div class="modal-header flex-row-reverse">
|
||||||
<button type="button" class="close" data-dismiss="popup">×</button>
|
<button type="button" class="close" data-dismiss="popup">×</button>
|
||||||
<h4 class="modal-title">Convert guest user</h4>
|
<h4 class="modal-title">Convert Guest User</h4>
|
||||||
</div>
|
</div>
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
|
|
||||||
<?php if ($this->fatalError): ?>
|
<?php if ($this->fatalError): ?>
|
||||||
<p class="flash-message static error"><?= $fatalError ?></p>
|
<p class="flash-message static error"><?= $fatalError ?></p>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<div class="form-group dropdown-field span-full">
|
<div class="form-group dropdown-field span-full">
|
||||||
<label>Select a new user group</label>
|
<label class="form-label">Select a new user group</label>
|
||||||
<select class="form-control custom-select" name="new_group">
|
<select class="form-control custom-select" name="new_group">
|
||||||
<option selected="selected" value="">- No group -</option>
|
<option selected="selected" value="">- No group -</option>
|
||||||
<?php foreach ($groups as $group): ?>
|
<?php foreach ($groups as $group): ?>
|
||||||
|
|
@ -23,9 +22,9 @@
|
||||||
<div class="checkbox custom-checkbox">
|
<div class="checkbox custom-checkbox">
|
||||||
<input type="hidden" class="checkbox" value="" name="send_registration_notification">
|
<input type="hidden" class="checkbox" value="" name="send_registration_notification">
|
||||||
<input name="send_registration_notification" value="1" type="checkbox" id="sendNotification" checked="checked" />
|
<input name="send_registration_notification" value="1" type="checkbox" id="sendNotification" checked="checked" />
|
||||||
<label for="sendNotification">Send registration notification</label>
|
<label class="storm-icon-pseudo" for="sendNotification">Send registration notification</label>
|
||||||
<p class="help-block">Use this checkbox to generate new random password for the user and send a registration notification email.</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<p class="help-block form-text">Use this checkbox to generate new random password for the user and send a registration notification email.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -36,7 +35,7 @@
|
||||||
class="btn btn-primary"
|
class="btn btn-primary"
|
||||||
data-popup-load-indicator
|
data-popup-load-indicator
|
||||||
data-request="onConvertGuest">
|
data-request="onConvertGuest">
|
||||||
Convert to registered
|
Convert to Registered
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-default dropdown-toggle"
|
class="btn btn-default dropdown-toggle dropdown-toggle-split"
|
||||||
data-trigger-action="enable"
|
data-trigger-action="enable"
|
||||||
data-trigger=".control-list input[type=checkbox]"
|
data-trigger=".control-list input[type=checkbox]"
|
||||||
data-trigger-condition="checked"
|
data-trigger-condition="checked"
|
||||||
|
|
@ -28,12 +28,12 @@
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
</button>
|
</button>
|
||||||
<ul class="dropdown-menu" data-dropdown-title="<?= e(trans('rainlab.user::lang.users.bulk_actions')) ?>">
|
<ul class="dropdown-menu" data-dropdown-title="<?= e(trans('rainlab.user::lang.users.bulk_actions')) ?>">
|
||||||
<!-- <li>
|
<li>
|
||||||
<a href="javascript:;" class="oc-icon-trash-o" data-action="delete" data-confirm="<?= e(trans('rainlab.user::lang.users.delete_selected_confirm')) ?>">
|
<a href="javascript:;" class="oc-icon-trash-o" data-action="delete" data-confirm="<?= e(trans('rainlab.user::lang.users.delete_selected_confirm')) ?>">
|
||||||
<?= e(trans('rainlab.user::lang.users.delete_selected')) ?>
|
<?= e(trans('rainlab.user::lang.users.delete_selected')) ?>
|
||||||
</a>
|
</a>
|
||||||
</li> -->
|
</li>
|
||||||
<!-- <li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:;" class="oc-icon-user-plus" data-action="activate" data-confirm="<?= e(trans('rainlab.user::lang.users.activate_selected_confirm')) ?>">
|
<a href="javascript:;" class="oc-icon-user-plus" data-action="activate" data-confirm="<?= e(trans('rainlab.user::lang.users.activate_selected_confirm')) ?>">
|
||||||
<?= e(trans('rainlab.user::lang.users.activate_selected')) ?>
|
<?= e(trans('rainlab.user::lang.users.activate_selected')) ?>
|
||||||
|
|
@ -49,7 +49,7 @@
|
||||||
<a href="javascript:;" class="oc-icon-user-plus" data-action="restore" data-confirm="<?= e(trans('rainlab.user::lang.users.restore_selected_confirm')) ?>">
|
<a href="javascript:;" class="oc-icon-user-plus" data-action="restore" data-confirm="<?= e(trans('rainlab.user::lang.users.restore_selected_confirm')) ?>">
|
||||||
<?= e(trans('rainlab.user::lang.users.restore_selected')) ?>
|
<?= e(trans('rainlab.user::lang.users.restore_selected')) ?>
|
||||||
</a>
|
</a>
|
||||||
</li> -->
|
</li>
|
||||||
<li role="separator" class="divider"></li>
|
<li role="separator" class="divider"></li>
|
||||||
<li>
|
<li>
|
||||||
<a href="javascript:;" class="oc-icon-ban" data-action="ban" data-confirm="<?= e(trans('rainlab.user::lang.users.ban_selected_confirm')) ?>">
|
<a href="javascript:;" class="oc-icon-ban" data-action="ban" data-confirm="<?= e(trans('rainlab.user::lang.users.ban_selected_confirm')) ?>">
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,13 @@
|
||||||
<?= e(trans('rainlab.user::lang.users.update_details')) ?>
|
<?= e(trans('rainlab.user::lang.users.update_details')) ?>
|
||||||
</a>
|
</a>
|
||||||
<?php if ($this->user->hasAccess('rainlab.users.impersonate_user')): ?>
|
<?php if ($this->user->hasAccess('rainlab.users.impersonate_user')): ?>
|
||||||
<!-- <a
|
<a
|
||||||
href="javascript:;"
|
href="javascript:;"
|
||||||
data-request="onImpersonateUser"
|
data-request="onImpersonateUser"
|
||||||
data-request-confirm="<?= e(trans('rainlab.user::lang.users.impersonate_confirm')) ?>"
|
data-request-confirm="<?= e(trans('rainlab.user::lang.users.impersonate_confirm')) ?>"
|
||||||
class="btn btn-default oc-icon-user-secret">
|
class="btn btn-default oc-icon-user-secret">
|
||||||
<?= e(trans('rainlab.user::lang.users.impersonate_user')) ?>
|
<?= e(trans('rainlab.user::lang.users.impersonate_user')) ?>
|
||||||
</a> -->
|
</a>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<?php if ($formModel->isSuspended()): ?>
|
<?php if ($formModel->isSuspended()): ?>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
||||||
# ===================================
|
|
||||||
# Filter Scope Definitions
|
|
||||||
# ===================================
|
|
||||||
|
|
||||||
scopes:
|
|
||||||
|
|
||||||
# groups:
|
|
||||||
# # Filter name
|
|
||||||
# label: rainlab.user::lang.group.label
|
|
||||||
# # Model Class name
|
|
||||||
# modelClass: RainLab\User\Models\UserGroup
|
|
||||||
# # Model attribute to display for the name
|
|
||||||
# nameFrom: name
|
|
||||||
# # Filter scope
|
|
||||||
# scope: filterByGroup
|
|
||||||
|
|
||||||
created_date:
|
|
||||||
label: rainlab.user::lang.user.created_at
|
|
||||||
type: daterange
|
|
||||||
conditions: created_at >= ':after' AND created_at <= ':before'
|
|
||||||
|
|
||||||
# activated:
|
|
||||||
# # Filter name
|
|
||||||
# label: rainlab.user::lang.user.status_activated
|
|
||||||
# # Filter type
|
|
||||||
# type: switch
|
|
||||||
# # SQL conditions
|
|
||||||
# conditions:
|
|
||||||
# - is_activated = '0'
|
|
||||||
# - is_activated = '1'
|
|
||||||
|
|
@ -8,6 +8,9 @@ title: rainlab.user::lang.users.list_title
|
||||||
# Model List Column configuration
|
# Model List Column configuration
|
||||||
list: $/rainlab/user/models/user/columns.yaml
|
list: $/rainlab/user/models/user/columns.yaml
|
||||||
|
|
||||||
|
# Filter widget configuration
|
||||||
|
filter: $/rainlab/user/models/user/scopes.yaml
|
||||||
|
|
||||||
# Model Class name
|
# Model Class name
|
||||||
modelClass: RainLab\User\Models\User
|
modelClass: RainLab\User\Models\User
|
||||||
|
|
||||||
|
|
@ -26,9 +29,6 @@ showCheckboxes: true
|
||||||
# Displays the list column set up button
|
# Displays the list column set up button
|
||||||
showSetup: true
|
showSetup: true
|
||||||
|
|
||||||
# Filter widget configuration
|
|
||||||
filter: config_filter.yaml
|
|
||||||
|
|
||||||
# Toolbar widget configuration
|
# Toolbar widget configuration
|
||||||
toolbar:
|
toolbar:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'plugin' => [
|
||||||
|
'name' => 'المستخدم',
|
||||||
|
'description' => 'إدارة المستخدم الأمامية.',
|
||||||
|
'tab' => 'المستخدمون',
|
||||||
|
'access_users' => 'ادارة المستخدمين',
|
||||||
|
'access_groups' => 'إدارة مجموعات المستخدمين',
|
||||||
|
'access_settings' => 'إدارة إعدادات المستخدم',
|
||||||
|
'impersonate_user' => 'انتحال شخصية المستخدمين'
|
||||||
|
],
|
||||||
|
'users' => [
|
||||||
|
'menu_label' => 'المستخدمون',
|
||||||
|
'all_users' => 'جميع المستخدمين',
|
||||||
|
'new_user' => 'مستخدم جديد',
|
||||||
|
'list_title' => 'ادارة المستخدمين',
|
||||||
|
'trashed_hint_title' => 'قام المستخدم بإلغاء تنشيط حسابه',
|
||||||
|
'trashed_hint_desc' => 'قام هذا المستخدم بإلغاء تنشيط حسابه ولم يعد يريد الظهور على الموقع. يمكنهم استعادة حسابهم في أي وقت عن طريق تسجيل الدخول مرة أخرى.',
|
||||||
|
'banned_hint_title' => 'تم حظر المستخدم',
|
||||||
|
'banned_hint_desc' => 'تم حظر هذا المستخدم من قبل المسؤول ولن يتمكن من تسجيل الدخول.',
|
||||||
|
'guest_hint_title' => 'هذا مستخدم ضيف',
|
||||||
|
'guest_hint_desc' => 'يتم تخزين هذا المستخدم لأغراض مرجعية فقط ويحتاج إلى التسجيل قبل تسجيل الدخول.',
|
||||||
|
'activate_warning_title' => 'المستخدم غير مفعل!',
|
||||||
|
'activate_warning_desc' => 'لم يتم تنشيط هذا المستخدم وقد يتعذر عليه تسجيل الدخول.',
|
||||||
|
'activate_confirm' => 'هل تريد فعلاً تفعيل هذا المستخدم؟',
|
||||||
|
'activated_success' => 'تم تنشيط المستخدم',
|
||||||
|
'activate_manually' => 'قم بتنشيط هذا المستخدم يدويًا',
|
||||||
|
'convert_guest_confirm' => 'تحويل هذا الضيف إلى مستخدم؟',
|
||||||
|
'convert_guest_manually' => 'التحويل إلى مستخدم مسجل',
|
||||||
|
'convert_guest_success' => 'تم تحويل المستخدم إلى حساب مسجل',
|
||||||
|
'impersonate_user' => 'انتحال شخصية المستخدم',
|
||||||
|
'impersonate_confirm' => 'انتحال شخصية هذا المستخدم؟ يمكنك العودة إلى حالتك الأصلية بتسجيل الخروج.',
|
||||||
|
'impersonate_success' => 'أنت الآن تنتحل شخصية هذا المستخدم',
|
||||||
|
'delete_confirm' => 'هل تريد حقًا حذف هذا المستخدم؟',
|
||||||
|
'unban_user' => 'إلغاء حظر هذا المستخدم',
|
||||||
|
'unban_confirm' => 'هل تريد حقًا إلغاء حظر هذا المستخدم؟',
|
||||||
|
'unbanned_success' => 'تم إلغاء حظر المستخدم',
|
||||||
|
'return_to_list' => 'العودة إلى قائمة المستخدمين',
|
||||||
|
'update_details' => 'تحديث التفاصيل',
|
||||||
|
'bulk_actions' => 'إجراءات ',
|
||||||
|
'delete_selected' => 'احذف المختار',
|
||||||
|
'delete_selected_confirm' => 'حذف المستخدمين المختارين؟',
|
||||||
|
'delete_selected_empty' => 'لا يوجد مستخدمون محددون لحذفهم.',
|
||||||
|
'delete_selected_success' => 'تم حذف المستخدمين المحددين بنجاح.',
|
||||||
|
'activate_selected' => 'تفعيل المحدد',
|
||||||
|
'activate_selected_confirm' => 'تفعيل المستخدمين المختارين؟',
|
||||||
|
'activate_selected_empty' => 'لا يوجد مستخدمون محددون لتنشيطهم.',
|
||||||
|
'activate_selected_success' => 'تم تفعيل المستخدمين المختارين بنجاح.',
|
||||||
|
'deactivate_selected' => 'تم تحديد إلغاء التنشيط',
|
||||||
|
'deactivate_selected_confirm' => 'تعطيل المستخدمين المختارين؟',
|
||||||
|
'deactivate_selected_empty' => 'لا يوجد مستخدمون محددون لإلغاء تنشيطهم.',
|
||||||
|
'deactivate_selected_success' => 'تم إلغاء تنشيط المستخدمين المحددين بنجاح.',
|
||||||
|
'restore_selected' => 'استعادة المختارة',
|
||||||
|
'restore_selected_confirm' => 'استعادة المستخدمين المختارين؟',
|
||||||
|
'restore_selected_empty' => 'لا يوجد مستخدمون محددون لاستعادتهم.',
|
||||||
|
'restore_selected_success' => 'تمت استعادة المستخدمين المحددين بنجاح.',
|
||||||
|
'ban_selected' => 'تم تحديد الحظر',
|
||||||
|
'ban_selected_confirm' => 'حظر المستخدمين المختارين؟',
|
||||||
|
'ban_selected_empty' => 'لا يوجد مستخدمون محددون لحظرهم.',
|
||||||
|
'ban_selected_success' => 'تم بنجاح حظر المستخدمين المحددين.',
|
||||||
|
'unban_selected' => 'تم تحديد إلغاء الحظر',
|
||||||
|
'unban_selected_confirm' => 'إلغاء حظر المستخدمين المحددين؟',
|
||||||
|
'unban_selected_empty' => 'لا يوجد مستخدمون محددون لإلغاء الحظر.',
|
||||||
|
'unban_selected_success' => 'تم بنجاح فك الحظر عن المستخدمين المحددين.',
|
||||||
|
'unsuspend' => 'غير معلق',
|
||||||
|
'unsuspend_success' => 'تم إلغاء تعليق المستخدم.',
|
||||||
|
'unsuspend_confirm' => 'إلغاء تعليق هذا المستخدم؟'
|
||||||
|
],
|
||||||
|
'settings' => [
|
||||||
|
'users' => 'المستخدمون',
|
||||||
|
'menu_label' => 'إعدادات المستخدم',
|
||||||
|
'menu_description' => 'إدارة مصادقة المستخدم والتسجيل وإعدادات التنشيط.',
|
||||||
|
'activation_tab' => 'التنشيط',
|
||||||
|
'signin_tab' => 'تسجيل الدخول',
|
||||||
|
'registration_tab' => 'تسجيل',
|
||||||
|
'profile_tab' => 'الملف الشخصي',
|
||||||
|
'notifications_tab' => 'إشعارات',
|
||||||
|
'allow_registration' => 'السماح بتسجيل المستخدم',
|
||||||
|
'allow_registration_comment' => 'إذا تم تعطيل هذا ، فلا يمكن إنشاء المستخدمين إلا بواسطة المسؤولين.',
|
||||||
|
'activate_mode' => 'وضع التنشيط',
|
||||||
|
'activate_mode_comment' => 'حدد كيفية تنشيط حساب المستخدم.',
|
||||||
|
'activate_mode_auto' => 'تلقائي',
|
||||||
|
'activate_mode_auto_comment' => 'يتم تفعيله تلقائيًا عند التسجيل.',
|
||||||
|
'activate_mode_user' => 'اسم االمستخدم',
|
||||||
|
'activate_mode_user_comment' => 'يقوم المستخدم بتنشيط حسابه الخاص باستخدام البريد.',
|
||||||
|
'activate_mode_admin' => 'مدير',
|
||||||
|
'activate_mode_admin_comment' => 'يمكن للمسؤول فقط تنشيط المستخدم.',
|
||||||
|
'require_activation' => 'يتطلب تسجيل الدخول التنشيط',
|
||||||
|
'require_activation_comment' => 'يجب أن يكون لدى المستخدمين حساب نشط لتسجيل الدخول.',
|
||||||
|
'use_throttle' => 'محاولات خنق',
|
||||||
|
'use_throttle_comment' => 'ستؤدي محاولات تسجيل الدخول الفاشلة المتكررة إلى تعليق المستخدم مؤقتًا.',
|
||||||
|
'use_register_throttle' => 'تسجيل الخانق',
|
||||||
|
'use_register_throttle_comment' => 'منع التسجيلات المتعددة من نفس عنوان IP في تتابع قصير.',
|
||||||
|
'block_persistence' => 'منع الجلسات المتزامنة',
|
||||||
|
'block_persistence_comment' => 'عند التمكين ، لا يمكن للمستخدمين تسجيل الدخول إلى أجهزة متعددة في نفس الوقت.',
|
||||||
|
'login_attribute' => 'سمة تسجيل الدخول',
|
||||||
|
'login_attribute_comment' => 'حدد تفاصيل المستخدم الأساسية التي يجب استخدامها لتسجيل الدخول.',
|
||||||
|
'remember_login' => 'تذكر وضع تسجيل الدخول',
|
||||||
|
'remember_login_comment' => 'حدد ما إذا كانت جلسة المستخدم يجب أن تكون مستمرة.',
|
||||||
|
'remember_always' => 'دائماً',
|
||||||
|
'remember_never' => 'أبداً',
|
||||||
|
'remember_ask' => 'اسأل المستخدم عند تسجيل الدخول',
|
||||||
|
],
|
||||||
|
'user' => [
|
||||||
|
'label' => 'المستخدم',
|
||||||
|
'id' => 'ID',
|
||||||
|
'username' => 'اسم المستخدم',
|
||||||
|
'name' => 'اسم',
|
||||||
|
'name_empty' => 'مجهول',
|
||||||
|
'surname' => 'اسم العائلة',
|
||||||
|
'email' => 'البريد الإلكتروني',
|
||||||
|
'created_at' => 'مسجل',
|
||||||
|
'last_seen' => 'اخر ظهور',
|
||||||
|
'is_guest' => 'زائر',
|
||||||
|
'joined' => 'انضم',
|
||||||
|
'is_online' => 'متواجد حاليا',
|
||||||
|
'is_offline' => 'حاليا غير متصل',
|
||||||
|
'send_invite' => 'إرسال دعوة عبر البريد الإلكتروني',
|
||||||
|
'send_invite_comment' => 'يرسل رسالة ترحيب تحتوي على معلومات تسجيل الدخول وكلمة المرور.',
|
||||||
|
'create_password' => 'أنشئ كلمة مرور',
|
||||||
|
'create_password_comment' => 'أدخل كلمة مرور جديدة مستخدمة لتسجيل الدخول.',
|
||||||
|
'reset_password' => 'إعادة تعيين كلمة المرور',
|
||||||
|
'reset_password_comment' => 'لإعادة تعيين كلمة مرور هذا المستخدم ، أدخل كلمة مرور جديدة هنا.',
|
||||||
|
'confirm_password' => 'تأكيد كلمة المرور',
|
||||||
|
'confirm_password_comment' => 'أدخل كلمة المرور مرة أخرى لتأكيدها.',
|
||||||
|
'groups' => 'مجموعات',
|
||||||
|
'empty_groups' => 'لا توجد مجموعات مستخدمين متاحة.',
|
||||||
|
'avatar' => 'الصورة الرمزية',
|
||||||
|
'details' => 'تفاصيل',
|
||||||
|
'account' => 'الحساب',
|
||||||
|
'block_mail' => 'حظر كل البريد الصادر المرسل إلى هذا المستخدم.',
|
||||||
|
'status_label' => 'حالة',
|
||||||
|
'status_guest' => 'زائر',
|
||||||
|
'status_activated' => 'مفعل',
|
||||||
|
'status_registered' => 'مسجل',
|
||||||
|
'created_ip_address' => 'عنوان IP الذي تم إنشاؤه',
|
||||||
|
'last_ip_address' => 'عنوان IP الأخير',
|
||||||
|
],
|
||||||
|
'group' => [
|
||||||
|
'label' => 'مجموعة',
|
||||||
|
'id' => 'ID',
|
||||||
|
'name' => 'الاسم',
|
||||||
|
'description_field' => 'الوصف',
|
||||||
|
'code' => 'رمز',
|
||||||
|
'code_comment' => 'أدخل رمزًا فريدًا يستخدم لتعريف هذه المجموعة.',
|
||||||
|
'created_at' => 'أنشئت',
|
||||||
|
'users_count' => 'المستخدمون'
|
||||||
|
],
|
||||||
|
'groups' => [
|
||||||
|
'menu_label' => 'مجموعات',
|
||||||
|
'all_groups' => 'مجموعات الاعضاء',
|
||||||
|
'new_group' => 'مجموعة جديدة',
|
||||||
|
'delete_selected_confirm' => 'هل تريد حقًا حذف المجموعات المختارة؟',
|
||||||
|
'list_title' => 'إدارة المجموعات',
|
||||||
|
'delete_confirm' => 'هل تريد حقًا حذف هذه المجموعة؟',
|
||||||
|
'delete_selected_success' => 'تم حذف المجموعات المحددة بنجاح.',
|
||||||
|
'delete_selected_empty' => 'لا توجد مجموعات محددة لحذفها.',
|
||||||
|
'return_to_list' => 'رجوع إلى قائمة المجموعات',
|
||||||
|
'return_to_users' => 'رجوع إلى قائمة المستخدمين',
|
||||||
|
'create_title' => 'إنشاء مجموعة مستخدمين',
|
||||||
|
'update_title' => 'تحرير مجموعة المستخدمين',
|
||||||
|
'preview_title' => 'معاينة مجموعة المستخدمين'
|
||||||
|
],
|
||||||
|
'login' => [
|
||||||
|
'attribute_email' => 'البريد الإلكتروني',
|
||||||
|
'attribute_username' => 'اسم المستخدم'
|
||||||
|
],
|
||||||
|
'account' => [
|
||||||
|
'account' => 'الحساب',
|
||||||
|
'account_desc' => 'نموذج إدارة المستخدم.',
|
||||||
|
'banned' => 'عذرا ، هذا المستخدم غير مفعل حاليا. يرجى الاتصال بنا للحصول على مزيد من المساعدة.',
|
||||||
|
'redirect_to' => 'إعادة توجيه ل',
|
||||||
|
'redirect_to_desc' => 'اسم الصفحة المراد إعادة التوجيه إليه بعد التحديث أو تسجيل الدخول أو التسجيل.',
|
||||||
|
'code_param' => 'تفعيل كود بارام',
|
||||||
|
'code_param_desc' => 'معلمة URL للصفحة المستخدمة في رمز تنشيط التسجيل',
|
||||||
|
'force_secure' => 'فرض بروتوكول آمن',
|
||||||
|
'force_secure_desc' => 'قم دائمًا بإعادة توجيه عنوان URL باستخدام مخطط HTTPS.',
|
||||||
|
'invalid_user' => 'لم يتم العثور على مستخدم ببيانات الاعتماد المقدمة.',
|
||||||
|
'invalid_activation_code' => 'تم توفير رمز التفعيل غير صالح.',
|
||||||
|
'invalid_deactivation_pass' => 'كلمة المرور التي أدخلتها غير صالحة.',
|
||||||
|
'invalid_current_pass' => 'كلمة المرور الحالية التي أدخلتها غير صالحة.',
|
||||||
|
'success_activation' => 'تم تفعيل حسابك بنجاح.',
|
||||||
|
'success_deactivation' => 'تم إلغاء تنشيط حسابك بنجاح. اسف لرؤيتك تذهب!',
|
||||||
|
'success_saved' => 'تم حفظ الإعدادات بنجاح!',
|
||||||
|
'login_first' => 'يجب عليك تسجيل الدخول أولا!',
|
||||||
|
'already_active' => 'تم تنشيط حسابك بالفعل!',
|
||||||
|
'activation_email_sent' => 'تم ارسال رسالة التحقق الى بريدك الالكتروني.',
|
||||||
|
'activation_by_admin' => 'لقد قمت بالتسجيل بنجاح. حسابك ليس نشطًا بعد ويجب أن يوافق عليه المسؤول.',
|
||||||
|
'registration_disabled' => 'التسجيلات معطلة حاليا.',
|
||||||
|
'registration_throttled' => 'التسجيل مخنق. الرجاء معاودة المحاولة في وقت لاحق.',
|
||||||
|
'sign_in' => 'تسجيل الدخول',
|
||||||
|
'register' => 'تسجيل',
|
||||||
|
'full_name' => 'الاسم الكامل',
|
||||||
|
'email' => 'البريد الإلكتروني',
|
||||||
|
'password' => 'كلمة المرور',
|
||||||
|
'login' => 'تسجيل الدخول',
|
||||||
|
'new_password' => 'كلمة السر الجديدة',
|
||||||
|
'new_password_confirm' => 'تأكيد كلمة المرور الجديدة',
|
||||||
|
'update_requires_password' => 'تأكيد كلمة المرور عند التحديث',
|
||||||
|
'update_requires_password_comment' => 'طلب كلمة المرور الحالية للمستخدم عند تغيير ملف التعريف الخاص به.',
|
||||||
|
'activation_page' => 'صفحة التفعيل',
|
||||||
|
'activation_page_comment' => 'حدد صفحة لاستخدامها في تنشيط حساب المستخدم',
|
||||||
|
'reset_page' => 'إعادة ضبط الصفحة',
|
||||||
|
'reset_page_comment' => 'حدد صفحة لاستخدامها في إعادة تعيين كلمة مرور الحساب',
|
||||||
|
],
|
||||||
|
'reset_password' => [
|
||||||
|
'reset_password' => 'إعادة تعيين كلمة المرور',
|
||||||
|
'reset_password_desc' => 'استمارة كلمة السر المنسية.',
|
||||||
|
'code_param' => 'إعادة تعيين الرمز',
|
||||||
|
'code_param_desc' => 'معلمة URL للصفحة المستخدمة في إعادة تعيين رمز'
|
||||||
|
],
|
||||||
|
'session' => [
|
||||||
|
'session' => 'جلسة',
|
||||||
|
'session_desc' => 'يضيف جلسة المستخدم إلى الصفحة ويمكنه تقييد الوصول إلى الصفحة.',
|
||||||
|
'security_title' => 'السماح فقط',
|
||||||
|
'security_desc' => 'من المسموح له الوصول إلى هذه الصفحة.',
|
||||||
|
'all' => 'الجميع',
|
||||||
|
'users' => 'المستخدمون',
|
||||||
|
'guests' => 'ضيوف',
|
||||||
|
'allowed_groups_title' => 'السماح للمجموعات',
|
||||||
|
'allowed_groups_description' => 'اختر المجموعات المسموح بها أو لا تختارها للسماح لجميع المجموعات',
|
||||||
|
'redirect_title' => 'إعادة توجيه ل',
|
||||||
|
'redirect_desc' => 'اسم الصفحة لإعادة التوجيه إذا تم رفض الوصول.',
|
||||||
|
'logout' => 'لقد تم تسجيل الخروج بنجاح!',
|
||||||
|
'stop_impersonate_success' => 'لم تعد تنتحل شخصية مستخدم.',
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
@ -70,7 +70,7 @@ return [
|
||||||
'settings' => [
|
'settings' => [
|
||||||
'users' => 'Users',
|
'users' => 'Users',
|
||||||
'menu_label' => 'User settings',
|
'menu_label' => 'User settings',
|
||||||
'menu_description' => 'Manage user based settings.',
|
'menu_description' => 'Manage user authentication, registration and activation settings.',
|
||||||
'activation_tab' => 'Activation',
|
'activation_tab' => 'Activation',
|
||||||
'signin_tab' => 'Sign in',
|
'signin_tab' => 'Sign in',
|
||||||
'registration_tab' => 'Registration',
|
'registration_tab' => 'Registration',
|
||||||
|
|
@ -199,13 +199,10 @@ return [
|
||||||
'new_password_confirm' => 'Confirm New Password',
|
'new_password_confirm' => 'Confirm New Password',
|
||||||
'update_requires_password' => 'Confirm password on update',
|
'update_requires_password' => 'Confirm password on update',
|
||||||
'update_requires_password_comment' => 'Require the current password of the user when changing their profile.',
|
'update_requires_password_comment' => 'Require the current password of the user when changing their profile.',
|
||||||
'email_verification' => 'Email verification',
|
'activation_page' => 'Activation Page',
|
||||||
'email_verification_check_message' => 'Please check your email',
|
'activation_page_comment' => 'Select a page to use for activating the user account',
|
||||||
'email_verified_message' => 'Your email address has been succesfully verified',
|
'reset_page' => 'Reset Page',
|
||||||
'email_verification_link_invalid' => 'Invalid verification link',
|
'reset_page_comment' => 'Select a page to use for resetting the account password',
|
||||||
'email_already_verified' => 'You have already verified your email address',
|
|
||||||
'phone_verified_message' => 'Your phone number has been succesfully verified',
|
|
||||||
'phone_verification_code_invalid' => 'Invalid sms code',
|
|
||||||
],
|
],
|
||||||
'reset_password' => [
|
'reset_password' => [
|
||||||
'reset_password' => 'Reset Password',
|
'reset_password' => 'Reset Password',
|
||||||
|
|
|
||||||
|
|
@ -199,13 +199,10 @@ return [
|
||||||
'new_password_confirm' => 'Подтверждение пароля',
|
'new_password_confirm' => 'Подтверждение пароля',
|
||||||
'update_requires_password' => 'Подтверждать пароль при обновлении',
|
'update_requires_password' => 'Подтверждать пароль при обновлении',
|
||||||
'update_requires_password_comment' => 'Запрашивать текущий пароль пользователя при редактировании его профиля.',
|
'update_requires_password_comment' => 'Запрашивать текущий пароль пользователя при редактировании его профиля.',
|
||||||
'email_verification' => 'Подтверждение Email',
|
'activation_page' => 'Страница активации',
|
||||||
'email_verification_check_message' => 'Пожалуйста, проверьте Еmail',
|
'activation_page_comment' => 'Выберите страницу для активации аккаунта пользователя.',
|
||||||
'email_verified_message' => 'Ваш Email успешно подтвержден',
|
'reset_page' => 'Страница сброса пароля',
|
||||||
'email_verification_link_invalid' => 'Неверный код подтверждения',
|
'reset_page_comment' => 'Выберите страницу для сброса проля аккаунта.',
|
||||||
'email_already_verified' => 'Вы уже подтвердили свой Email',
|
|
||||||
'phone_verified_message' => 'Ваш номер телефона подтвержден',
|
|
||||||
'phone_verification_code_invalid' => 'Неверный СМС код',
|
|
||||||
],
|
],
|
||||||
'reset_password' => [
|
'reset_password' => [
|
||||||
'reset_password' => 'Сброс пароля',
|
'reset_password' => 'Сброс пароля',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,228 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
return [
|
||||||
|
'plugin' => [
|
||||||
|
'name' => 'පරිශීලක',
|
||||||
|
'description' => 'ඉදිරිපස පරිශීලක කළමනාකරණය.',
|
||||||
|
'tab' => 'පරිශීලකයන්',
|
||||||
|
'access_users' => 'පරිශීලකයන් කළමනාකරණය කරන්න',
|
||||||
|
'access_groups' => 'පරිශීලක කණ්ඩායම් කළමනාකරණය කරන්න',
|
||||||
|
'access_settings' => 'පරිශීලක සැකසුම් කළමනාකරණය කරන්න',
|
||||||
|
'impersonate_user' => 'පරිශීලකයන් ලෙස පෙනී සිටින්න'
|
||||||
|
],
|
||||||
|
'users' => [
|
||||||
|
'menu_label' => 'පරිශීලකයන්',
|
||||||
|
'all_users' => 'සියලුම පරිශීලකයින්',
|
||||||
|
'new_user' => 'නව පරිශීලක',
|
||||||
|
'list_title' => 'පරිශීලකයන් කළමනාකරණය කරන්න',
|
||||||
|
'trashed_hint_title' => 'පරිශීලකයා ඔවුන්ගේ ගිණුම අක්රිය කර ඇත',
|
||||||
|
'trashed_hint_desc' => 'මෙම පරිශීලකයා ඔවුන්ගේ ගිණුම අක්රිය කර ඇති අතර තවදුරටත් අඩවියේ පෙනී සිටීමට අවශ්ය නැත. ඔවුන්ට නැවත පුරනය වීමෙන් ඕනෑම වේලාවක ඔවුන්ගේ ගිණුම ප්රතිසාධනය කළ හැක.',
|
||||||
|
'banned_hint_title' => 'පරිශීලකයා තහනම් කර ඇත',
|
||||||
|
'banned_hint_desc' => 'මෙම පරිශීලකයා පරිපාලකයෙකු විසින් තහනම් කර ඇති අතර ඔහුට පුරනය වීමට නොහැකි වනු ඇත.',
|
||||||
|
'guest_hint_title' => 'මෙය ආගන්තුක පරිශීලකයෙකි',
|
||||||
|
'guest_hint_desc' => 'මෙම පරිශීලකයා ගබඩා කර ඇත්තේ යොමු අරමුණු සඳහා පමණක් වන අතර පුරනය වීමට පෙර ලියාපදිංචි වීමට අවශ්ය වේ.',
|
||||||
|
'activate_warning_title' => 'පරිශීලකයා සක්රිය කර නැත!',
|
||||||
|
'activate_warning_desc' => 'මෙම පරිශීලකයා සක්රිය කර නොමැති අතර පුරනය වීමට නොහැකි විය හැක.',
|
||||||
|
'activate_confirm' => 'ඔබට ඇත්තටම මෙම පරිශීලකයා සක්රිය කිරීමට අවශ්යද?',
|
||||||
|
'activated_success' => 'පරිශීලකයා සක්රිය කර ඇත',
|
||||||
|
'activate_manually' => 'මෙම පරිශීලකයා අතින් සක්රිය කරන්න',
|
||||||
|
'convert_guest_confirm' => 'මෙම අමුත්තා පරිශීලකයෙකු බවට පරිවර්තනය කරන්නද?',
|
||||||
|
'convert_guest_manually' => 'ලියාපදිංචි පරිශීලකයා බවට පරිවර්තනය කරන්න',
|
||||||
|
'convert_guest_success' => 'පරිශීලක ලියාපදිංචි ගිණුමක් බවට පරිවර්තනය කර ඇත',
|
||||||
|
'impersonate_user' => 'පරිශීලක ලෙස පෙනී සිටින්න',
|
||||||
|
'impersonate_confirm' => 'මෙම පරිශීලකයා ලෙස පෙනී සිටින්නද? ලොග් අවුට් වීමෙන් ඔබට ඔබේ මුල් තත්වයට ආපසු යා හැක.',
|
||||||
|
'impersonate_success' => 'ඔබ දැන් මෙම පරිශීලකයා ලෙස පෙනී සිටියි',
|
||||||
|
'delete_confirm' => 'ඔබට ඇත්තටම මෙම පරිශීලකයා මකා දැමීමට අවශ්යද?',
|
||||||
|
'unban_user' => 'මෙම පරිශීලක තහනම ඉවත් කරන්න',
|
||||||
|
'unban_confirm' => 'ඔබට ඇත්තටම මෙම පරිශීලකයාගේ තහනම ඉවත් කිරීමට අවශ්යද?',
|
||||||
|
'unbanned_success' => 'පරිශීලක තහනම ඉවත් කර ඇත',
|
||||||
|
'return_to_list' => 'පරිශීලක ලැයිස්තුව වෙත ආපසු යන්න',
|
||||||
|
'update_details' => 'යාවත්කාලීන විස්තර',
|
||||||
|
'bulk_actions' => 'තොග ක්රියාවන්',
|
||||||
|
'delete_selected' => 'තෝරාගත් මකන්න',
|
||||||
|
'delete_selected_confirm' => 'තෝරාගත් පරිශීලකයින් මකන්නද?',
|
||||||
|
'delete_selected_empty' => 'මකා දැමීමට තෝරාගත් පරිශීලකයන් නැත.',
|
||||||
|
'delete_selected_success' => 'තෝරාගත් පරිශීලකයින් සාර්ථකව මකා දමන ලදී.',
|
||||||
|
'activate_selected' => 'තෝරාගත් සක්රිය කරන්න',
|
||||||
|
'activate_selected_confirm' => 'තෝරාගත් පරිශීලකයන් සක්රිය කරන්නද?',
|
||||||
|
'activate_selected_empty' => 'සක්රිය කිරීමට තෝරාගත් පරිශීලකයන් නොමැත.',
|
||||||
|
'activate_selected_success' => ' තෝරාගත් පරිශීලකයින් සාර්ථකව සක්රිය කර ඇත.',
|
||||||
|
'deactivate_selected' => 'තෝරාගත් අක්රිය කරන්න',
|
||||||
|
'deactivate_selected_confirm' => 'තෝරාගත් පරිශීලකයන් අක්රිය කරන්නද?',
|
||||||
|
'deactivate_selected_empty' => 'අක්රිය කිරීමට තෝරාගත් පරිශීලකයන් නැත.',
|
||||||
|
'deactivate_selected_success' => 'තෝරාගත් පරිශීලකයින් සාර්ථකව අක්රිය කර ඇත.',
|
||||||
|
'restore_selected' => 'තෝරාගත් ප්රතිසාධනය කරන්න',
|
||||||
|
'restore_selected_confirm' => 'තෝරාගත් පරිශීලකයන් ප්රතිසාධනය කරන්නද?',
|
||||||
|
'restore_selected_empty' => 'ප්රතිසාධනය කිරීමට තෝරාගත් පරිශීලකයන් නැත.',
|
||||||
|
'restore_selected_success' => 'තෝරාගත් පරිශීලකයින් සාර්ථකව ප්රතිසාධනය කරන ලදී.',
|
||||||
|
'ban_selected' => 'තහනම් තෝරන ලදී',
|
||||||
|
'ban_selected_confirm' => 'තෝරාගත් පරිශීලකයින් තහනම් කරන්නද?',
|
||||||
|
'ban_selected_empty' => 'තහනම් කිරීමට තෝරාගත් පරිශීලකයන් නොමැත.',
|
||||||
|
'ban_selected_success' => 'තෝරාගත් පරිශීලකයින් සාර්ථකව තහනම් කරන ලදී.',
|
||||||
|
'unban_selected' => 'තහනම් ඉවත් කිරීම තෝරා ඇත',
|
||||||
|
'unban_selected_confirm' => 'තෝරාගත් පරිශීලකයින් තහනම් නොකරන්නද?',
|
||||||
|
'unban_selected_empty' => 'තහනම් කිරීම ඉවත් කිරීමට තෝරාගත් පරිශීලකයන් නොමැත.',
|
||||||
|
'unban_selected_success' => 'තෝරාගත් පරිශීලකයින් සාර්ථකව තහනම් කිරීම ඉවත් කරන ලදී.',
|
||||||
|
'unsuspend' => 'අත්හිටුවීම ඉවත් කරන්න',
|
||||||
|
'unsuspend_success' => 'පරිශීලකයාගේ අත්හිටුවීම ඉවත් කර ඇත.',
|
||||||
|
'unsuspend_confirm' => 'මෙම පරිශීලකයාගේ අත්හිටුවීම ඉවත් කරන්නද?'
|
||||||
|
],
|
||||||
|
'settings' => [
|
||||||
|
'users' => 'පරිශීලකයන්',
|
||||||
|
'menu_label' => 'පරිශීලක සැකසුම්',
|
||||||
|
'menu_description' => 'පරිශීලක සත්යාපනය, ලියාපදිංචිය සහ සක්රිය කිරීමේ සැකසුම් කළමනාකරණය කරන්න.',
|
||||||
|
'activation_tab' => 'සක්රිය කිරීම',
|
||||||
|
'signin_tab' => 'පුරන්න',
|
||||||
|
'registration_tab' => 'ලියාපදිංචි කිරීම',
|
||||||
|
'profile_tab' => 'පැතිකඩ',
|
||||||
|
'notifications_tab' => 'දැනුම්දීම්',
|
||||||
|
'allow_registration' => 'පරිශීලක ලියාපදිංචියට ඉඩ දෙන්න',
|
||||||
|
'allow_registration_comment' => 'මෙය ආබාධිත නම්, පරිශීලකයින් නිර්මාණය කළ හැක්කේ පරිපාලකයින්ට පමණි.',
|
||||||
|
'activate_mode' => 'සක්රිය කිරීමේ මාදිලිය',
|
||||||
|
'activate_mode_comment' => 'පරිශීලක ගිණුමක් සක්රිය කළ යුතු ආකාරය තෝරන්න.',
|
||||||
|
'activate_mode_auto' => 'ස්වයංක්රීය',
|
||||||
|
'activate_mode_auto_comment' => 'ලියාපදිංචි වීමෙන් පසු ස්වයංක්රීයව සක්රිය කර ඇත.',
|
||||||
|
'activate_mode_user' => 'පරිශීලක',
|
||||||
|
'activate_mode_user_comment' => 'පරිශීලකයා තැපෑල භාවිතයෙන් තමන්ගේම ගිණුම සක්රිය කරයි.',
|
||||||
|
'activate_mode_admin' => 'පරිපාලක',
|
||||||
|
'activate_mode_admin_comment' => 'පරිශීලකයෙකු සක්රිය කළ හැක්කේ පරිපාලකයෙකුට පමණි.',
|
||||||
|
'require_activation' => 'පුරනය වීමට සක්රිය කිරීම අවශ්ය වේ',
|
||||||
|
'require_activation_comment' => 'පුරනය වීමට පරිශීලකයින්ට සක්රිය කළ ගිණුමක් තිබිය යුතුය.',
|
||||||
|
'use_throttle' => 'Throttle උත්සාහයන්',
|
||||||
|
'use_throttle_comment' => 'නැවත නැවත අසාර්ථක පුරනය වීමේ උත්සාහයන් පරිශීලකයා තාවකාලිකව අත්හිටුවනු ඇත.',
|
||||||
|
'use_register_throttle' => 'Throttle ලියාපදිංචිය',
|
||||||
|
'use_register_throttle_comment' => 'කෙටි කාලීනව එකම IP වෙතින් බහු ලියාපදිංචි කිරීම් වලක්වන්න.',
|
||||||
|
'block_persistence' => 'සමගාමී සැසි වැළැක්වීම',
|
||||||
|
'block_persistence_comment' => 'සබල කළ විට පරිශීලකයින්ට එකවර උපාංග කිහිපයකට පුරනය විය නොහැක.',
|
||||||
|
'login_attribute' => 'පිවිසුම් ගුණාංගය',
|
||||||
|
'login_attribute_comment' => 'පුරනය වීම සඳහා භාවිතා කළ යුතු මූලික පරිශීලක විස්තර තෝරන්න.',
|
||||||
|
'remember_login' => 'පිවිසුම් මාදිලිය මතක තබා ගන්න',
|
||||||
|
'remember_login_comment' => 'පරිශීලක සැසිය ස්ථීර විය යුතුද යන්න තෝරන්න.',
|
||||||
|
'remember_always' => 'සැමවිටම',
|
||||||
|
'remember_never' => 'කවදාවත් නැහැ',
|
||||||
|
'remember_ask' => 'පුරනය වීමේදී පරිශීලකයාගෙන් විමසන්න',
|
||||||
|
],
|
||||||
|
'user' => [
|
||||||
|
'label' => 'පරිශීලක',
|
||||||
|
'id' => 'හැඳුනුම්පත',
|
||||||
|
'username' => 'පරිශීලක නාමය',
|
||||||
|
'name' => 'නම',
|
||||||
|
'name_empty' => 'නිර්නාමික',
|
||||||
|
'surname' => 'වාසගම',
|
||||||
|
'email' => 'විද්යුත් තැපෑල',
|
||||||
|
'created_at' => 'ලියාපදිංචි',
|
||||||
|
'last_seen' => 'අන්තිමට දැක්කේ',
|
||||||
|
'is_guest' => 'අමුත්තන්ගේ',
|
||||||
|
'joined' => 'එකතු වුණා',
|
||||||
|
'is_online' => 'දැන් ඔන්ලයින්',
|
||||||
|
'is_offline' => 'දැනට නොබැඳි',
|
||||||
|
'send_invite' => 'විද්යුත් තැපෑලෙන් ආරාධනාවක් යවන්න',
|
||||||
|
'send_invite_comment' => 'පිවිසුම් සහ මුරපද තොරතුරු අඩංගු පිළිගැනීමේ පණිවිඩයක් යවයි.',
|
||||||
|
'create_password' => 'මුරපදය සාදන්න',
|
||||||
|
'create_password_comment' => 'පුරනය වීමට භාවිතා කරන නව මුරපදයක් ඇතුලත් කරන්න.',
|
||||||
|
'reset_password' => 'මුරපදය නැවත සකසන්න',
|
||||||
|
'reset_password_comment' => 'මෙම පරිශීලක මුරපදය නැවත සැකසීමට, මෙහි නව මුරපදයක් ඇතුළත් කරන්න.',
|
||||||
|
'confirm_password' => 'මුරපදය තහවුරු කිරීම',
|
||||||
|
'confirm_password_comment' => 'එය තහවුරු කිරීමට මුරපදය නැවත ඇතුල් කරන්න.',
|
||||||
|
'groups' => 'කණ්ඩායම්',
|
||||||
|
'empty_groups' => 'ලබා ගත හැකි පරිශීලක කණ්ඩායම් නොමැත.',
|
||||||
|
'avatar' => 'පැතිකඩ පින්තූරය',
|
||||||
|
'details' => 'විස්තර',
|
||||||
|
'account' => 'ගිණුම',
|
||||||
|
'block_mail' => 'මෙම පරිශීලකයාට යවන සියලුම පිටතට යන තැපැල් අවහිර කරන්න.',
|
||||||
|
'status_label' => 'තත්ත්වය',
|
||||||
|
'status_guest' => 'අමුත්තන්ගේ',
|
||||||
|
'status_activated' => 'සක්රිය කර ඇත',
|
||||||
|
'status_registered' => 'ලියාපදිංචි',
|
||||||
|
'created_ip_address' => 'සාදන ලද IP ලිපිනය',
|
||||||
|
'last_ip_address' => 'අවසාන IP ලිපිනය',
|
||||||
|
],
|
||||||
|
'group' => [
|
||||||
|
'label' => 'සමූහය',
|
||||||
|
'id' => 'හැඳුනුම්පත',
|
||||||
|
'name' => 'නම',
|
||||||
|
'description_field' => 'විස්තර',
|
||||||
|
'code' => 'කේතය',
|
||||||
|
'code_comment' => 'මෙම කණ්ඩායම හඳුනා ගැනීමට භාවිතා කරන අද්විතීය කේතයක් ඇතුළත් කරන්න.',
|
||||||
|
'created_at' => 'නිර්මාණය කළා',
|
||||||
|
'users_count' => 'පරිශීලකයන්'
|
||||||
|
],
|
||||||
|
'groups' => [
|
||||||
|
'menu_label' => 'කණ්ඩායම්',
|
||||||
|
'all_groups' => 'පරිශීලක කණ්ඩායම්',
|
||||||
|
'new_group' => 'නව සමූහය',
|
||||||
|
'delete_selected_confirm' => 'ඔබට ඇත්තටම තෝරාගත් කණ්ඩායම් මැකීමට අවශ්යද?',
|
||||||
|
'list_title' => 'කණ්ඩායම් කළමනාකරණය කරන්න',
|
||||||
|
'delete_confirm' => 'ඔබට ඇත්තටම මෙම සමූහය මැකීමට අවශ්යද?',
|
||||||
|
'delete_selected_success' => 'තෝරාගත් කණ්ඩායම් සාර්ථකව මකා දමන ලදී.',
|
||||||
|
'delete_selected_empty' => 'මකා දැමීමට තෝරාගත් කණ්ඩායම් නොමැත.',
|
||||||
|
'return_to_list' => 'කණ්ඩායම් ලැයිස්තුව වෙත ආපසු යන්න',
|
||||||
|
'return_to_users' => 'පරිශීලක ලැයිස්තුව වෙත ආපසු යන්න',
|
||||||
|
'create_title' => 'පරිශීලක කණ්ඩායමක් සාදන්න',
|
||||||
|
'update_title' => 'පරිශීලක කණ්ඩායම සංස්කරණය කරන්න',
|
||||||
|
'preview_title' => 'පරිශීලක කණ්ඩායම පෙරදසුන් කරන්න'
|
||||||
|
],
|
||||||
|
'login' => [
|
||||||
|
'attribute_email' => 'විද්යුත් තැපෑල',
|
||||||
|
'attribute_username' => 'පරිශීලක නාමය'
|
||||||
|
],
|
||||||
|
'account' => [
|
||||||
|
'account' => 'ගිණුම',
|
||||||
|
'account_desc' => 'පරිශීලක කළමනාකරණ පෝරමය.',
|
||||||
|
'banned' => 'සමාවන්න, මෙම පරිශීලකයා දැනට සක්රිය කර නැත. වැඩිදුර සහාය සඳහා කරුණාකර අප හා සම්බන්ධ වන්න.',
|
||||||
|
'redirect_to' => 'වෙත හරවා යවන්න',
|
||||||
|
'redirect_to_desc' => 'යාවත්කාලීන කිරීම, පුරනය වීම හෝ ලියාපදිංචි වීමෙන් පසු නැවත යොමු කිරීමට පිටුවේ නම.',
|
||||||
|
'code_param' => 'සක්රිය කිරීමේ කේතය පරාමිතිය',
|
||||||
|
'code_param_desc' => 'ලියාපදිංචි සක්රිය කිරීමේ කේතය සඳහා භාවිතා කරන පිටු URL පරාමිතිය',
|
||||||
|
'force_secure' => 'ආරක්ෂිත ප්රොටෝකෝලය බල කරන්න',
|
||||||
|
'force_secure_desc' => 'සෑම විටම URL HTTPS ක්රමයෙන් හරවා යවන්න.',
|
||||||
|
'invalid_user' => 'ලබා දී ඇති අක්තපත්ර සමඟ පරිශීලකයෙකු හමු නොවීය.',
|
||||||
|
'invalid_activation_code' => 'වලංගු නොවන සක්රීය කිරීමේ කේතයක් සපයා ඇත.',
|
||||||
|
'invalid_deactivation_pass' => 'ඔබ ඇතුළු කළ මුරපදය වලංගු නොවේ.',
|
||||||
|
'invalid_current_pass' => 'ඔබ ඇතුළත් කළ වත්මන් මුරපදය වලංගු නොවේ.',
|
||||||
|
'success_activation' => 'ඔබගේ ගිණුම සාර්ථකව සක්රිය කර ඇත.',
|
||||||
|
'success_deactivation' => 'ඔබගේ ගිණුම සාර්ථකව අක්රිය කර ඇත. ඔබ යනවා දැකීම ගැන කණගාටුයි!',
|
||||||
|
'success_saved' => 'සැකසීම් සාර්ථකව සුරකින ලදී!',
|
||||||
|
'login_first' => 'ඔබ මුලින්ම ලොග් විය යුතුය!',
|
||||||
|
'already_active' => 'ඔබගේ ගිණුම දැනටමත් සක්රිය කර ඇත!',
|
||||||
|
'activation_email_sent' => 'ඔබගේ ඊමේල් ලිපිනයට සක්රිය කිරීමේ විද්යුත් තැපෑලක් යවා ඇත.',
|
||||||
|
'activation_by_admin' => 'ඔබ සාර්ථකව ලියාපදිංචි වී ඇත. ඔබගේ ගිණුම තවමත් සක්රිය නොවන අතර පරිපාලකයෙකු විසින් අනුමත කළ යුතුය.',
|
||||||
|
'registration_disabled' => 'ලියාපදිංචි කිරීම් දැනට අබල කර ඇත.',
|
||||||
|
'registration_throttled' => 'ලියාපදිංචිය අවහිර කර ඇත. කරුණාකර පසුව නැවත උත්සාහ කරන්න.',
|
||||||
|
'sign_in' => 'පුරන්න',
|
||||||
|
'register' => 'ලියාපදිංචි කරන්න',
|
||||||
|
'full_name' => 'සම්පූර්ණ නම',
|
||||||
|
'email' => 'විද්යුත් තැපෑල',
|
||||||
|
'password' => 'මුරපදය',
|
||||||
|
'login' => 'ඇතුල් වන්න',
|
||||||
|
'new_password' => 'නව මුරපදය',
|
||||||
|
'new_password_confirm' => 'නව මුරපදය තහවුරු කරන්න',
|
||||||
|
'update_requires_password' => 'යාවත්කාලීන කිරීමේදී මුරපදය තහවුරු කරන්න',
|
||||||
|
'update_requires_password_comment' => 'ඔවුන්ගේ පැතිකඩ වෙනස් කිරීමේදී පරිශීලකයාගේ වත්මන් මුරපදය අවශ්ය වේ.',
|
||||||
|
'activation_page' => 'සක්රිය කිරීමේ පිටුව',
|
||||||
|
'activation_page_comment' => 'පරිශීලක ගිණුම සක්රිය කිරීම සඳහා භාවිතා කිරීමට පිටුවක් තෝරන්න',
|
||||||
|
'reset_page' => 'පිටුව යළි පිහිටුවන්න',
|
||||||
|
'reset_page_comment' => 'ගිණුමේ මුරපදය යළි පිහිටුවීම සඳහා භාවිතා කිරීමට පිටුවක් තෝරන්න',
|
||||||
|
],
|
||||||
|
'reset_password' => [
|
||||||
|
'reset_password' => 'මුරපදය නැවත සකසන්න',
|
||||||
|
'reset_password_desc' => ' අමතක වූ මුරපද පෝරමය.',
|
||||||
|
'code_param' => 'පරාමිතිය කේතය නැවත සකසන්න',
|
||||||
|
'code_param_desc' => 'යළි පිහිටුවීමේ කේතය සඳහා භාවිතා කරන ලද පිටු URL පරාමිතිය'
|
||||||
|
],
|
||||||
|
'session' => [
|
||||||
|
'session' => 'වාරය',
|
||||||
|
'session_desc' => 'පරිශීලක සැසිය පිටුවකට එක් කරන අතර පිටු ප්රවේශය සීමා කළ හැක.',
|
||||||
|
'security_title' => 'පමණක් ඉඩ දෙන්න',
|
||||||
|
'security_desc' => 'මෙම පිටුවට ප්රවේශ වීමට අවසර ඇත්තේ කාටද.',
|
||||||
|
'all' => 'සියලුම',
|
||||||
|
'users' => 'පරිශීලකයන්',
|
||||||
|
'guests' => 'අමුත්තන්',
|
||||||
|
'allowed_groups_title' => 'කණ්ඩායම් වලට ඉඩ දෙන්න',
|
||||||
|
'allowed_groups_description' => 'සියලුම කණ්ඩායම්වලට ඉඩ දීමට අවසර දී ඇති කණ්ඩායම් හෝ කිසිවෙකුට ඉඩ නොදෙන්න',
|
||||||
|
'redirect_title' => 'වෙත හරවා යවන්න',
|
||||||
|
'redirect_desc' => 'ප්රවේශය ප්රතික්ෂේප කළහොත් යළි-යොමු කිරීමට පිටුවේ නම.',
|
||||||
|
'logout' => 'ඔබ සාර්ථකව ලොග් අවුට් වී ඇත!',
|
||||||
|
'stop_impersonate_success' => 'ඔබ තවදුරටත් පරිශීලකයෙකු ලෙස පෙනී සිටින්නේ නැත.',
|
||||||
|
]
|
||||||
|
];
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue