Skip to content

Commit

Permalink
Email: all current members
Browse files Browse the repository at this point in the history
close #314
  • Loading branch information
dpslwk committed Jul 17, 2019
1 parent a03be50 commit 243e44c
Show file tree
Hide file tree
Showing 22 changed files with 2,288 additions and 554 deletions.
126 changes: 126 additions & 0 deletions app/Http/Controllers/EmailController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php

namespace App\Http\Controllers;

use HMS\Entities\Role;
use Illuminate\Http\Request;
use App\Mail\ToCurrentMembers;
use Illuminate\Support\HtmlString;
use App\Jobs\EmailCurrentMembersJob;
use HMS\Repositories\RoleRepository;
use Illuminate\Contracts\View\Factory as ViewFactory;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;

class EmailController extends Controller
{
/**
* @var RoleRepository
*/
protected $roleRepository;

/**
* Create a new controller instance.
*
* @param RoleRepository $roleRepository
*/
public function __construct(
RoleRepository $roleRepository
) {
$this->roleRepository = $roleRepository;

$this->middleware('can:email.allMembers');
}

/**
* Show the draft email view.
*
* @return \Illuminate\Http\Response
*/
public function draft()
{
$draft = \Cache::get('emailMembers.draft', [
'subject' => '',
'emailContent' => '',
]);

return view('emailMembers.draft', $draft);
}

/**
* Store the draft email and return a preview.
*
* @param Illuminate\Http\Request $request
*
* @return \Illuminate\Http\Response
*/
public function review(Request $request)
{
\Cache::put('emailMembers.draft', [
'subject' => $request->subject,
'emailContent' => $request->emailContent,
], now()->addMinutes(30));

$emailView = new ToCurrentMembers($request->subject, $request->emailContent);
$renderedTextPlain = $emailView->renderText();

$currentMemberCount = $this->roleRepository->findOneByName(Role::MEMBER_CURRENT)->getUsers()->count();

return view('emailMembers.review')
->with([
'subject' => $request->subject,
'emailPlain' => $renderedTextPlain,
'currentMemberCount' => $currentMemberCount,
]);
}

/**
* Show a html review of the draft email.
*
* @param ViewFactory $viewFactory
* @param CssToInlineStyles $cssToInlineStyles
*
* @return \Illuminate\Http\Response
*/
public function reviewHtml(ViewFactory $viewFactory, CssToInlineStyles $cssToInlineStyles)
{
$draft = \Cache::get('emailMembers.draft', [
'subject' => '',
'emailContent' => '',
]);

$emailView = new ToCurrentMembers($draft['subject'], $draft['emailContent']);
$renderedHtml = $emailView->render();
// TODO: build theme string from config
$renderedHtmlCSS = new HtmlString(
$cssToInlineStyles->convert(
$renderedHtml,
$viewFactory->make('vendor.mail.html.themes.hms')->render()
)
);

return response($renderedHtmlCSS);
}

/**
* Send the email.
*
* @param Illuminate\Http\Request $request
*
* @return \Illuminate\Http\RedirectResponse
*/
public function send(Request $request)
{
$draft = \Cache::get('emailMembers.draft');

EmailCurrentMembersJob::dispatch($draft['subject'], $draft['emailContent'], $request->testSend);

if (! $request->testSend) {
flash('Email queued for sending', 'success');
\Cache::forget('emailMembers.draft');
} else {
flash('Test email queued for sending', 'success');
}

return redirect()->route('email-members.draft');
}
}
132 changes: 132 additions & 0 deletions app/Jobs/EmailCurrentMembersJob.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
<?php

namespace App\Jobs;

use HMS\Entities\Role;
use Soundasleep\Html2Text;
use Illuminate\Bus\Queueable;
use App\Mail\ToCurrentMembers;
use Illuminate\Support\HtmlString;
use HMS\Repositories\RoleRepository;
use Bogardo\Mailgun\Contracts\Mailgun;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Contracts\View\Factory as ViewFactory;
use TijsVerkoyen\CssToInlineStyles\CssToInlineStyles;

class EmailCurrentMembersJob implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

/**
* The email subject.
*
* @var string
*/
public $subject;

/**
* The email content as text/html.
*
* @var string
*/
public $htmlContent;

/**
* Should this only sent as a test.
*
* @var bool
*/
public $testSend;

/**
* Create a new job instance.
*
* @param string $subject The email subject.
* @param string $htmlContent The email content as text/html.
* @param bool $testSend Should this only sent as a test.
*/
public function __construct(
string $subject,
string $htmlContent,
bool $testSend = true
) {
$this->subject = $subject;
$this->htmlContent = $htmlContent;
$this->testSend = $testSend;
}

/**
* Execute the job.
*
* @param Mailgun $mailgun
* @param CssToInlineStyles $cssToInlineStyles
* @param ViewFactory $viewFactory
* @param RoleRepository $roleRepository
*
* @return void
*/
public function handle(
Mailgun $mailgun,
CssToInlineStyles $cssToInlineStyles,
ViewFactory $viewFactory,
RoleRepository $roleRepository
) {
$trusteesRole = $roleRepository->findOneByName(Role::TEAM_TRUSTEES);
$trusteesEmail = $trusteesRole->getEmail();

$currentMembers = $roleRepository->findOneByName(Role::MEMBER_CURRENT)->getUsers();

// Send using Mailgun
$views = [
'html' => 'emails.emailMembers.toCurrentMembers_mailgun',
'text' => 'emails.emailMembers.toCurrentMembers_plain',
];

$emailView = new ToCurrentMembers($this->subject, $this->htmlContent);
$renderedHtml = $emailView->render();
$renderedHtmlCSS = new HtmlString(
$cssToInlineStyles->convert(
$renderedHtml,
$viewFactory->make('vendor.mail.html.themes.default')->render()
)
);

$data = [
'htmlContent' => $renderedHtmlCSS,
'textPlain' => Html2Text::convert($this->htmlContent),
];

if ($this->testSend) {
// only send to the trustees address
$to = [
$trusteesEmail => [
'name' => 'Trustees',
],
];
} else {
// send to all current members
// this converts to an Illuminate\Support\Collection first then maps our User object
$to = collect($currentMembers)->mapWithKeys(function ($user) {
return [$user->getEmail() => [
'name' => $user->getFirstname(),
],
];
})->toArray();
}

$trusteesMgEmail = preg_replace('/@/m', '@mg.', $trusteesEmail);
$subject = $this->subject;
$mailgun->send($views, $data, function ($message) use ($subject, $trusteesEmail, $trusteesMgEmail, $to) {
$message
->trackOpens(true)
->subject($subject)
->header('sender', 'Nottingham Hackspace Trustees <' . $trusteesMgEmail . '>')
->replyTo($trusteesEmail, 'Nottingham Hackspace Trustees')
->from($trusteesMgEmail, 'Nottingham Hackspace Trustees')
->to($to);
});
}
}
78 changes: 78 additions & 0 deletions app/Mail/ToCurrentMembers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?php

namespace App\Mail;

use Soundasleep\Html2Text;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Container\Container;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class ToCurrentMembers extends Mailable implements ShouldQueue
{
use Queueable, SerializesModels;

/**
* The email subject.
*
* @var string
*/
public $subject;

/**
* The email content as text/html.
*
* @var string
*/
public $htmlContent;

/**
* The email content as text/plain.
*
* @var string
*/
public $textPlain;

/**
* Create a new message instance.
*
* @param string $subject The email subject.
* @param string $htmlContent The email content as text/html.
*/
public function __construct(string $subject, string $htmlContent)
{
$this->subject = $subject;
$this->htmlContent = $htmlContent;
$this->textPlain = Html2Text::convert($htmlContent);

//TODO: for hms2 pull trustee address from Role::TEAM_TRUSTEES
}

/**
* Build the message.
*
* @return $this
*/
public function build()
{
return $this->from('[email protected]', 'Nottingham Hackspace Trustees')
->subject($this->subject)
->view('emails.emailMembers.toCurrentMembers')
->text('emails.emailMembers.toCurrentMembers_plain');
}

/**
* Render the template into text.
*
* @return \Illuminate\Support\HtmlString
*/
public function renderText()
{
Container::getInstance()->call([$this, 'build']);

return Container::getInstance()->make('mailer')->render(
'emails.emailMembers.toCurrentMembers_plain', $this->buildViewData()
);
}
}
7 changes: 7 additions & 0 deletions app/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,12 @@ public function boot()
\Blade::directive('format_pennies', function ($pennies) {
return "<?php echo money_format('%n', (" . $pennies . ')/100); ?>';
});

// setup Guzzle6 for mailgun batch sender
$this->app->bind('mailgun.client', function () {
return \Http\Adapter\Guzzle6\Client::createWithConfig([
// your Guzzle6 configuration
]);
});
}
}
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
"type": "project",
"require": {
"php": "^7.1.3",
"bogardo/mailgun": "^5.1",
"brainrepo/carbon-normalizer": "dev-master",
"fideloper/proxy": "^4.0",
"garygreen/pretty-routes": "^1.0",
"gedmo/doctrine-extensions": "^2.4",
"guzzlehttp/guzzle": "^6.3",
"karpy47/php-mqtt-client": "^1.0",
"karpy47/php-mqtt-client": "dev-master",
"laracasts/flash": "^3.0",
"laravel-doctrine/acl": "1.0.*",
"laravel-doctrine/extensions": "^1.0",
Expand All @@ -26,7 +27,9 @@
"maxbrokman/safe-queue": "^0.3.0",
"orphans/git-deploy-laravel": "dev-master",
"pda/pheanstalk": "~4.0",
"php-http/guzzle6-adapter": "^1.1",
"predis/predis": "^1.1",
"soundasleep/html2text": "^1.1",
"spatie/laravel-cookie-consent": "^2.0",
"tremby/laravel-git-version": "^1.1"
},
Expand Down
Loading

0 comments on commit 243e44c

Please sign in to comment.