Skip to content

Commit

Permalink
Merge branch 'master' of github.com:JWardee/wp-mail-catcher
Browse files Browse the repository at this point in the history
# Conflicts:
#	readme.md
#	readme.txt
  • Loading branch information
JWardee committed May 29, 2024
2 parents aa1aa49 + dc1b27c commit 9dc1110
Show file tree
Hide file tree
Showing 9 changed files with 197 additions and 34 deletions.
2 changes: 1 addition & 1 deletion WpMailCatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
Domain Path: /languages
Description: Logging your mail will stop you from ever losing your emails again! This fast, lightweight plugin (under 140kb in size!) is also useful for debugging or backing up your messages.
Author: James Ward
Version: 2.1.7
Version: 2.1.8
Author URI: https://jamesward.io
Donate link: https://paypal.me/jamesmward
*/
Expand Down
2 changes: 1 addition & 1 deletion build/grunt/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion build/grunt/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "WpMailCatcher",
"version": "2.1.7",
"version": "2.1.8",
"lang_po_directory": "../../languages",
"build_directory": "./..",
"dist_directory": "../../assets",
Expand Down
2 changes: 1 addition & 1 deletion entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export DB_DATABASE=wordpress
export DB_USERNAME=wp_mail_catcher
export DB_PASSWORD=password
export PHP_VERSION=8.0
export WP_VERSION=6.4.1
export WP_VERSION=6.5.3

CMD=$1

Expand Down
26 changes: 13 additions & 13 deletions languages/WpMailCatcher.pot
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
#, fuzzy
msgid ""
msgstr ""
"Project-Id-Version: WpMailCatcher 2.1.4\n"
"Project-Id-Version: WpMailCatcher 2.1.8\n"
"Report-Msgid-Bugs-To: [email protected]\n"
"POT-Creation-Date: 2023-11-09 20:31+0000\n"
"POT-Creation-Date: 2024-05-29 19:52+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <[email protected]>\n"
Expand Down Expand Up @@ -131,7 +131,7 @@ msgid ""
" to perform the upgrade.</strong>"
msgstr ""

#: ../../src/Views/Log.php:47
#: ../../src/Views/Log.php:50
#, php-format
msgid ""
"You have <strong>over %s</strong> messages stored and <a href=\"%s\">auto-"
Expand All @@ -141,27 +141,27 @@ msgid ""
" auto-delete or delete some logs."
msgstr ""

#: ../../src/Views/Log.php:62
#: ../../src/Views/Log.php:65
msgid "New Message"
msgstr ""

#: ../../src/Views/Log.php:67 ../../src/Views/Log.php:77
#: ../../src/Views/Log.php:70 ../../src/Views/Log.php:80
msgid "Export all messages"
msgstr ""

#: ../../src/Views/Log.php:88
#: ../../src/Views/Log.php:91
msgid "All"
msgstr ""

#: ../../src/Views/Log.php:96
#: ../../src/Views/Log.php:99
msgid "Successful"
msgstr ""

#: ../../src/Views/Log.php:104
#: ../../src/Views/Log.php:107
msgid "Failed"
msgstr ""

#: ../../src/Views/Log.php:118
#: ../../src/Views/Log.php:121
msgid "Search Logs"
msgstr ""

Expand Down Expand Up @@ -290,20 +290,20 @@ msgstr ""
msgid "Yes - delete messages that are over %s old"
msgstr ""

#: ../../src/Views/Settings.php:141
#: ../../src/Views/Settings.php:144
#, php-format
msgid "Will next run in: %s. <a href=\""
msgstr ""

#: ../../src/Views/Settings.php:155
#: ../../src/Views/Settings.php:158
msgid "Database version"
msgstr ""

#: ../../src/Views/Settings.php:164
#: ../../src/Views/Settings.php:170
#, php-format
msgid "%s. <a href=\""
msgstr ""

#: ../../src/Views/Settings.php:178
#: ../../src/Views/Settings.php:184
msgid "Save Changes"
msgstr ""
49 changes: 40 additions & 9 deletions src/Loggers/LogHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,27 @@ trait LogHelper
* Save the mail to the database, override this method if you wish
* to save the data elsewhere or change how it is saved
*
* @param array $args the details of the mail going to be sent
* @param $transformFunc($args) called before inserting the db entry to transform the mail into log format
* @param array $args the details of the mail going to be sent
* @param $transformFunc ($args) called before inserting the db entry to transform the mail into log format
*
* @return array must return an array in the same format
*/
public function saveMail(array $args, $transformFunc): array
{
global $wpdb;

$wpdb->insert($wpdb->prefix . GeneralHelper::$tableName, $transformFunc($args));
$transformedArgs = $transformFunc($args);
$userFilteredArgs = apply_filters(
GeneralHelper::$actionNameSpace . '_before_success_log_save',
// Only allow certain values to be changed via filters/hooks
array_intersect_key($transformedArgs, array_fill_keys(Logs::$whitelistedColumns, null))
);

if ($userFilteredArgs === false) {
return [];
}

$wpdb->insert($wpdb->prefix . GeneralHelper::$tableName, array_merge($transformedArgs, $userFilteredArgs));

Cache::flush();

Expand Down Expand Up @@ -53,18 +64,38 @@ public function saveError(string $error)

global $wpdb;

$log = Logs::getFirst(['post__in' => $this->id]);
$log['status'] = 0;
$log['error'] = $error;
$log['time'] = $log['timestamp'];

$transformedArgs = apply_filters(
GeneralHelper::$actionNameSpace . '_before_error_log_save',
// Only allow certain values to be changed via filters/hooks
array_intersect_key($log, array_fill_keys(Logs::$whitelistedColumns, null))
);

if ($transformedArgs === false) {
// Because of the way wp_mail hook works the log needs to be saved
// before appending any error that happened to it. As a result we need
// to delete the inital entry from the db rather than just `return`
Logs::delete($this->id);
return;
}

if (!$transformedArgs) {
$transformedArgs = $log;
}

$wpdb->update(
$wpdb->prefix . GeneralHelper::$tableName,
[
'status' => 0,
'error' => $error,
],
array_merge($transformedArgs, ['status' => 0]),
['id' => $this->id]
);

Cache::flush();

do_action(GeneralHelper::$actionNameSpace . '_mail_failed', Logs::getFirst(['post__in' => $this->id]));
do_action(GeneralHelper::$actionNameSpace . '_mail_failed', $log);
}

public function saveIsHtml($contentType)
Expand Down Expand Up @@ -94,7 +125,7 @@ public function saveIsHtml($contentType)
* Convert attachment ids or urls into a format to be usable
* by the logs
*
* @param array | string $attachments either array of attachment ids or their urls
* @param array | string $attachments either array of attachment ids or their urls
*
* @return array [id, url] of attachments
*/
Expand Down
5 changes: 5 additions & 0 deletions src/Models/Logs.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@

class Logs
{
// The db columns that can be set when logs are updated via filters/hooks
public static $whitelistedColumns = [
'email_to', 'subject', 'message', 'error', 'time', 'backtrace_segment'
];

// Need to set null because we're using array_intersect_key
public static $whitelistedParams = [
'orderby' => null,
Expand Down
28 changes: 20 additions & 8 deletions testing/tests/TestEmails.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,22 @@ public function setUp(): void
Logs::truncate();
}

public function testMail()
private function isTimeBetwen($time, $compareToTime, $threshold)
{
$to = '[email protected]';
$upperBound = $compareToTime + $threshold;
$lowerBound = $compareToTime - $threshold;
return $time < $upperBound && $time > $lowerBound;
}

// TODO: Tidy method up, make more generic rather than just setting current args
// needed by other tests
private function sendAndAssertMail($to, $additionalHeaders = [], $isHtml = false)
{
// FIXME: Need a better way to mock `time()`
$time = time();
$acceptableTimeThreshold = 5;
$subject = 'subject';
$message = 'message';
$additionalHeaders = [GeneralHelper::$htmlEmailHeader, 'cc: [email protected]'];

$imgAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/img-attachment.png');
$pdfAttachmentId = $this->factory()->attachment->create_upload_object(__DIR__ . '/../assets/pdf-attachment.pdf');
Expand All @@ -31,10 +41,12 @@ public function testMail()
$this->assertEquals($to, $emailLogs[0]['email_to']);
$this->assertEquals($subject, $emailLogs[0]['subject']);
$this->assertEquals($message, $emailLogs[0]['message']);
$this->assertTrue($emailLogs[0]['is_html']);
$this->assertTrue($this->isTimeBetwen($emailLogs[0]['timestamp'], $time, $acceptableTimeThreshold));
$this->assertEquals($isHtml, $emailLogs[0]['is_html']);

$this->assertEquals($additionalHeaders[0], $emailLogs[0]['additional_headers'][0]);
$this->assertEquals($additionalHeaders[1], $emailLogs[0]['additional_headers'][1]);
foreach ($additionalHeaders as $index => $additionalHeader) {
$this->assertEquals($additionalHeader, $emailLogs[0]['additional_headers'][$index]);
}

$this->assertEquals($imgAttachmentId, $emailLogs[0]['attachments'][0]['id']);
$this->assertEquals(wp_get_attachment_url($imgAttachmentId), $emailLogs[0]['attachments'][0]['url']);
Expand All @@ -48,13 +60,13 @@ public function testMail()

public function testCorrectTos()
{
wp_mail('[email protected]', 'subject', 'message');
$this->sendAndAssertMail('[email protected]', [GeneralHelper::$htmlEmailHeader, 'cc: [email protected]'], true);
$this->assertTrue(Logs::getFirst()['status']);
}

public function testIncorrectTos()
{
wp_mail('testtest.com', 'subject', 'message');
$this->sendAndAssertMail('testtest.com');
$this->assertFalse(Logs::getFirst()['status']);
}

Expand Down
115 changes: 115 additions & 0 deletions testing/tests/TestLogFunctions.php
Original file line number Diff line number Diff line change
Expand Up @@ -485,4 +485,119 @@ public function testCanDecodeAsciQuotedEncodedSubjectLine()
preg_replace('/\s+/', '', $expectedOutput)
);
}

public function testCanAlterSuccessfulLogBeforeSavingViaFilter()
{
$beforeTo = '[email protected]';
$beforeSubject = 'Before subject';

$afterTo = '[email protected]';
$afterSubject = 'After subject';
$afterTime = 123;
$afterBacktrace = 'Hello world';
$afterMessage = 'My new message';

$filterName = GeneralHelper::$actionNameSpace . '_before_success_log_save';

$func = function ($log) use ($afterTo, $afterSubject, $afterMessage, $afterTime, $afterBacktrace) {
$log['email_to'] = $afterTo;
$log['subject'] = $afterSubject;
$log['message'] = $afterMessage;
$log['time'] = $afterTime;
$log['backtrace_segment'] = $afterBacktrace;
return $log;
};

add_filter($filterName, $func);

wp_mail($beforeTo, $beforeSubject, 'Hello');

$emailLog = Logs::getFirst();

$this->assertEquals($afterTo, $emailLog['email_to']);
$this->assertEquals($afterSubject, $emailLog['subject']);
$this->assertEquals($afterMessage, $emailLog['message']);
$this->assertEquals($afterTime, $emailLog['timestamp']);
$this->assertEquals($afterBacktrace, $emailLog['backtrace_segment']);

remove_filter($filterName, $func);
}

public function testCanStopSuccessfulLogFromSavingViaFilter()
{
$filterName = GeneralHelper::$actionNameSpace . '_before_success_log_save';

$func = function ($log) {
return false;
};

add_filter($filterName, $func);

wp_mail('[email protected]', 'Subject', 'Hello');

$emailLogs = Logs::get();
$this->assertCount(0, $emailLogs);

remove_filter($filterName, $func);
}

public function testCanAlterErroredLogBeforeSavingViaFilter()
{
// Use invalid email address to trigger an error
$beforeTo = 'beforetest.com';
$beforeSubject = 'Before subject';

$afterTo = '[email protected]';
$afterSubject = 'After subject';
$afterErrorMessage = 'Something went wrong';
$afterMessage = 'My new message';
$afterTime = 123;
$afterBacktrace = 'Hello world';

$filterName = GeneralHelper::$actionNameSpace . '_before_error_log_save';

$func = function ($log) use ($afterTo, $afterSubject, $afterErrorMessage, $afterMessage, $afterTime, $afterBacktrace) {
$log['email_to'] = $afterTo;
$log['subject'] = $afterSubject;
$log['message'] = $afterMessage;
$log['error'] = $afterErrorMessage;
$log['time'] = $afterTime;
$log['backtrace_segment'] = $afterBacktrace;
return $log;
};

add_filter($filterName, $func);

wp_mail($beforeTo, $beforeSubject, 'Hello');

$emailLog = Logs::getFirst();

$this->assertEquals($afterTo, $emailLog['email_to']);
$this->assertEquals($afterSubject, $emailLog['subject']);
$this->assertEquals($afterErrorMessage, $emailLog['error']);
$this->assertEquals($afterMessage, $emailLog['message']);
$this->assertEquals($afterTime, $emailLog['timestamp']);
$this->assertEquals($afterBacktrace, $emailLog['backtrace_segment']);

remove_filter($filterName, $func);
}

public function testCanStopErroredLogFromSavingViaFilter()
{
$filterName = GeneralHelper::$actionNameSpace . '_before_error_log_save';

$func = function ($log) {
return false;
};

add_filter($filterName, $func);

// Use invalid email address to trigger an error
wp_mail('testtest.com', 'Subject', 'Hello');

$emailLogs = Logs::get();
$this->assertCount(0, $emailLogs);

remove_filter($filterName, $func);
}
}

0 comments on commit 9dc1110

Please sign in to comment.