diff --git a/src/Annotation/UserRestrictionType.php b/src/Annotation/UserRestrictionType.php
new file mode 100644
index 0000000..02ac371
--- /dev/null
+++ b/src/Annotation/UserRestrictionType.php
@@ -0,0 +1,37 @@
+name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getExpiry() {
+ return $this->expiry;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPattern() {
+ return $this->pattern;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getAccessType() {
+ return $this->access_type;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRuleType() {
+ return $this->rule_type;
+ }
- // Use the epoch as the default date for non-expiring rules.
- // @TODO do we instead want to make the expiration date extremely far in
- // the future or have another flag that signifies permanent?
- const NO_EXPIRY = 0;
-
- const BLACKLIST = 0;
-
- const WHITELIST = 1;
-
- /**
- * The name of the image style.
- *
- * @var string
- */
- protected $name;
-
- protected $id;
-
- protected $pattern;
-
- /**
- * The user restriction label.
- *
- * @var string
- */
- protected $label;
-
- protected $access_type;
-
- protected $expiry;
-
- protected $rule_type;
-
- /**
- * {@inheritdoc}
- */
- public function id() {
- return $this->name;
- }
-
- public function getExpiry() {
- return $this->expiry;
- }
-
- public function getPattern() {
- return $this->pattern;
- }
-
- public function getAccessType() {
- return $this->access_type;
- }
-
- public function getRuleType() {
- return $this->rule_type;
- }
}
diff --git a/src/Form/UserRestrictionsAddForm.php b/src/Form/UserRestrictionsAddForm.php
index 90f3c00..37479e7 100644
--- a/src/Form/UserRestrictionsAddForm.php
+++ b/src/Form/UserRestrictionsAddForm.php
@@ -9,22 +9,22 @@ use Drupal\Core\Form\FormStateInterface;
*/
class UserRestrictionsAddForm extends UserRestrictionsFormBase {
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, FormStateInterface $form_state) {
- parent::submitForm($form, $form_state);
- drupal_set_message($this->t('User restriction was created for %label.', array('%label' => $this->entity->label())));
- }
+ /**
+ * {@inheritdoc}
+ */
+ public function submitForm(array &$form, FormStateInterface $form_state) {
+ parent::submitForm($form, $form_state);
+ drupal_set_message($this->t('User restriction was created for %label.', array('%label' => $this->entity->label())));
+ }
- /**
- * {@inheritdoc}
- */
- public function actions(array $form, FormStateInterface $form_state) {
- $actions = parent::actions($form, $form_state);
- $actions['submit']['#value'] = $this->t('Create new user restriction');
+ /**
+ * {@inheritdoc}
+ */
+ public function actions(array $form, FormStateInterface $form_state) {
+ $actions = parent::actions($form, $form_state);
+ $actions['submit']['#value'] = $this->t('Create new user restriction');
- return $actions;
- }
+ return $actions;
+ }
}
diff --git a/src/Form/UserRestrictionsFormBase.php b/src/Form/UserRestrictionsFormBase.php
index 5a03f59..4094e99 100644
--- a/src/Form/UserRestrictionsFormBase.php
+++ b/src/Form/UserRestrictionsFormBase.php
@@ -4,138 +4,143 @@ namespace Drupal\user_restrictions\Form;
use Drupal\Core\Datetime\DrupalDateTime;
use Drupal\Core\Entity\EntityForm;
-use Drupal\Core\Entity\EntityStorageInterface;
use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Url;
use Drupal\user_restrictions\Entity\UserRestrictions;
-use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Base form for image style add and edit forms.
*/
abstract class UserRestrictionsFormBase extends EntityForm {
- /**
- * The entity being used by this form.
- *
- * @var \Drupal\user_restrictions\Entity\UserRestrictions
- */
- protected $entity;
-
- /**
- * {@inheritdoc}
- */
- public function form(array $form, FormStateInterface $form_state) {
-
- $form['label'] = array(
- '#type' => 'textfield',
- '#title' => $this->t('User restriction name'),
- '#default_value' => $this->entity->label(),
- '#required' => TRUE,
- );
- $form['name'] = array(
- '#type' => 'machine_name',
- '#machine_name' => array(
- 'exists' => ['\Drupal\user_restrictions\Entity\UserRestriction', 'load'],
- ),
- '#default_value' => $this->entity->id(),
- '#required' => TRUE,
- );
-
- $form['pattern'] = array(
- '#type' => 'textfield',
- '#title' => $this->t('Pattern'),
- '#size' => 10,
- '#maxlength' => 64,
- '#default_value' => $this->entity->getPattern(),
- '#field_prefix' => '/',
- '#field_suffix' => '/i',
- '#description' => $this->t('Add a pattern for this rule to match.
Regular expressions are accepted and can be used for more complex restrictions.'),
- '#required' => TRUE,
- );
-
- $form['access_type'] = array(
- '#type' => 'radios',
- '#title' => t('Access type'),
- '#default_value' => $this->entity->getAccessType(),
- '#options' => array(UserRestrictions::BLACKLIST => $this->t('Blacklist'), UserRestrictions::WHITELIST => $this->t('Whitelist')),
- '#required' => TRUE,
- );
-
- $form['rule_type'] = array(
- '#type' => 'radios',
- '#title' => t('Restriction type'),
- '#default_value' => $this->entity->getRuleType(),
- '#options' => array('name' => $this->t('Username'), 'mail' => $this->t('Email')),
- '#required' => TRUE,
- );
-
- $form['expiration'] = array(
- '#type' => 'details',
- '#title' => $this->t('Expiration'),
- '#description' => $this->t('Set a time for this user restriction to expire or create a permanent restriction.'),
- '#open' => TRUE,
- '#required' => TRUE,
-
- );
- $form['expiration']['permanent'] = array(
- '#type' => 'checkbox',
- '#title' => $this->t('Never expire'),
- );
- $form['expiration']['expiry_container'] = array(
- '#type' => 'container',
- '#states' => array(
- // Hide the additional settings when the blocked email is disabled.
- 'invisible' => array(
- 'input[name="permanent"]' => array('checked' => TRUE),
- ),
- ),
- '#open' => TRUE,
- );
-
- // Set the default expiration to be 7 days in the future.
- $default_expiration = new DrupalDateTime('now +7 days');
-
- if ($default_expiration = (int) $this->entity->getExpiry()) {
- $default_expiration = DrupalDateTime::createFromTimestamp($default_expiration);
- }
-
- $form['expiration']['expiry_container']['expiry'] = array(
- '#type' => 'datetime',
- '#default_value' => $default_expiration,
- '#title_display' => 'invisible',
- '#title' => $this->t('Expiry time'),
- '#required' => TRUE,
- );
-
- return parent::form($form, $form_state);
+ /**
+ * The entity being used by this form.
+ *
+ * @var \Drupal\user_restrictions\Entity\UserRestrictions
+ */
+ protected $entity;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function form(array $form, FormStateInterface $form_state) {
+ /** @var \Drupal\user_restrictions\UserRestrictionTypeManagerInterface $type_manager */
+ $type_manager = \Drupal::service('user_restrictions.type_manager');
+
+ $form['label'] = [
+ '#type' => 'textfield',
+ '#title' => $this->t('User restriction name'),
+ '#default_value' => $this->entity->label(),
+ '#required' => TRUE,
+ ];
+ $form['name'] = [
+ '#type' => 'machine_name',
+ '#machine_name' => [
+ 'exists' => ['\Drupal\user_restrictions\Entity\UserRestriction', 'load'],
+ ],
+ '#default_value' => $this->entity->id(),
+ '#required' => TRUE,
+ ];
+
+ $form['pattern'] = [
+ '#type' => 'textfield',
+ '#title' => $this->t('Pattern'),
+ '#size' => 10,
+ '#maxlength' => 64,
+ '#default_value' => $this->entity->getPattern(),
+ '#field_prefix' => '/',
+ '#field_suffix' => '/i',
+ '#description' => $this->t('Add a pattern for this rule to match.
Regular expressions are accepted and can be used for more complex restrictions.'),
+ '#required' => TRUE,
+ ];
+
+ $form['access_type'] = [
+ '#type' => 'radios',
+ '#title' => t('Access type'),
+ '#default_value' => $this->entity->getAccessType(),
+ '#options' => [UserRestrictions::BLACKLIST => $this->t('Blacklist'), UserRestrictions::WHITELIST => $this->t('Whitelist')],
+ '#required' => TRUE,
+ ];
+
+ $form['rule_type'] = [
+ '#type' => 'radios',
+ '#title' => t('Restriction type'),
+ '#default_value' => $this->entity->getRuleType(),
+ '#options' => $type_manager->getTypesAsOptions(),
+ '#required' => TRUE,
+ ];
+
+ $form['expiration'] = [
+ '#type' => 'details',
+ '#title' => $this->t('Expiration'),
+ '#description' => $this->t('Set a time for this user restriction to expire or create a permanent restriction.'),
+ '#open' => TRUE,
+ '#required' => TRUE,
+ ];
+ $form['expiration']['permanent'] = [
+ '#type' => 'checkbox',
+ '#title' => $this->t('Never expire'),
+ '#default_value' => ($this->entity->getExpiry() == UserRestrictions::NO_EXPIRY),
+ ];
+ $form['expiration']['expiry_container'] = [
+ '#type' => 'container',
+ '#states' => [
+ // Hide the additional settings when the blocked email is disabled.
+ 'invisible' => [
+ 'input[name="permanent"]' => ['checked' => TRUE],
+ ],
+ ],
+ '#open' => TRUE,
+ ];
+
+ // Set the default expiration to be 7 days in the future.
+ $default_expiration = new DrupalDateTime('now +7 days');
+
+ if ($expiration = (int) $this->entity->getExpiry()) {
+ $default_expiration = DrupalDateTime::createFromTimestamp($expiration);
}
-
- public function validateForm(array &$form, FormStateInterface $form_state)
- {
- // Store the expiration time as unixtime as configuration entities may
- // only use scalar values.
-
- /* @var $datetime DrupalDateTime */
- $datetime = $form_state->getValue('expiry');
+ $form['expiration']['expiry_container']['expiry'] = [
+ '#type' => 'datetime',
+ '#default_value' => $default_expiration,
+ '#title_display' => 'invisible',
+ '#title' => $this->t('Expiry time'),
+ '#required' => TRUE,
+ ];
+
+ return parent::form($form, $form_state);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateForm(array &$form, FormStateInterface $form_state) {
+ // Check for duplicate pattern.
+ $existing = $this->entityTypeManager->getStorage('user_restrictions')->loadByProperties(['rule_type' => $form_state->getValue('rule_type'), 'pattern' => $form_state->getValue('pattern')]);
+ if (!empty($existing)) {
+ $form_state->setError($form['pattern'], $this->t('A rule with the same pattern already exists.'));
+ }
- if ($form_state->getValue('permanent')) {
- $form_state->setValue('expiry', UserRestrictions::NO_EXPIRY);
- }
- else {
- $form_state->setValue('expiry', (int) $datetime->format('U'));
- }
+ // Store the expiration time as unixtime as configuration entities may
+ // only use scalar values.
+ /* @var $datetime DrupalDateTime */
+ $datetime = $form_state->getValue('expiry');
- parent::validateForm($form, $form_state);
+ if ($form_state->getValue('permanent')) {
+ $form_state->setValue('expiry', UserRestrictions::NO_EXPIRY);
}
-
- /**
- * {@inheritdoc}
- */
- public function save(array $form, FormStateInterface $form_state) {
- parent::save($form, $form_state);
- //$form_state->setRedirectUrl(Url::fromRoute('user_restrictions.collection'));
+ else {
+ $form_state->setValue('expiry', (int) $datetime->format('U'));
}
-}
\ No newline at end of file
+ parent::validateForm($form, $form_state);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function save(array $form, FormStateInterface $form_state) {
+ parent::save($form, $form_state);
+ //$form_state->setRedirectUrl(Url::fromRoute('user_restrictions.collection'));
+ }
+
+}
diff --git a/src/Plugin/UserRestrictionType/ClientIp.php b/src/Plugin/UserRestrictionType/ClientIp.php
new file mode 100644
index 0000000..fa4629a
--- /dev/null
+++ b/src/Plugin/UserRestrictionType/ClientIp.php
@@ -0,0 +1,62 @@
+requestStack = $request_stack;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('request_stack'), $container->get('logger.channel.user_restrictions'));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function matches($data) {
+ $client_ip = $this->requestStack->getCurrentRequest()->getClientIp();
+ $restriction = parent::matchesValue($client_ip);
+ if ($restriction) {
+ $this->logger->notice('Restricted client IP %client_ip matching %restriction has been blocked.', ['%client_ip' => $client_ip, '%restriction' => $restriction->link($restriction->label())]);
+ }
+ return $restriction;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getErrorMessage() {
+ return $this->t('Accessing the site from the IP %value is not allowed.', ['%value' => $this->requestStack->getCurrentRequest()->getClientIp()]);
+ }
+
+}
diff --git a/src/Plugin/UserRestrictionType/Email.php b/src/Plugin/UserRestrictionType/Email.php
new file mode 100644
index 0000000..7936f2d
--- /dev/null
+++ b/src/Plugin/UserRestrictionType/Email.php
@@ -0,0 +1,42 @@
+mail = $data['mail'];
+ $restriction = parent::matchesValue($this->mail);
+ if ($restriction) {
+ $this->logger->notice('Restricted email %mail matching %restriction has been blocked.', ['%mail' => $this->mail, '%restriction' => $restriction->link($restriction->label())]);
+ }
+ return $restriction;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getErrorMessage() {
+ return $this->t('The email %mail is reserved, and cannot be used.', ['%mail' => $this->mail]);
+ }
+
+}
diff --git a/src/Plugin/UserRestrictionType/Name.php b/src/Plugin/UserRestrictionType/Name.php
new file mode 100644
index 0000000..2a64da7
--- /dev/null
+++ b/src/Plugin/UserRestrictionType/Name.php
@@ -0,0 +1,42 @@
+name = $data['name'];
+ $restriction = parent::matchesValue($this->name);
+ if ($restriction) {
+ $this->logger->notice('Restricted name %name matching %restriction has been blocked.', ['%name' => $this->name, '%restriction' => $restriction->link($restriction->label())]);
+ }
+ return $restriction;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getErrorMessage() {
+ return $this->t('The name %name is reserved, and cannot be used.', ['%name' => $this->name]);
+ }
+
+}
diff --git a/src/Plugin/UserRestrictionType/UserRestrictionTypeBase.php b/src/Plugin/UserRestrictionType/UserRestrictionTypeBase.php
new file mode 100644
index 0000000..cd655ab
--- /dev/null
+++ b/src/Plugin/UserRestrictionType/UserRestrictionTypeBase.php
@@ -0,0 +1,128 @@
+entityStorage = $entity_manager->getStorage('user_restrictions');
+ $this->logger = $logger;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
+ return new static($configuration, $plugin_id, $plugin_definition, $container->get('entity_type.manager'), $container->get('logger.channel.user_restrictions'));
+ }
+
+ /**
+ * Check if the specified value matches the restriction.
+ *
+ * @param string $value
+ * String to check against all restrictions of the type.
+ *
+ * @return boolean|\Drupal\user_restrictions\Entity\UserRestrictions
+ * The restriction entity if the value matches one of the restrictions,
+ * FALSE otherwise.
+ */
+ protected function matchesValue($value) {
+ // Load rules with exact pattern matches.
+ $exact_rules = $this->entityStorage
+ ->loadByProperties(['rule_type' => $this->getPluginId(), 'pattern' => $value]);
+ if (!empty($exact_rules)) {
+ // Simply take the first matching rule as we have no weight (yet).
+ /** @var \Drupal\user_restrictions\Entity\UserRestrictions $rule */
+ $rule = reset($exact_rules);
+ return ($rule->getAccessType() == UserRestrictions::BLACKLIST) ? $rule : FALSE;
+ }
+
+ // Load all rules of the restriction type.
+ $rules = $this->entityStorage
+ ->loadByProperties(['rule_type' => $this->getPluginId()]);
+ if (empty($rules)) {
+ return FALSE;
+ }
+
+ /** @var \Drupal\user_restrictions\Entity\UserRestrictions $rule */
+ foreach ($rules as $rule) {
+ $pattern = strtr(preg_quote($rule->getPattern()), ['%' => '.*']);
+ if (preg_match('/' . $pattern . '/i', $value)) {
+ // Exit loop after first matching pattern.
+ return ($rule->getAccessType() == UserRestrictions::BLACKLIST) ? $rule : FALSE;
+ }
+ }
+
+ // Fallback to no match.
+ return FALSE;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPatterns() {
+ if (!empty($this->patterns)) {
+ return $this->patterns;
+ }
+ $rules = $this->entityStorage
+ ->loadByProperties(['rule_type' => $this->getPluginId()]);
+ if (empty($rules)) {
+ return [];
+ }
+ /** @var \Drupal\user_restrictions\Entity\UserRestrictions $rule */
+ foreach ($rules as $id => $rule) {
+ $this->patterns[$id] = $rule->getPattern();
+ }
+ return $this->patterns;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getLabel() {
+ return $this->pluginDefinition['label'];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getErrorMessage() {
+ return $this->t('Using reserved data.');
+ }
+
+}
diff --git a/src/Plugin/UserRestrictionTypeInterface.php b/src/Plugin/UserRestrictionTypeInterface.php
new file mode 100644
index 0000000..0f3ab46
--- /dev/null
+++ b/src/Plugin/UserRestrictionTypeInterface.php
@@ -0,0 +1,47 @@
+ 'User Restrictions Basic test',
- 'description' => 'Tests creation and loading of restrictions',
- 'group' => 'User Restrictions',
- );
- }
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- $this->name = $this->randomName();
- $this->type = 'name';
-
- $restriction = entity_create('user_restrictions', array(
- 'mask' => $this->name,
- 'type' => $this->type,
- 'status' => 1,
- ));
- $restriction->save();
-
- $this->id = $restriction->id();
- }
-
- /**
- * Ensure the restriction exists in the database
- */
- protected function testUserRestrictionsRecordExists() {
- $restriction = user_restrictions_load($this->id, TRUE);
- $this->assertTrue($restriction, 'User Restriction exists in the database');
- $this->assertEqual($restriction->label(), $this->name, 'User Restriction name matches');
- $this->assertEqual($restriction->getType(), $this->type, 'User Restriction type matches');
- }
-
-}
diff --git a/src/Tests/UserRestrictionsExpireTest.php b/src/Tests/UserRestrictionsExpireTest.php
deleted file mode 100644
index cee95a2..0000000
--- a/src/Tests/UserRestrictionsExpireTest.php
+++ /dev/null
@@ -1,72 +0,0 @@
- 'User Restrictions Expire test',
- 'description' => 'Tests expired user restrictions rules do not take effect and are deleted on cron.',
- 'group' => 'User Restrictions',
- );
- }
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- // Create a restriction with an expiration date in the past.
- $this->name = $this->randomName();
-
- $restriction = entity_create('user_restrictions', array(
- 'mask' => $this->name,
- 'type' => $this->mail,
- 'status' => 1,
- 'expire' => 1000,
- ));
- $restriction->save();
-
- $this->id = $restriction->id();
- }
-
- /**
- * Ensure the restriction exists in the database
- */
- protected function testUserRestrictionsRecordExists() {
- $restriction = user_restrictions_load($this->id, TRUE);
- $this->assertTrue($restriction, 'User Restriction exists in the database');
- $this->assertEqual($restriction->label(), $this->name, 'User Restriction name matches');
- }
-
- /**
- * Ensure an expired user may now log in.
- */
- protected function testUserRestrictionsExpiredLogin() {
- $account = $this->drupalCreateUser(array(), $this->name);
- $this->drupalLogin($account);
- }
-
- /**
- * Ensure an expired restriction gets deleted on cron
- */
- protected function testUserRestrictionsExpiredCron() {
- \Drupal::service('cron')->run();
- $this->assertFalse(user_restrictions_load($this->id, TRUE), 'User Restriction was removed from the database.');
- }
-
-}
diff --git a/src/Tests/UserRestrictionsTestBase.php b/src/Tests/UserRestrictionsTestBase.php
deleted file mode 100644
index 71d4df8..0000000
--- a/src/Tests/UserRestrictionsTestBase.php
+++ /dev/null
@@ -1,71 +0,0 @@
-set('register', USER_REGISTER_VISITORS)->save();
- }
-
- /**
- * Create some user restrictions
- */
- protected function createRestrictions() {
-
- // Block any user with a name starting 'lol'
- $restrictions[] = array(
- 'mask' => 'lol%',
- 'type' => 'name',
- 'status' => 0,
- );
-
- // Allow the user named 'lolcats'
- $restrictions[] = array(
- 'mask' => 'lolcats',
- 'type' => 'name',
- 'status' => 1,
- );
-
- // Block any user with a .ru email address
- $restrictions[] = array(
- 'mask' => '%@%.ru',
- 'type' => 'mail',
- 'status' => 0,
- );
-
- // Specically allow typhonius@mail.ru
- $restrictions[] = array(
- 'mask' => 'typhonius@mail.ru',
- 'type' => 'mail',
- 'status' => 1,
- );
-
- foreach ($restrictions as $restriction) {
- $entity = entity_create('user_restrictions', $restriction);
- $entity->save();
- }
- }
-
-}
diff --git a/src/UserRestrictionTypeManager.php b/src/UserRestrictionTypeManager.php
new file mode 100644
index 0000000..69ae504
--- /dev/null
+++ b/src/UserRestrictionTypeManager.php
@@ -0,0 +1,77 @@
+alterInfo('user_restriction_type_info');
+ $this->setCacheBackend($cache_backend, 'user_restriction_type_plugins');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTypes() {
+ $instances = &drupal_static(__FUNCTION__, []);
+ if (empty($instances)) {
+ // Get registered plugins.
+ $plugins = $this->getDefinitions();
+ // Sort plugins by weight.
+ uasort($plugins, array('Drupal\Component\Utility\SortArray', 'sortByWeightElement'));
+ foreach ($plugins as $plugin_id => $plugin) {
+ // Instanciate the plugin.
+ $instances[$plugin_id] = $this->createInstance($plugin_id, $plugin);
+ }
+ }
+
+ return $instances;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getType($id) {
+ $instances = $this->getTypes();
+ return $instances[$id];
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getTypesAsOptions() {
+ $options = [];
+
+ foreach ($this->getTypes() as $plugin_id => $type) {
+ $options[$plugin_id] = $type->getLabel();
+ }
+
+ return $options;
+ }
+
+}
diff --git a/src/UserRestrictionTypeManagerInterface.php b/src/UserRestrictionTypeManagerInterface.php
new file mode 100644
index 0000000..6daecb0
--- /dev/null
+++ b/src/UserRestrictionTypeManagerInterface.php
@@ -0,0 +1,37 @@
+t('User restriction');
- $header['rule_type'] = $this->t('Rule type');
- $header['pattern'] = $this->t('Pattern');
- $header['access_type'] = $this->t('Access type');
- $header['expiry'] = $this->t('Expiry');
- return $header + parent::buildHeader();
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildRow(UserRestrictions $entity) {
-
- $row['label'] = $entity->label();
- $row['type'] = $entity->getRuleType();
- $row['pattern'] = $entity->getPattern();
- $row['access_type'] = $entity->getAccessType() ? $this->t('Whitelisted') : $this->t('Blacklisted');
- $row['expiry'] = $entity->getExpiry() ? date('Y-m-d H:i:s', $entity->getExpiry()) : $this->t('Never');
- return $row + parent::buildRow($entity);
- }
-
- /**
- * {@inheritdoc}
- */
- public function render() {
- $build = parent::render();
- $build['table']['#empty'] = $this->t('There are currently no user restrictions. Add a new one.', [
- ':url' => Url::fromRoute('user_restrictions.add')->toString(),
- ]);
- return $build;
- }
+ /**
+ * The user restriction type manager.
+ *
+ * @var \Drupal\user_restrictions\UserRestrictionTypeManagerInterface
+ */
+ protected $typeManager;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __construct(EntityTypeInterface $entity_type, EntityStorageInterface $storage) {
+ parent::__construct($entity_type, $storage);
+ $this->typeManager = \Drupal::service('user_restrictions.type_manager');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildHeader() {
+ $header['label'] = $this->t('User restriction');
+ $header['rule_type'] = $this->t('Rule type');
+ $header['pattern'] = $this->t('Pattern');
+ $header['access_type'] = $this->t('Access type');
+ $header['expiry'] = $this->t('Expiry');
+ return $header + parent::buildHeader();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function buildRow(UserRestrictions $entity) {
+ $row['label'] = $entity->label();
+ $row['type'] = $this->typeManager->getType($entity->getRuleType())->getLabel();
+ $row['pattern'] = $entity->getPattern();
+ $row['access_type'] = $entity->getAccessType() ? $this->t('Whitelisted') : $this->t('Blacklisted');
+ $row['expiry'] = $entity->getExpiry() == UserRestrictions::NO_EXPIRY ? $this->t('Never') : date('Y-m-d H:i:s', $entity->getExpiry());
+ return $row + parent::buildRow($entity);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function render() {
+ $build = parent::render();
+ $build['table']['#empty'] = $this->t('There are currently no user restrictions. Add a new one.', [
+ ':url' => Url::fromRoute('user_restrictions.add')->toString(),
+ ]);
+ return $build;
+ }
}
diff --git a/src/UserRestrictionsManager.php b/src/UserRestrictionsManager.php
index 25b3ec5..b0c9560 100644
--- a/src/UserRestrictionsManager.php
+++ b/src/UserRestrictionsManager.php
@@ -1,102 +1,116 @@
getQuery()
- ->sort('name')
- ->execute();
-
- $this->rules = $entity_storage->loadMultiple($ids);
- }
-
- public function setName($name) {
- $this->name = $name;
+ /**
+ *
+ * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_manager
+ * The entity storage.
+ * @param \Drupal\user_restrictions\UserRestrictionTypeManagerInterface $type_manager
+ * The user restriction type manager.
+ * @param LoggerInterface $logger
+ * The user_restrictions logger channel.
+ */
+ public function __construct(EntityTypeManagerInterface $entity_manager, UserRestrictionTypeManagerInterface $type_manager, LoggerInterface $logger) {
+ $this->entityStorage = $entity_manager->getStorage('user_restrictions');
+ $this->typeManager = $type_manager;
+ $this->logger = $logger;
}
- public function setMail($mail) {
- $this->mail = $mail;
- }
-
- public function isRestricted() {
- foreach ($this->rules as $rule) {
- /* @var $rule UserRestrictions */
-
- // @TODO preg_quote
-
- switch ($rule->getRuleType()) {
- case 'name':
- if (preg_match($rule->getPattern(), $this->name)) {
- $this->setError('name', t('The name %name is reserved, and cannot be used.', array('%name' => $this->name)));
- \Drupal::logger('user_restrictions')->notice('Restricted name %name matching %rule has been blocked.', array('%name' => $this->name, '%rule' => $rule->link($rule->label())));
- return TRUE;
- }
- break;
-
- case 'mail':
- if (preg_match($rule->getPattern(), $this->mail)) {
- $this->setError('mail', t('The email address %email is reserved, and cannot be used.', array('%email' => $this->mail)));
- \Drupal::logger('user_restrictions')->notice('Restricted email %mail matching %rule has been blocked.', array('%mail' => $this->mail, '%rule' => $rule->link($rule->label())));
- return TRUE;
- }
- break;
-
- default:
- // @TODO log this or remove it?
- continue;
-
+ /**
+ * {@inheritdoc}
+ */
+ public function matchesRestrictions($data) {
+ /** @var \Drupal\user_restrictions\Plugin\UserRestrictionTypeInterface $type */
+ foreach ($this->typeManager->getTypes() as $key => $type) {
+ if ($type->matches($data)) {
+ $this->setError($key, $type->getErrorMessage());
+ // Break after first match.
+ return TRUE;
}
}
+ // No restrictions match.
return FALSE;
}
+ /**
+ * Set error message for a specific restriction type.
+ *
+ * @param string $type
+ * Type of restriction, i.e. "name".
+ * @param string $message
+ * Error message.
+ *
+ * @return \Drupal\user_restrictions\UserRestrictionsManagerInterface
+ * The service for chaining.
+ */
protected function setError($type, $message) {
$this->errors[$type] = $message;
+ return $this;
}
+ /**
+ * {@inheritdoc}
+ */
public function getErrors() {
return $this->errors;
}
+ /**
+ * {@inheritdoc}
+ */
public function deleteExpiredRules() {
- foreach ($this->rules as $rule) {
- /* @var $rule UserRestrictions */
-
+ $rules = $this->entityStorage->loadMultiple();
+ /* @var $rule \Drupal\user_restrictions\Entity\UserRestrictions */
+ foreach ($rules as $rule) {
$expiry = $rule->getExpiry();
if ($expiry !== UserRestrictions::NO_EXPIRY && $expiry < REQUEST_TIME) {
$rule->delete();
- \Drupal::logger('user_restrictions')->notice('Expired rule %label has been deleted.', array('%label' => $rule->label()));
+ $this->logger->notice('Expired rule %label has been deleted.', ['%label' => $rule->label()]);
}
}
+ return $this;
}
-}
\ No newline at end of file
+}
diff --git a/src/UserRestrictionsManagerInterface.php b/src/UserRestrictionsManagerInterface.php
index 06c1b08..2fd5986 100644
--- a/src/UserRestrictionsManagerInterface.php
+++ b/src/UserRestrictionsManagerInterface.php
@@ -1,16 +1,37 @@
storage->load($this->id);
+ $this->assertTrue($restriction, 'User restriction exists in the database');
+ $this->assertEqual($restriction->label(), $this->name, 'User restriction name matches');
+ $this->assertEqual($restriction->getType(), $this->type, 'User restriction type matches');
+ }
+
+}
diff --git a/tests/src/Functional/UserRestrictionsExpireTest.php b/tests/src/Functional/UserRestrictionsExpireTest.php
new file mode 100644
index 0000000..5c9d0a8
--- /dev/null
+++ b/tests/src/Functional/UserRestrictionsExpireTest.php
@@ -0,0 +1,42 @@
+storage->load($this->id);
+ $this->assertNotNull($restriction, 'User Restriction exists in the database');
+ $this->assertEqual($restriction->label(), $this->name, 'User restriction exists');
+ }
+
+ /**
+ * Ensure an expired user may now log in.
+ */
+ protected function testUserRestrictionsExpiredLogin() {
+ $account = $this->drupalCreateUser([], $this->name);
+ $this->drupalLogin($account);
+ }
+
+ /**
+ * Ensure an expired restriction gets deleted on cron
+ */
+ protected function testUserRestrictionsExpiredCron() {
+ \Drupal::service('cron')->run();
+ $this->storage->resetCache($this->id);
+ $this->assertNull($this->storage->load($this->id), 'User restriction does not exist.');
+ }
+
+}
diff --git a/src/Tests/UserRestrictionsLoginTest.php b/tests/src/Functional/UserRestrictionsLoginTest.php
similarity index 71%
rename from src/Tests/UserRestrictionsLoginTest.php
rename to tests/src/Functional/UserRestrictionsLoginTest.php
index 1a44392..2711c3d 100644
--- a/src/Tests/UserRestrictionsLoginTest.php
+++ b/tests/src/Functional/UserRestrictionsLoginTest.php
@@ -1,33 +1,14 @@
'User Restrictions Login test',
- 'description' => 'Test the user restrictions rules for approved and denied names and emails.',
- 'group' => 'User Restrictions',
- );
- }
-
- /**
- * {@inheritdoc}
- */
- protected function setUp() {
- parent::setUp();
-
- // Create some default User Restrictions
- $this->createRestrictions();
- }
-
/**
* Ensure a user cannot log in if their name is on the blacklist
*/
@@ -35,11 +16,11 @@ class UserRestrictionsLoginTest extends UserRestrictionsTestBase {
$this->drupalGet('user/register');
$name = 'lol' . $this->randomName();
- $edit = array();
+ $edit = [];
$edit['name'] = $name;
$edit['mail'] = $this->randomName() . '@example.com';
$this->drupalPostForm('user/register', $edit, t('Create new account'));
- $this->assertText(t('The name @name is not allowed', array('@name' => $name)), 'User "name" restricted.');
+ $this->assertText(t('The name %name is reserved, and cannot be used.', ['%name' => $name]), 'User "name" restricted.');
}
/**
@@ -50,7 +31,7 @@ class UserRestrictionsLoginTest extends UserRestrictionsTestBase {
$this->drupalGet('user/register');
$name = 'lolcats';
- $edit = array();
+ $edit = [];
$edit['name'] = $name;
$edit['mail'] = $this->randomName() . '@example.com';
$this->drupalPostForm('user/register', $edit, t('Create new account'));
@@ -64,11 +45,11 @@ class UserRestrictionsLoginTest extends UserRestrictionsTestBase {
$this->drupalGet('user/register');
$email = $this->randomName() . '@' . $this->randomName() . '.ru';
- $edit = array();
+ $edit = [];
$edit['name'] = $this->randomName();
$edit['mail'] = $email;
$this->drupalPostForm('user/register', $edit, t('Create new account'));
- $this->assertText(t('The mail @email is not allowed', array('@email' => $email)), 'User "email" restricted.');
+ $this->assertText(t('The email %mail is reserved, and cannot be used.', ['%email' => $email]), 'User "email" restricted.');
}
/**
@@ -79,7 +60,7 @@ class UserRestrictionsLoginTest extends UserRestrictionsTestBase {
$this->drupalGet('user/register');
$email = 'typhonius@mail.ru';
- $edit = array();
+ $edit = [];
$edit['name'] = $this->randomName();
$edit['mail'] = $email;
$this->drupalPostForm('user/register', $edit, t('Create new account'));
diff --git a/tests/src/Functional/UserRestrictionsTestBase.php b/tests/src/Functional/UserRestrictionsTestBase.php
new file mode 100644
index 0000000..4042d06
--- /dev/null
+++ b/tests/src/Functional/UserRestrictionsTestBase.php
@@ -0,0 +1,44 @@
+storage = \Drupal::service('entity_type.manager')
+ ->getStorage('user_restrictions');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function setUp() {
+ parent::setUp();
+
+ // Allow registration by site visitors without administrator approval.
+ $config = \Drupal::config('user.settings');
+ $config->set('register', \USER_REGISTER_VISITORS)->save();
+ }
+
+}
diff --git a/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_1.yml b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_1.yml
new file mode 100644
index 0000000..ac530d2
--- /dev/null
+++ b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_1.yml
@@ -0,0 +1,8 @@
+status: true
+dependencies: { }
+name: test_rule_1
+label: 'Test rule #1'
+pattern: 'lol%'
+access_type: '0'
+rule_type: name
+expiry: 0
diff --git a/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_2.yml b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_2.yml
new file mode 100644
index 0000000..5f823c9
--- /dev/null
+++ b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_2.yml
@@ -0,0 +1,8 @@
+status: true
+dependencies: { }
+name: test_rule_2
+label: 'Test rule #2'
+pattern: 'lolcats'
+access_type: '1'
+rule_type: name
+expiry: 0
diff --git a/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_3.yml b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_3.yml
new file mode 100644
index 0000000..ea5b637
--- /dev/null
+++ b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_3.yml
@@ -0,0 +1,8 @@
+status: true
+dependencies: { }
+name: test_rule_3
+label: 'Test rule #3'
+pattern: '%@%.ru'
+access_type: '0'
+rule_type: mail
+expiry: 0
diff --git a/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_4.yml b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_4.yml
new file mode 100644
index 0000000..40f0d86
--- /dev/null
+++ b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_4.yml
@@ -0,0 +1,8 @@
+status: true
+dependencies: { }
+name: test_rule_4
+label: 'Test rule #4'
+pattern: 'typhonius@mail.ru'
+access_type: '1'
+rule_type: mail
+expiry: 0
diff --git a/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_expire_1.yml b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_expire_1.yml
new file mode 100644
index 0000000..6473ecf
--- /dev/null
+++ b/tests/user_restrictions_test/config/install/user_restrictions.user_restrictions.test_rule_expire_1.yml
@@ -0,0 +1,8 @@
+status: true
+dependencies: { }
+name: test_rule_expire_1
+label: 'Test rule with expiration #1'
+pattern: 'expired-user'
+access_type: '0'
+rule_type: name
+expiry: 1000
diff --git a/tests/user_restrictions_test/user_restrictions_test.info.yml b/tests/user_restrictions_test/user_restrictions_test.info.yml
new file mode 100644
index 0000000..c360051
--- /dev/null
+++ b/tests/user_restrictions_test/user_restrictions_test.info.yml
@@ -0,0 +1,5 @@
+name: 'User Restrictions Test'
+description: 'Specifies tests for module User restrictions.'
+type: module
+core: '8.x'
+package: Testing
diff --git a/user_restrictions.module b/user_restrictions.module
index cdf993b..35d8408 100755
--- a/user_restrictions.module
+++ b/user_restrictions.module
@@ -4,7 +4,6 @@
* @file
* Specifies rules for restricting the data users can set for their accounts.
*/
-
use \Drupal\user_restrictions\UserRestrictionsManager;
use \Drupal\Core\Form\FormStateInterface;
@@ -14,8 +13,10 @@ use \Drupal\Core\Form\FormStateInterface;
* Delete expired items in the user_restrictions table.
*/
function user_restrictions_cron() {
- $entity_storage = \Drupal::getContainer()->get('entity_type.manager')->getStorage('user_restrictions');
- $user_restrictions = new UserRestrictionsManager($entity_storage);
+ $entity_manager = \Drupal::getContainer()->get('entity_type.manager');
+ $user_restrictions_type_manager = \Drupal::getContainer()->get('user_restrictions.type_manager');
+ $logger = \Drupal::getContainer()->get('logger.factory')->get('user_restrictions');
+ $user_restrictions = new UserRestrictionsManager($entity_manager, $user_restrictions_type_manager, $logger);
$user_restrictions->deleteExpiredRules();
}
@@ -41,8 +42,8 @@ function user_restrictions_help($path, $arg) {
$output .= '