mirror of
https://github.com/appwrite/appwrite
synced 2026-05-15 04:59:01 +00:00
Add failure email
This commit is contained in:
parent
fdf5367e39
commit
e222221ec9
2 changed files with 97 additions and 35 deletions
|
|
@ -57,14 +57,21 @@
|
|||
"emails.recovery.thanks": "Thanks,",
|
||||
"emails.recovery.buttonText": "Reset password",
|
||||
"emails.recovery.signature": "{{project}} team",
|
||||
"emails.csvExport.subject": "Your CSV export is ready",
|
||||
"emails.csvExport.preview": "Your data export has been completed successfully.",
|
||||
"emails.csvExport.hello": "Hello {{user}},",
|
||||
"emails.csvExport.body": "Your CSV export is ready for download. Click the link below to download your data export.",
|
||||
"emails.csvExport.footer": "This download link will expire in 1 hour.",
|
||||
"emails.csvExport.thanks": "Thanks,",
|
||||
"emails.csvExport.buttonText": "Download CSV",
|
||||
"emails.csvExport.signature": "{{project}} team",
|
||||
"emails.csvExport.success.subject": "Your CSV export is ready",
|
||||
"emails.csvExport.success.preview": "Your data export has been completed successfully.",
|
||||
"emails.csvExport.success.hello": "Hello {{user}},",
|
||||
"emails.csvExport.success.body": "Your CSV export is ready for download. Click the link below to download your data export.",
|
||||
"emails.csvExport.success.footer": "This download link will expire in 1 hour.",
|
||||
"emails.csvExport.success.thanks": "Thanks,",
|
||||
"emails.csvExport.success.buttonText": "Download CSV",
|
||||
"emails.csvExport.success.signature": "{{project}} team",
|
||||
"emails.csvExport.failure.subject": "Your CSV export failed - file too large",
|
||||
"emails.csvExport.failure.preview": "Your data export failed because the file size exceeds your plan limit.",
|
||||
"emails.csvExport.failure.hello": "Hello {{user}},",
|
||||
"emails.csvExport.failure.body": "Your CSV export could not be completed because the export file size ({{size}}MB) exceeds your plan limit. Please consider upgrading your plan or exporting a smaller dataset.",
|
||||
"emails.csvExport.failure.footer": "If you have any questions, please contact our support team.",
|
||||
"emails.csvExport.failure.thanks": "Thanks,",
|
||||
"emails.csvExport.failure.signature": "{{project}} team",
|
||||
"emails.invitation.subject": "Invitation to {{team}} Team at {{project}}",
|
||||
"emails.invitation.preview": "{{owner}} invited you to join {{team}} at {{project}}",
|
||||
"emails.invitation.hello": "Hello {{user}},",
|
||||
|
|
|
|||
|
|
@ -5,8 +5,8 @@ namespace Appwrite\Platform\Workers;
|
|||
use Ahc\Jwt\JWT;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Realtime;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Template\Template;
|
||||
use Exception;
|
||||
use Utopia\CLI\Console;
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Database;
|
||||
|
|
@ -458,16 +458,27 @@ class Migrations extends Action
|
|||
$fileId = ID::unique();
|
||||
|
||||
$sizeMB = \round($size / (1000 * 1000), 2);
|
||||
if ($sizeMB > $plan['fileSize'] ?? PHP_INT_MAX) {
|
||||
if ($sizeMB > $this->plan['fileSize'] ?? PHP_INT_MAX) {
|
||||
try {
|
||||
$this->deviceForFiles->delete($path);
|
||||
} finally {
|
||||
$message = "Export file size {$sizeMB}MB exceeds your plan limit.";
|
||||
|
||||
$this->dbForProject->updateDocument('migrations', $migration->getId(), $migration->setAttribute(
|
||||
'errors',
|
||||
$message,
|
||||
Document::SET_TYPE_APPEND,
|
||||
));
|
||||
|
||||
$this->sendCSVEmail(
|
||||
success: false,
|
||||
project: $project,
|
||||
userInternalId: $userInternalId,
|
||||
options: $options,
|
||||
queueForMails: $queueForMails,
|
||||
sizeMB: $sizeMB
|
||||
);
|
||||
|
||||
throw new \Exception($message);
|
||||
}
|
||||
}
|
||||
|
|
@ -497,7 +508,52 @@ class Migrations extends Action
|
|||
|
||||
Console::info("Created file document in bucket: $fileId");
|
||||
|
||||
// No notification required, skip email sending
|
||||
// Generate JWT valid for 1 hour
|
||||
$maxAge = 60 * 60;
|
||||
$encoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $maxAge, 0);
|
||||
$jwt = $encoder->encode([
|
||||
'bucketId' => $bucketId,
|
||||
'fileId' => $fileId,
|
||||
'projectId' => $project->getId(),
|
||||
]);
|
||||
|
||||
// Generate download URL with JWT
|
||||
$endpoint = System::getEnv('_APP_DOMAIN', '');
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled' ? 'https' : 'http';
|
||||
$downloadUrl = "{$protocol}://{$endpoint}/v1/storage/buckets/{$bucketId}/files/{$fileId}/push?project={$project->getId()}&jwt={$jwt}";
|
||||
|
||||
$this->sendCSVEmail(
|
||||
success: true,
|
||||
project: $project,
|
||||
userInternalId: $userInternalId,
|
||||
options: $options,
|
||||
queueForMails: $queueForMails,
|
||||
downloadUrl: $downloadUrl
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send CSV export notification email
|
||||
*
|
||||
* @param bool $success Whether the export was successful
|
||||
* @param Document $project
|
||||
* @param string $userInternalId Internal ID of the user
|
||||
* @param array $options Migration options
|
||||
* @param Mail $queueForMails
|
||||
* @param string $downloadUrl Download URL for successful exports
|
||||
* @param float $sizeMB File size in MB for failed exports
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function sendCSVEmail(
|
||||
bool $success,
|
||||
Document $project,
|
||||
string $userInternalId,
|
||||
array $options,
|
||||
Mail $queueForMails,
|
||||
string $downloadUrl = '',
|
||||
float $sizeMB = 0.0
|
||||
): void {
|
||||
if (!($options['notify'] ?? false)) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -514,29 +570,19 @@ class Migrations extends Action
|
|||
$locale = new Locale(System::getEnv('_APP_LOCALE', 'en'));
|
||||
$locale->setFallback(System::getEnv('_APP_LOCALE', 'en'));
|
||||
|
||||
// Generate JWT valid for 1 hour
|
||||
$maxAge = 60 * 60;
|
||||
$encoder = new JWT(System::getEnv('_APP_OPENSSL_KEY_V1'), 'HS256', $maxAge, 0);
|
||||
$jwt = $encoder->encode([
|
||||
'bucketId' => $bucketId,
|
||||
'fileId' => $fileId,
|
||||
'projectId' => $project->getId(),
|
||||
]);
|
||||
|
||||
// Generate download URL with JWT
|
||||
$endpoint = System::getEnv('_APP_DOMAIN', '');
|
||||
$protocol = System::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled' ? 'https' : 'http';
|
||||
$downloadUrl = "{$protocol}://{$endpoint}/v1/storage/buckets/{$bucketId}/files/{$fileId}/push?project={$project->getId()}&jwt={$jwt}";
|
||||
$emailType = $success
|
||||
? 'success'
|
||||
: 'failure';
|
||||
|
||||
// Get localized email content
|
||||
$subject = $locale->getText('emails.csvExport.subject');
|
||||
$preview = $locale->getText('emails.csvExport.preview');
|
||||
$hello = $locale->getText('emails.csvExport.hello');
|
||||
$body = $locale->getText('emails.csvExport.body');
|
||||
$footer = $locale->getText('emails.csvExport.footer');
|
||||
$thanks = $locale->getText('emails.csvExport.thanks');
|
||||
$buttonText = $locale->getText('emails.csvExport.buttonText');
|
||||
$signature = $locale->getText('emails.csvExport.signature');
|
||||
$subject = $locale->getText("emails.csvExport.{$emailType}.subject");
|
||||
$preview = $locale->getText("emails.csvExport.{$emailType}.preview");
|
||||
$hello = $locale->getText("emails.csvExport.{$emailType}.hello");
|
||||
$body = $locale->getText("emails.csvExport.{$emailType}.body");
|
||||
$footer = $locale->getText("emails.csvExport.{$emailType}.footer");
|
||||
$thanks = $locale->getText("emails.csvExport.{$emailType}.thanks");
|
||||
$signature = $locale->getText("emails.csvExport.{$emailType}.signature");
|
||||
$buttonText = $success ? $locale->getText("emails.csvExport.{$emailType}.buttonText") : '';
|
||||
|
||||
// Build email body using inner template
|
||||
$message = Template::fromFile(__DIR__ . '/../../../../app/config/locale/templates/email-inner-base.tpl')
|
||||
|
|
@ -549,7 +595,8 @@ class Migrations extends Action
|
|||
->setParam('{{direction}}', $locale->getText('settings.direction'))
|
||||
->setParam('{{project}}', $project->getAttribute('name'))
|
||||
->setParam('{{user}}', $user->getAttribute('name', $user->getAttribute('email')))
|
||||
->setParam('{{redirect}}', $downloadUrl);
|
||||
->setParam('{{redirect}}', $downloadUrl)
|
||||
->setParam('{{size}}', $success ? '' : (string)$sizeMB);
|
||||
|
||||
$emailBody = $message->render();
|
||||
|
||||
|
|
@ -557,9 +604,14 @@ class Migrations extends Action
|
|||
'direction' => $locale->getText('settings.direction'),
|
||||
'project' => $project->getAttribute('name'),
|
||||
'user' => $user->getAttribute('name', $user->getAttribute('email')),
|
||||
'redirect' => $downloadUrl,
|
||||
];
|
||||
|
||||
if ($success) {
|
||||
$emailVariables['redirect'] = $downloadUrl;
|
||||
} else {
|
||||
$emailVariables['size'] = (string)$sizeMB;
|
||||
}
|
||||
|
||||
$queueForMails
|
||||
->setSubject($subject)
|
||||
->setPreview($preview)
|
||||
|
|
@ -570,11 +622,14 @@ class Migrations extends Action
|
|||
->setRecipient($user->getAttribute('email'))
|
||||
->trigger();
|
||||
|
||||
Console::info('CSV export notification email sent to ' . $user->getAttribute('email'));
|
||||
Console::info("CSV export {$emailType} notification email sent to " . $user->getAttribute('email'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize a filename to make it filesystem-safe
|
||||
*
|
||||
* @param string $filename
|
||||
* @return string
|
||||
*/
|
||||
protected function sanitizeFilename(string $filename): string
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue