| 1 |
<?php |
| 2 |
|
| 3 |
namespace FluentAuth\App\Http\Controllers; |
| 4 |
|
| 5 |
use FluentAuth\App\Helpers\Arr; |
| 6 |
use FluentAuth\App\Helpers\Helper; |
| 7 |
use FluentAuth\App\Services\SmartCodeParser; |
| 8 |
use FluentAuth\App\Services\SystemEmailService; |
| 9 |
|
| 10 |
class SystemEmailsController |
| 11 |
{ |
| 12 |
public static function getEmails(\WP_REST_Request $request) |
| 13 |
{ |
| 14 |
return [ |
| 15 |
'emailIndexes' => array_values(SystemEmailService::getEmailIndexes()), |
| 16 |
]; |
| 17 |
} |
| 18 |
|
| 19 |
public static function findEmail(\WP_REST_Request $request) |
| 20 |
{ |
| 21 |
$remailId = $request->get_param('email_id'); |
| 22 |
|
| 23 |
if (!$remailId) { |
| 24 |
return new \WP_Error('invalid_email_id', __('Email ID is required', 'fluent-security'), ['status' => 400]); |
| 25 |
} |
| 26 |
|
| 27 |
$emailIndexes = SystemEmailService::getEmailIndexes(); |
| 28 |
|
| 29 |
if (!isset($emailIndexes[$remailId])) { |
| 30 |
return new \WP_Error('invalid_email_id', __('Email ID is invalid', 'fluent-security'), ['status' => 400]); |
| 31 |
} |
| 32 |
|
| 33 |
$emailSettings = SystemEmailService::getGlobalSettings(); |
| 34 |
|
| 35 |
$targetEmail = $emailIndexes[$remailId]; |
| 36 |
|
| 37 |
$contextSmartCodes = Arr::get($targetEmail, 'additional_smartcodes', []); |
| 38 |
|
| 39 |
$userSmartCodes = [ |
| 40 |
'{{user.first_name}}' => __('First Name', 'fluent-security'), |
| 41 |
'{{user.last_name}}' => __('Last Name', 'fluent-security'), |
| 42 |
'{{user.display_name}}' => __('Display Name', 'fluent-security'), |
| 43 |
'{{user.user_email}}' => __('Email', 'fluent-security'), |
| 44 |
'{{user.user_login}}' => __('Username', 'fluent-security'), |
| 45 |
'{{user.roles}}' => __('User Roles', 'fluent-security'), |
| 46 |
]; |
| 47 |
|
| 48 |
if ($contextSmartCodes) { |
| 49 |
$userSmartCodes = array_merge($contextSmartCodes, $userSmartCodes); |
| 50 |
} |
| 51 |
|
| 52 |
$editorCodes = [ |
| 53 |
[ |
| 54 |
'key' => 'user', |
| 55 |
'title' => __('User Data', 'fluent-security'), |
| 56 |
'shortcodes' => apply_filters('fluentcrm_auth/email_smartcodes', $userSmartCodes) |
| 57 |
], |
| 58 |
[ |
| 59 |
'key' => 'site', |
| 60 |
'title' => __('Site Data', 'fluent-security'), |
| 61 |
'shortcodes' => apply_filters('fluentcrm_auth/email_smartcodes', [ |
| 62 |
'{{site.name}}' => __('Site Title', 'fluent-security'), |
| 63 |
'{{site.description}}' => __('Site tagline', 'fluent-security'), |
| 64 |
'{{site.admin_email}}' => __('Admin Email', 'fluent-security'), |
| 65 |
'##site.url##' => __('Site URL', 'fluent-security'), |
| 66 |
'##site.login_url##' => __('Login Url', 'fluent-security'), |
| 67 |
]) |
| 68 |
] |
| 69 |
]; |
| 70 |
|
| 71 |
if (!isset($emailSettings['emails'][$remailId])) { |
| 72 |
return new \WP_Error('invalid_email_id', __('Email ID is invalid', 'fluent-security'), ['status' => 400]); |
| 73 |
} |
| 74 |
|
| 75 |
$defaultEmails = SystemEmailService::getEmailDefaults(); |
| 76 |
|
| 77 |
return [ |
| 78 |
'email' => $targetEmail, |
| 79 |
'settings' => $emailSettings['emails'][$remailId], |
| 80 |
'smartcodes' => $editorCodes, |
| 81 |
'default_content' => Arr::get($defaultEmails, $remailId), |
| 82 |
]; |
| 83 |
} |
| 84 |
|
| 85 |
public static function previewEmail(\WP_REST_Request $request) |
| 86 |
{ |
| 87 |
$remailId = $request->get_param('email_id'); |
| 88 |
|
| 89 |
if (!$remailId) { |
| 90 |
return new \WP_Error('invalid_email_id', __('Email ID is required', 'fluent-security'), ['status' => 400]); |
| 91 |
} |
| 92 |
|
| 93 |
$emailIndexes = SystemEmailService::getEmailIndexes(); |
| 94 |
|
| 95 |
if (!isset($emailIndexes[$remailId])) { |
| 96 |
return new \WP_Error('invalid_email_id', __('Email ID is invalid', 'fluent-security'), ['status' => 400]); |
| 97 |
} |
| 98 |
|
| 99 |
$emailData = (array) $request->get_param('email_data'); |
| 100 |
|
| 101 |
if (empty($emailData['body']) || empty($emailData['body'])) { |
| 102 |
return new \WP_Error('invalid_email_settings', __('Email subject and body are required', 'fluent-security'), ['status' => 400]); |
| 103 |
} |
| 104 |
|
| 105 |
$subject = sanitize_text_field(Arr::get($emailData, 'subject')); |
| 106 |
$emailBody = wp_kses_post(Arr::get($emailData, 'body')); |
| 107 |
|
| 108 |
if (!defined('FLUENTAUTH_PREVIEWING_EMAIL')) { |
| 109 |
define('FLUENTAUTH_PREVIEWING_EMAIL', true); |
| 110 |
} |
| 111 |
|
| 112 |
$wpUser = get_user_by('ID', get_current_user_id()); |
| 113 |
$subject = (new SmartCodeParser())->parse($subject, $wpUser); |
| 114 |
$body = (new SmartCodeParser())->parse($emailBody, $wpUser); |
| 115 |
$body = SystemEmailService::withHtmlTemplate($body, null, $wpUser); |
| 116 |
|
| 117 |
return [ |
| 118 |
'rendered_email' => [ |
| 119 |
'subject' => $subject, |
| 120 |
'body' => $body, |
| 121 |
] |
| 122 |
]; |
| 123 |
} |
| 124 |
|
| 125 |
public static function saveEmailSettings(\WP_REST_Request $request) |
| 126 |
{ |
| 127 |
$emailId = $request->get_param('email_id'); |
| 128 |
|
| 129 |
if (!$emailId) { |
| 130 |
return new \WP_Error('invalid_email_id', __('Email ID is required', 'fluent-security'), ['status' => 400]); |
| 131 |
} |
| 132 |
|
| 133 |
$emailIndexes = SystemEmailService::getEmailIndexes(); |
| 134 |
|
| 135 |
if (!isset($emailIndexes[$emailId])) { |
| 136 |
return new \WP_Error('invalid_email_id', __('Email ID is invalid', 'fluent-security'), ['status' => 400]); |
| 137 |
} |
| 138 |
|
| 139 |
$allEmailSettings = SystemEmailService::getGlobalSettings(); |
| 140 |
|
| 141 |
$settings = (array) $request->get_param('settings'); |
| 142 |
|
| 143 |
if ($settings['status'] == 'active') { |
| 144 |
$allEmailSettings['emails'][$emailId]['status'] = 'active'; |
| 145 |
|
| 146 |
$subject = sanitize_text_field(Arr::get($settings, 'email.subject')); |
| 147 |
$emailBody = wp_kses_post(Arr::get($settings, 'email.body')); |
| 148 |
|
| 149 |
if (!$subject || !$emailBody) { |
| 150 |
return new \WP_Error('invalid_email_settings', __('Email subject and body are required', 'fluent-security'), ['status' => 400]); |
| 151 |
} |
| 152 |
|
| 153 |
$requiredSmartCodes = Arr::get($emailIndexes, $emailId . '.required_smartcodes', []); |
| 154 |
|
| 155 |
if (!self::validateEmailBody($emailBody, $requiredSmartCodes)) { |
| 156 |
return new \WP_Error('invalid_email_settings', __('Email body is not valid. Please check the smartcodes.', 'fluent-security'), [ |
| 157 |
'status' => 400, |
| 158 |
'required_smartcodes' => $requiredSmartCodes |
| 159 |
]); |
| 160 |
} |
| 161 |
|
| 162 |
$allEmailSettings['emails'][$emailId]['email'] = [ |
| 163 |
'subject' => sanitize_text_field(Arr::get($settings, 'email.subject')), |
| 164 |
'body' => $emailBody, |
| 165 |
]; |
| 166 |
} else if ($settings['status'] == 'disabled') { |
| 167 |
$allEmailSettings['emails'][$emailId]['status'] = 'disabled'; |
| 168 |
$allEmailSettings['emails'][$emailId]['email'] = [ |
| 169 |
'subject' => sanitize_text_field(Arr::get($settings, 'email.subject')), |
| 170 |
'body' => wp_kses_post(Arr::get($settings, 'email.body')), |
| 171 |
]; |
| 172 |
} else { |
| 173 |
unset($allEmailSettings['emails'][$emailId]); |
| 174 |
} |
| 175 |
|
| 176 |
update_option('fa_system_email_settings', $allEmailSettings, false); |
| 177 |
|
| 178 |
return [ |
| 179 |
'message' => __('Email settings has been succcesfully updated', 'fluent-security') |
| 180 |
]; |
| 181 |
} |
| 182 |
|
| 183 |
public static function getTemplateSettings(\WP_REST_Request $request) |
| 184 |
{ |
| 185 |
$globalSettings = SystemEmailService::getGlobalSettings(); |
| 186 |
$settings = Arr::get($globalSettings, 'template_settings', []); |
| 187 |
|
| 188 |
$defaultContent = SystemEmailService::getDefaultEmailBody('user_registration_to_user'); |
| 189 |
$user = get_user_by('ID', get_current_user_id()); |
| 190 |
|
| 191 |
if (!defined('FLUENTAUTH_PREVIEWING_EMAIL')) { |
| 192 |
define('FLUENTAUTH_PREVIEWING_EMAIL', true); |
| 193 |
} |
| 194 |
|
| 195 |
$emailFooter = SystemEmailService::getEmailFooter(); |
| 196 |
|
| 197 |
if (!$emailFooter) { |
| 198 |
$emailFooter = 'Email Footer Placeholder'; |
| 199 |
} |
| 200 |
|
| 201 |
$defaultContent = (new SmartCodeParser())->parse($defaultContent, $user); |
| 202 |
$defaultContent = SystemEmailService::withHtmlTemplate($defaultContent, $emailFooter, $user); |
| 203 |
|
| 204 |
return [ |
| 205 |
'settings' => $settings, |
| 206 |
'default_content' => $defaultContent, |
| 207 |
'default_colors' => [ |
| 208 |
'body_bg' => '#f3f4f6', |
| 209 |
'content_bg' => '#ffffff', |
| 210 |
'content_color' => '#374151', |
| 211 |
'footer_content_color' => '#6b7280', |
| 212 |
'highlight_bg' => 'rgb(249, 250, 251)', |
| 213 |
'highlight_color' => '#374151', |
| 214 |
] |
| 215 |
]; |
| 216 |
} |
| 217 |
|
| 218 |
public static function saveTemplateSettings(\WP_REST_Request $request) |
| 219 |
{ |
| 220 |
$newSettings = (array) $request->get_param('settings'); |
| 221 |
|
| 222 |
$globalSettings = SystemEmailService::getGlobalSettings(); |
| 223 |
$settings = Arr::get($globalSettings, 'template_settings', []); |
| 224 |
$newSettings = Arr::only($newSettings, array_keys($settings)); |
| 225 |
$newSettings['footer_text'] = wp_kses_post($newSettings['footer_text']); |
| 226 |
|
| 227 |
// Sanitize color fields |
| 228 |
$colorFields = ['body_bg', 'content_bg', 'content_color', 'footer_content_color', 'highlight_bg', 'highlight_color']; |
| 229 |
foreach ($colorFields as $field) { |
| 230 |
if (!empty($newSettings[$field])) { |
| 231 |
$newSettings[$field] = self::sanitizeColorValue($newSettings[$field]); |
| 232 |
} |
| 233 |
} |
| 234 |
|
| 235 |
// Sanitize remaining text fields |
| 236 |
$textFields = ['font_family', 'template', 'logo', 'email_footer']; |
| 237 |
foreach ($textFields as $field) { |
| 238 |
if (isset($newSettings[$field])) { |
| 239 |
$newSettings[$field] = sanitize_text_field($newSettings[$field]); |
| 240 |
} |
| 241 |
} |
| 242 |
|
| 243 |
// Validate the data |
| 244 |
if (!empty($newSettings['from_email'])) { |
| 245 |
if (!is_email($newSettings['from_email'])) { |
| 246 |
return new \WP_Error('invalid_email', __('From email is not valid', 'fluent-security'), ['status' => 400]); |
| 247 |
} |
| 248 |
} |
| 249 |
|
| 250 |
if (!empty($newSettings['from_name'])) { |
| 251 |
$newSettings['from_name'] = sanitize_text_field($newSettings['from_name']); |
| 252 |
} |
| 253 |
|
| 254 |
if (!empty($newSettings['reply_to_email'])) { |
| 255 |
if (!is_email($newSettings['reply_to_email'])) { |
| 256 |
return new \WP_Error('invalid_email', __('Reply to email is not valid', 'fluent-security'), ['status' => 400]); |
| 257 |
} |
| 258 |
} |
| 259 |
|
| 260 |
if (!empty($newSettings['reply_to_name'])) { |
| 261 |
$newSettings['reply_to_name'] = sanitize_text_field($newSettings['reply_to_name']); |
| 262 |
} |
| 263 |
|
| 264 |
$globalSettings['template_settings'] = $newSettings; |
| 265 |
|
| 266 |
update_option('fa_system_email_settings', $globalSettings, false); |
| 267 |
|
| 268 |
return [ |
| 269 |
'message' => __('Email template settings has been succcesfully updated', 'fluent-security') |
| 270 |
]; |
| 271 |
} |
| 272 |
|
| 273 |
private static function sanitizeColorValue($value) |
| 274 |
{ |
| 275 |
$value = trim($value); |
| 276 |
|
| 277 |
// Allow hex colors: #fff, #ffffff, #ffffffff |
| 278 |
if (preg_match('/^#[0-9a-fA-F]{3,8}$/', $value)) { |
| 279 |
return $value; |
| 280 |
} |
| 281 |
|
| 282 |
// Allow rgb/rgba: rgb(0, 0, 0) or rgba(0, 0, 0, 0.5) |
| 283 |
if (preg_match('/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}\s*(,\s*(0|1|0?\.\d+))?\s*\)$/', $value)) { |
| 284 |
return $value; |
| 285 |
} |
| 286 |
|
| 287 |
return ''; |
| 288 |
} |
| 289 |
|
| 290 |
private static function validateEmailBody($emailBody, $smartCodes = []) |
| 291 |
{ |
| 292 |
if (!$smartCodes) { |
| 293 |
return true; |
| 294 |
} |
| 295 |
|
| 296 |
foreach ($smartCodes as $smartCode) { |
| 297 |
$codes = ['{{' . $smartCode . '}}', '##' . $smartCode . '##']; |
| 298 |
$hasCode = str_contains($emailBody, $codes[0]) || str_contains($emailBody, $codes[1]); |
| 299 |
if (!$hasCode) { |
| 300 |
return false; |
| 301 |
} |
| 302 |
} |
| 303 |
|
| 304 |
return true; |
| 305 |
} |
| 306 |
} |
| 307 |
|