Merge branch 'MDL-75971-404' of https://github.com/lameze/moodle into MOODLE_404_STABLE
This commit is contained in:
@@ -4,7 +4,7 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
As a user
|
||||
I need to be able to accept site policy during sign up
|
||||
|
||||
Scenario: Accept policy on sign up, no site policy
|
||||
Scenario: Accept policy on sign up manage by plugin, no site policy
|
||||
Given the following config values are set as admin:
|
||||
| registerauth | email |
|
||||
| passwordpolicy | 0 |
|
||||
@@ -16,13 +16,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -50,13 +50,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -95,13 +95,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -154,13 +154,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -207,13 +207,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -519,13 +519,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
When I press "Create my new account"
|
||||
Then I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I follow "Log in"
|
||||
When I click on "Create new account" "link"
|
||||
# Confirm that the user can view and accept policies when attempting to create another account.
|
||||
@@ -641,13 +641,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -710,13 +710,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -852,13 +852,13 @@ Feature: User must accept policy managed by this plugin when logging in and sign
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
|
||||
@@ -83,13 +83,13 @@ Feature: Optional policies
|
||||
And I set the following fields to these values:
|
||||
| Username | user3 |
|
||||
| Password | user3 |
|
||||
| Email address | user3@address.invalid |
|
||||
| Email (again) | user3@address.invalid |
|
||||
| Email address | user3@example.com |
|
||||
| Email (again) | user3@example.com |
|
||||
| First name | User3 |
|
||||
| Last name | L3 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user3@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user3@example.com"
|
||||
And I confirm email for "user3"
|
||||
And I should see "Thanks, User3 L3"
|
||||
And I should see "Your registration has been confirmed"
|
||||
|
||||
@@ -15,13 +15,13 @@ Feature: User must accept policy when logging in and signing up
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | student1@example.com |
|
||||
| Email (again) | student1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at student1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -45,14 +45,14 @@ Feature: User must accept policy when logging in and signing up
|
||||
And I set the following fields to these values:
|
||||
| Username | user1 |
|
||||
| Password | user1 |
|
||||
| Email address | user1@address.invalid |
|
||||
| Email (again) | user1@address.invalid |
|
||||
| Email address | user1@example.com |
|
||||
| Email (again) | user1@example.com |
|
||||
| First name | User1 |
|
||||
| Last name | L1 |
|
||||
| I understand and agree | 1 |
|
||||
And I press "Create my new account"
|
||||
And I should see "Confirm your account"
|
||||
And I should see "An email should have been sent to your address at user1@address.invalid"
|
||||
And I should see "An email should have been sent to your address at user1@example.com"
|
||||
And I confirm email for "user1"
|
||||
And I should see "Thanks, User1 L1"
|
||||
And I should see "Your registration has been confirmed"
|
||||
@@ -67,8 +67,8 @@ Feature: User must accept policy when logging in and signing up
|
||||
Scenario Outline: Email validation during email registration
|
||||
Given the following config values are set as admin:
|
||||
| allowaccountssameemail | <allowsameemail> |
|
||||
| registerauth | email |
|
||||
| passwordpolicy | 0 |
|
||||
| registerauth | email |
|
||||
| passwordpolicy | 0 |
|
||||
And the following "users" exist:
|
||||
| username | firstname | lastname | email |
|
||||
| s1 | John | Doe | s1@example.com |
|
||||
|
||||
@@ -1694,6 +1694,32 @@ EOF;
|
||||
return !empty($matches);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user object from an identifier.
|
||||
*
|
||||
* The user username and email fields are checked.
|
||||
*
|
||||
* @param string $identifier The user's username or email.
|
||||
* @return stdClass|null The user id or null if not found.
|
||||
*/
|
||||
protected function get_user_by_identifier(string $identifier): ?stdClass {
|
||||
global $DB;
|
||||
|
||||
$sql = <<<EOF
|
||||
SELECT *
|
||||
FROM {user}
|
||||
WHERE username = :username
|
||||
OR email = :email
|
||||
EOF;
|
||||
|
||||
$result = $DB->get_record_sql($sql, [
|
||||
'username' => $identifier,
|
||||
'email' => $identifier,
|
||||
]);
|
||||
|
||||
return $result ?: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user id from an identifier.
|
||||
*
|
||||
|
||||
@@ -233,6 +233,12 @@ function behat_clean_init_config() {
|
||||
unset($CFG->{$key});
|
||||
}
|
||||
}
|
||||
|
||||
// Allow email catcher settings.
|
||||
if (defined('TEST_EMAILCATCHER_MAIL_SERVER')) {
|
||||
$CFG->noemailever = false;
|
||||
$CFG->smtphosts = TEST_EMAILCATCHER_MAIL_SERVER;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\test;
|
||||
|
||||
/**
|
||||
* Generic email catcher interface.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @copyright Simey Lameze <[email protected]>
|
||||
*/
|
||||
interface email_catcher {
|
||||
|
||||
/**
|
||||
* Get a list of messages from the mailpit server.
|
||||
*
|
||||
* @param bool $showdetails Optional. Whether to include detailed information in the messages. Default is false.
|
||||
* @return iterable<message>
|
||||
*/
|
||||
public function get_messages(bool $showdetails = false): iterable;
|
||||
|
||||
/**
|
||||
* Delete all messages from the mailpit server.
|
||||
*/
|
||||
public function delete_all();
|
||||
|
||||
/**
|
||||
* Search for a message in the mailpit server.
|
||||
*
|
||||
* @param string $query The search query.
|
||||
* @return iterable
|
||||
*/
|
||||
public function search(string $query): iterable;
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* Mailpit mail handling implementation.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @copyright Simey Lameze <[email protected]>
|
||||
*/
|
||||
namespace core\test;
|
||||
|
||||
use core\http_client;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Mailpit email handling class.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mailpit_email_catcher implements email_catcher {
|
||||
|
||||
/** @var http_client The http client object. */
|
||||
protected http_client $httpclient;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $baseuri The base uri for the mailpit server.
|
||||
*/
|
||||
public function __construct(string $baseuri) {
|
||||
$this->httpclient = new http_client(['base_uri' => $baseuri]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the mailpit server after a test.
|
||||
*/
|
||||
public function reset_after_test(): void {
|
||||
$this->httpclient->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all messages from the mailpit server.
|
||||
*/
|
||||
public function delete_all() {
|
||||
$this->httpclient->delete('api/v1/messages');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a list of messages from the mailpit server.
|
||||
*
|
||||
* @param bool $showdetails Optional. Whether to include detailed information in the messages. Default is false.
|
||||
* @return iterable
|
||||
*/
|
||||
public function get_messages(bool $showdetails = false): iterable {
|
||||
$uri = 'api/v1/messages';
|
||||
$options = [
|
||||
'query' => [
|
||||
'start' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
do {
|
||||
$response = $this->httpclient->get(
|
||||
uri: $uri,
|
||||
options: $options,
|
||||
);
|
||||
|
||||
$data = json_decode($response->getBody());
|
||||
foreach ($data->messages as $messagedata) {
|
||||
yield mailpit_message::create_from_api_response($this, $messagedata, $showdetails);
|
||||
}
|
||||
|
||||
$options['query']['start'] = $data->start + $data->count;
|
||||
} while ($data->total > ($options['query']['start']));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message summary for a specific message.
|
||||
*
|
||||
* @param string $id The message id.
|
||||
* @return stdClass
|
||||
*/
|
||||
public function get_message_data(string $id): stdClass {
|
||||
$response = $this->httpclient->get("api/v1/message/{$id}");
|
||||
|
||||
return json_decode($response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for a message in the mailpit server.
|
||||
*
|
||||
* @param string $query The search query.
|
||||
* @return mixed
|
||||
*/
|
||||
public function search(string $query): iterable {
|
||||
$uri = "api/v1/search?query={$query}";
|
||||
|
||||
$response = $this->httpclient->get($uri);
|
||||
$data = json_decode($response->getBody());
|
||||
|
||||
foreach ($data->messages as $messagedata) {
|
||||
yield mailpit_message::create_from_api_response($this, $messagedata);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,227 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\test;
|
||||
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* Mailpit message handling implementation.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class mailpit_message implements message {
|
||||
|
||||
/** @var bool Whether the message has been loaded. */
|
||||
protected bool $messageloaded = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param email_catcher $client The email catcher client.
|
||||
* @param string $id The message ID.
|
||||
* @param stdClass $sender The sender.
|
||||
* @param string $subject The subject.
|
||||
* @param array $recipients The recipients.
|
||||
* @param array $cc The cc recipients.
|
||||
* @param array $bcc The bcc recipients.
|
||||
* @param int $attachmentcount The number of attachments.
|
||||
* @param string|null $text The text body.
|
||||
* @param string|null $html The HTML body.
|
||||
* @param array $attachments The attachments.
|
||||
* @param array $inline The inline attachments.
|
||||
*/
|
||||
protected function __construct(
|
||||
/** @var email_catcher $client The email catcher client used for message operations.*/
|
||||
private readonly email_catcher $client,
|
||||
/** @var string $id The unique identifier for the message. */
|
||||
private readonly string $id,
|
||||
/** @var stdClass $sender The sender of the message, represented as an object with email details. */
|
||||
private readonly stdClass $sender,
|
||||
/** @var string $subject The subject line of the message. */
|
||||
private readonly string $subject,
|
||||
/** @var array $recipients List of primary recipients for the message. */
|
||||
private readonly array $recipients,
|
||||
/** @var array $cc List of carbon copy recipients (optional, defaults to an empty array). */
|
||||
private readonly array $cc = [],
|
||||
/** @var array $bcc List of blind carbon copy recipients (optional, defaults to an empty array). */
|
||||
private readonly array $bcc = [],
|
||||
/** @var int $attachmentcount The number of attachments in the message (default is 0). */
|
||||
private readonly int $attachmentcount = 0,
|
||||
/** @var ?string $text The plain text body of the message (nullable, might be loaded later). */
|
||||
private ?string $text = null,
|
||||
/** @var ?string $html The HTML body of the message (nullable, might be loaded later). */
|
||||
private ?string $html = null,
|
||||
/** @var array $attachments An array of attachment details (defaults to empty array). */
|
||||
private array $attachments = [],
|
||||
/** @var array $inline An array of inline elements like images or styles (defaults to empty array). */
|
||||
private array $inline = [],
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the message content.
|
||||
*/
|
||||
protected function load_message_content(): void {
|
||||
if (!$this->messageloaded) {
|
||||
$message = $this->client->get_message_data($this->id);
|
||||
$this->text = $message->Text;
|
||||
$this->html = $message->HTML;
|
||||
$this->attachments = $message->Attachments;
|
||||
$this->inline = $message->Inline;
|
||||
$this->messageloaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a message from an api response.
|
||||
*
|
||||
* @param email_catcher $client The email catcher client.
|
||||
* @param stdClass $message The api response.
|
||||
* @param bool $showdetails Optional. Whether to include detailed information in the messages. Default is false.
|
||||
* @return mailpit_message The created mailpit message instance.
|
||||
*/
|
||||
public static function create_from_api_response(
|
||||
email_catcher $client,
|
||||
stdClass $message,
|
||||
bool $showdetails = false,
|
||||
): self {
|
||||
$message = new self(
|
||||
client: $client,
|
||||
id: $message->ID,
|
||||
sender: $message->From,
|
||||
subject: $message->Subject,
|
||||
recipients: $message->To,
|
||||
cc: $message->Cc,
|
||||
attachmentcount: $message->Attachments,
|
||||
);
|
||||
|
||||
if ($showdetails) {
|
||||
$message->load_message_content();
|
||||
}
|
||||
|
||||
return $message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text representation of the body, if one was provided.
|
||||
*
|
||||
* @return null|string The text body.
|
||||
*/
|
||||
public function get_body_text(): ?string {
|
||||
return $this->text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML representation of the body, if one was provided.
|
||||
*
|
||||
* @return null|string The HTML body.
|
||||
*/
|
||||
public function get_body_html(): ?string {
|
||||
return $this->html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message ID.
|
||||
*
|
||||
* @return string The ID.
|
||||
*/
|
||||
public function get_id(): string {
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message recipients.
|
||||
*
|
||||
* @return iterable The recipients.
|
||||
*/
|
||||
public function get_recipients(): iterable {
|
||||
foreach ($this->recipients as $user) {
|
||||
yield mailpit_message_user::from_recipient($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first recipient of the message.
|
||||
*
|
||||
* @return string The email address of the first recipient.
|
||||
*/
|
||||
public function get_first_recipient(): string {
|
||||
$recipients = $this->get_recipients();
|
||||
foreach ($recipients as $recipient) {
|
||||
return $recipient->get_address();
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the message has the specified recipient.
|
||||
*
|
||||
* @param string $email The email address.
|
||||
* @return bool Whether the message has the recipient.
|
||||
*/
|
||||
public function has_recipient(string $email): bool {
|
||||
foreach ($this->get_recipients() as $recipient) {
|
||||
if ($recipient->get_address() === $email) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message cc recipients.
|
||||
*
|
||||
* @return iterable The cc recipients.
|
||||
*/
|
||||
public function get_cc(): iterable {
|
||||
foreach ($this->cc as $user) {
|
||||
yield mailpit_message_user::from_recipient($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message bcc recipients.
|
||||
*
|
||||
* @return iterable The bcc recipients.
|
||||
*/
|
||||
public function get_bcc(): iterable {
|
||||
foreach ($this->bcc as $user) {
|
||||
yield mailpit_message_user::from_recipient($user);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message subject.
|
||||
*
|
||||
* @return string The subject.
|
||||
*/
|
||||
public function get_subject(): string {
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message sender.
|
||||
*
|
||||
* @return message_user The sender.
|
||||
*/
|
||||
public function get_sender(): message_user {
|
||||
return mailpit_message_user::from_sender($this->sender);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\test;
|
||||
|
||||
/**
|
||||
* Message user interface for Mailpit.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
*/
|
||||
class mailpit_message_user implements message_user {
|
||||
|
||||
/**
|
||||
* Create a new message user object from a sender.
|
||||
*
|
||||
* @param \stdClass $user The user object.
|
||||
* @return self
|
||||
*/
|
||||
public static function from_sender(
|
||||
\stdClass $user,
|
||||
): self {
|
||||
return new self(
|
||||
name: $user->Name,
|
||||
address: $user->Address,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new message user object from a recipient.
|
||||
*
|
||||
* @param \stdClass $user The user object.
|
||||
* @return self
|
||||
*/
|
||||
public static function from_recipient(
|
||||
\stdClass $user,
|
||||
): self {
|
||||
return new self(
|
||||
name: $user->Name,
|
||||
address: $user->Address,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the user.
|
||||
* @param string $address The email address of the user.
|
||||
*/
|
||||
protected function __construct(
|
||||
/** @var string The name of the user. */
|
||||
protected string $name,
|
||||
/** @var string The email address of the user. */
|
||||
protected string $address
|
||||
) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the display name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name(): string {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_address(): string {
|
||||
return $this->address;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\test;
|
||||
|
||||
/**
|
||||
* Generic message interface.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @copyright Simey Lameze <[email protected]>
|
||||
*/
|
||||
interface message {
|
||||
|
||||
/**
|
||||
* Get the message subject.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_subject(): string;
|
||||
|
||||
/**
|
||||
* Get the text representation of the body, if one was provided.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_body_text(): ?string;
|
||||
|
||||
/**
|
||||
* Get the HTML representation of the body, if one was provided.
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
public function get_body_html(): ?string;
|
||||
|
||||
/**
|
||||
* Get the message sender.
|
||||
*
|
||||
* @return message_user
|
||||
*/
|
||||
public function get_sender(): message_user;
|
||||
|
||||
/**
|
||||
* Get the message recipients.
|
||||
*
|
||||
* @return iterable<message_user>
|
||||
*/
|
||||
public function get_recipients(): iterable;
|
||||
|
||||
/**
|
||||
* Whether the message has the specified recipient.
|
||||
*
|
||||
* @param string $email The email address.
|
||||
* @return bool
|
||||
*/
|
||||
public function has_recipient(string $email): bool;
|
||||
|
||||
/**
|
||||
* Get the message cc recipients.
|
||||
*
|
||||
* @return iterable<message_user>
|
||||
*/
|
||||
public function get_cc(): iterable;
|
||||
|
||||
/**
|
||||
* Get the message cc recipients.
|
||||
*
|
||||
* @return iterable<message_user>
|
||||
*/
|
||||
public function get_bcc(): iterable;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
namespace core\test;
|
||||
|
||||
/**
|
||||
* Generic message user interface.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
* @copyright Andrew Lyons <[email protected]>
|
||||
*/
|
||||
interface message_user {
|
||||
/**
|
||||
* Get the display name of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_name(): string;
|
||||
|
||||
/**
|
||||
* Get the email address of the user.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_address(): string;
|
||||
}
|
||||
+5
-3
@@ -5595,14 +5595,16 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '',
|
||||
return false;
|
||||
}
|
||||
|
||||
if (defined('BEHAT_SITE_RUNNING')) {
|
||||
// Fake email sending in behat.
|
||||
if (defined('BEHAT_SITE_RUNNING') && !defined('TEST_EMAILCATCHER_MAIL_SERVER') &&
|
||||
!defined('TEST_EMAILCATCHER_API_SERVER')) {
|
||||
|
||||
// Behat tests are running and we are not using email catcher so fake email sending.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!empty($CFG->noemailever)) {
|
||||
// Hidden setting for development sites, set in config.php if needed.
|
||||
debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL);
|
||||
debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_DEVELOPER);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
// This file is part of Moodle - http://moodle.org/
|
||||
//
|
||||
// Moodle is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// Moodle is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use core\test\message;
|
||||
use Behat\Gherkin\Node\TableNode;
|
||||
use Behat\Mink\Exception\ExpectationException;
|
||||
use Moodle\BehatExtension\Exception\SkippedException;
|
||||
|
||||
require_once(__DIR__ . '/../../behat/behat_base.php');
|
||||
|
||||
/**
|
||||
* Steps definitions to assist with email testing.
|
||||
*
|
||||
* @package core
|
||||
* @category test
|
||||
* @copyright Simey Lameze <[email protected]>
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class behat_email extends behat_base {
|
||||
|
||||
/**
|
||||
* Check if email catcher is configured.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_email_catcher_configured(): bool {
|
||||
return defined('TEST_EMAILCATCHER_MAIL_SERVER') && defined('TEST_EMAILCATCHER_API_SERVER');
|
||||
}
|
||||
|
||||
/**
|
||||
* Behat step to check if email catcher is configured.
|
||||
*
|
||||
* @Given /^an email catcher server is configured$/
|
||||
*/
|
||||
public function email_catcher_is_configured(): void {
|
||||
if (!self::is_email_catcher_configured()) {
|
||||
throw new SkippedException(
|
||||
'The TEST_EMAILCATCHER_MAIL_SERVER and TEST_EMAILCATCHER_API_SERVER constants must be ' .
|
||||
'defined in config.php to use the mailcatcher steps.'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the email catcher object or thrown a SkippedException if TEST_MAILPIT_SERVER is not defined.
|
||||
*
|
||||
* @return \core\test\email_catcher|null
|
||||
*/
|
||||
private function get_catcher(): ?\core\test\email_catcher {
|
||||
if (self::is_email_catcher_configured()) {
|
||||
return new \core\test\mailpit_email_catcher(TEST_EMAILCATCHER_API_SERVER);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the email inbox after each scenario.
|
||||
*
|
||||
* @AfterScenario @behat_email
|
||||
*/
|
||||
public function reset_after_test(): void {
|
||||
$this->get_catcher()?->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the e-mail address of a user from the step input.
|
||||
*
|
||||
* This could be an e-mail address, or a username.
|
||||
*
|
||||
* @param string $input The input from the step.
|
||||
* @return string
|
||||
*/
|
||||
private function get_email_address_from_input(string $input): string {
|
||||
if (strpos($input, '@') !== false) {
|
||||
return $input;
|
||||
}
|
||||
|
||||
$user = $this->get_user_by_identifier($input);
|
||||
if (!$user) {
|
||||
throw new ExpectationException("No user found with identifier {$input}", $this->getSession()->getDriver());
|
||||
}
|
||||
|
||||
return $user->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get any message matching the supplied user and subject.
|
||||
*
|
||||
* @param string $user The user to check for.
|
||||
* @param string $subject The subject to check for.
|
||||
* @return iterable<message>
|
||||
*/
|
||||
private function get_messages_matching_address_and_subject(
|
||||
string $user,
|
||||
string $subject,
|
||||
): iterable {
|
||||
$address = $this->get_email_address_from_input($user);
|
||||
return new \CallbackFilterIterator(
|
||||
iterator: $this->get_catcher()->get_messages(showdetails: true),
|
||||
callback: function (message $message) use ($address, $subject): bool {
|
||||
if (!$message->has_recipient($address)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (strpos($message->get_subject(), $subject) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the content of an email sent to a specific user and subject.
|
||||
*
|
||||
* @Given the email to :user with subject containing :subject should contain :content
|
||||
*
|
||||
* @param string $user The user to check for.
|
||||
* @param string $subject The subject to check for.
|
||||
* @param string $content The content to check for.
|
||||
*/
|
||||
public function verify_email_content(string $user, string $subject, string $content): void {
|
||||
$messages = $this->get_messages_matching_address_and_subject($user, $subject);
|
||||
|
||||
$count = 0;
|
||||
foreach ($messages as $message) {
|
||||
$count++;
|
||||
$this->validate_data('content', $message, $content);
|
||||
}
|
||||
|
||||
if ($count === 0) {
|
||||
throw new ExpectationException(
|
||||
"No messages found with subject containing {$subject}",
|
||||
$this->getSession()->getDriver(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Behat test to verify the number of emails for a user.
|
||||
*
|
||||
* @Then user :address should have :count emails
|
||||
*
|
||||
* @param string $address The user to check for.
|
||||
* @param int $expected The number of emails to check for.
|
||||
*/
|
||||
public function verify_email_count(string $address, int $expected): void {
|
||||
$address = $this->get_email_address_from_input($address);
|
||||
$messages = new \CallbackFilterIterator(
|
||||
iterator: $this->get_catcher()->get_messages(),
|
||||
callback: fn($message) => $message->has_recipient($address),
|
||||
);
|
||||
|
||||
$count = iterator_count($messages);
|
||||
if ($count !== $expected) {
|
||||
throw new ExpectationException(
|
||||
sprintf(
|
||||
'Expected %d messages, but found %d',
|
||||
$expected,
|
||||
$count,
|
||||
),
|
||||
$this->getSession(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom Behat test to empty the email inbox.
|
||||
*
|
||||
* @When I empty the email inbox
|
||||
*/
|
||||
public function empty_email_inbox() {
|
||||
$this->get_catcher()->delete_all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Behat step to send emails.
|
||||
*
|
||||
* @Given the following emails have been sent:
|
||||
*
|
||||
* @param TableNode $table The table of emails to send.
|
||||
*/
|
||||
public function the_following_emails_have_been_sent(TableNode $table): void {
|
||||
if (!$rows = $table->getRows()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Allowed fields.
|
||||
$allowedfields = ['to', 'subject', 'message'];
|
||||
|
||||
// Create a map of header to index.
|
||||
$headers = array_flip($rows[0]);
|
||||
// Remove header row.
|
||||
unset($rows[0]);
|
||||
|
||||
// Validate supplied headers.
|
||||
foreach ($headers as $header => $index) {
|
||||
if (!in_array($header, $allowedfields)) {
|
||||
throw new ExpectationException("Invalid header {$header} found in table", $this->getSession()->getDriver());
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($rows as $row) {
|
||||
// Check if the required headers are set in the $headers map.
|
||||
$to = isset($headers['to']) ? $row[$headers['to']] : '[email protected]';
|
||||
$subject = isset($headers['subject']) ? $row[$headers['subject']] : 'Default test subject';
|
||||
$message = isset($headers['message']) ? $row[$headers['message']] : 'Default test message';
|
||||
|
||||
// Use no-reply user as dummy user to send emails from.
|
||||
$noreplyuser = \core_user::get_user(\core_user::NOREPLY_USER);
|
||||
|
||||
// Create a dummy user to send emails to.
|
||||
$emailuserto = new stdClass();
|
||||
$emailuserto->id = -99;
|
||||
$emailuserto->email = $to;
|
||||
$emailuserto->firstname = 'Test';
|
||||
$emailuserto->lastname = 'User';
|
||||
|
||||
// Send test email.
|
||||
email_to_user($emailuserto, $noreplyuser, $subject, $message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the emails expected and actual values.
|
||||
*
|
||||
* @param string $field The field to validate.
|
||||
* @param message $message The expected value.
|
||||
* @param string $expected The actual value.
|
||||
*/
|
||||
private function validate_data(
|
||||
string $field,
|
||||
message $message,
|
||||
string $expected,
|
||||
): void {
|
||||
switch ($field) {
|
||||
case 'user':
|
||||
$actual = $message->get_recipients();
|
||||
foreach ($actual as $recipient) {
|
||||
if ($recipient->get_address() === $expected) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw new ExpectationException(
|
||||
sprintf(
|
||||
'Expected %s %s, but found %s',
|
||||
$expected,
|
||||
$field,
|
||||
$actual,
|
||||
),
|
||||
$this->getSession(),
|
||||
);
|
||||
case 'subject':
|
||||
$actual = $message->get_subject();
|
||||
if (str_contains($expected, $actual)) {
|
||||
return;
|
||||
}
|
||||
throw new ExpectationException(
|
||||
sprintf(
|
||||
'Expected %s %s, but found %s',
|
||||
$expected,
|
||||
$field,
|
||||
$actual,
|
||||
),
|
||||
$this->getSession(),
|
||||
);
|
||||
case 'content':
|
||||
if (str_contains($expected, $message->get_body_text())) {
|
||||
return;
|
||||
}
|
||||
if (str_contains($expected, $message->get_body_html())) {
|
||||
return;
|
||||
}
|
||||
throw new ExpectationException(
|
||||
sprintf(
|
||||
'Expected %s to contain %s, but it does not. Actual text was:\n%s\nActual HTML content was:\n%s\n',
|
||||
$field,
|
||||
$expected,
|
||||
$message->get_body_text(),
|
||||
$message->get_body_html(),
|
||||
),
|
||||
$this->getSession(),
|
||||
);
|
||||
default:
|
||||
throw new ExpectationException(
|
||||
sprintf(
|
||||
'Unknown field to validate: %s',
|
||||
$field,
|
||||
),
|
||||
$this->getSession(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
@behat_test @behat_email
|
||||
Feature: Testing Email Functionality
|
||||
|
||||
Background:
|
||||
Given an email catcher server is configured
|
||||
|
||||
Scenario: Verifying email content to user
|
||||
When the following emails have been sent:
|
||||
| to | subject | message |
|
||||
| student1@example.com | A testing subject | This is a test message |
|
||||
Then the email to "student1@example.com" with subject containing "A testing subject" should contain "This is a test message"
|
||||
|
||||
Scenario: Test emptying the email inbox
|
||||
When the following emails have been sent:
|
||||
| to | subject |
|
||||
| student1@example.com | Apple |
|
||||
| student1@example.com | Banana |
|
||||
| student1@example.com | Chocolate |
|
||||
Then user "student1@example.com" should have 3 emails
|
||||
And I empty the email inbox
|
||||
And user "student1@example.com" should have 0 emails
|
||||
@@ -1,6 +1,17 @@
|
||||
This files describes API changes in core libraries and APIs,
|
||||
information provided here is intended especially for developers.
|
||||
|
||||
=== 4.4.8 ===
|
||||
|
||||
* Behat now supports email content verification using Mailpit.
|
||||
You can check the contents of an email using the step `Then the email to "[email protected]" with subject containing "subject" should contain "content".`
|
||||
To use this feature:
|
||||
1. Ensure that Mailpit is running
|
||||
2. Define the following constants in your `config.php`:
|
||||
- `TEST_EMAILCATCHER_MAIL_SERVER` - The Mailpit server address (e.g. `0.0.0.0:1025`)
|
||||
- `TEST_EMAILCATCHER_API_SERVER` - The Mailpit API server (qe.g. `http://localhost:8025`)
|
||||
3. Ensure that the email catcher is set up using the step `Given an email catcher server is configured`.
|
||||
|
||||
=== 4.4.6 ===
|
||||
|
||||
* A new core\ip_utils::normalize_internet_address() method is created to
|
||||
|
||||
Reference in New Issue
Block a user