-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(frontend|backend): To good to go (#198)
- Loading branch information
Showing
16 changed files
with
452 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
use Migrations\AbstractMigration; | ||
|
||
class AddUserSlackTimeZone extends AbstractMigration | ||
{ | ||
/** | ||
* Up Method. | ||
* | ||
* More information on this method is available here: | ||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-up-method | ||
* | ||
* @return void | ||
*/ | ||
public function up(): void | ||
{ | ||
$this->table('users') | ||
->addColumn('slack_time_zone', 'string', [ | ||
'after' => 'progression_id', | ||
'default' => null, | ||
'length' => 255, | ||
'null' => true, | ||
]) | ||
->update(); | ||
} | ||
|
||
/** | ||
* Down Method. | ||
* | ||
* More information on this method is available here: | ||
* https://book.cakephp.org/phinx/0/en/migrations.html#the-down-method | ||
* | ||
* @return void | ||
*/ | ||
public function down(): void | ||
{ | ||
$this->table('users') | ||
->removeColumn('slack_time_zone') | ||
->update(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
<?php | ||
declare(strict_types=1); | ||
|
||
namespace App\Command; | ||
|
||
use App\Database\Log\SentryQueryLogger; | ||
use App\Http\SlackClient; | ||
use Cake\Chronos\Chronos; | ||
use Cake\Command\Command; | ||
use Cake\Console\Arguments; | ||
use Cake\Console\ConsoleIo; | ||
use Cake\Console\ConsoleOptionParser; | ||
use Cake\Datasource\ConnectionManager; | ||
use DateTimeZone; | ||
use Sentry\MonitorConfig; | ||
use Sentry\MonitorSchedule; | ||
use Sentry\SentrySdk; | ||
use Sentry\Tracing\SpanContext; | ||
use Sentry\Tracing\SpanStatus; | ||
use Sentry\Tracing\TransactionContext; | ||
use Sentry\Tracing\TransactionSource; | ||
use Throwable; | ||
use function Sentry\captureException; | ||
use function Sentry\startTransaction; | ||
use function Sentry\withMonitor; | ||
|
||
/** | ||
* TooGoodToGo command. | ||
*/ | ||
class TooGoodToGoCommand extends Command | ||
{ | ||
private const int TARGET_HOUR = 16; | ||
|
||
/** | ||
* Hook method for defining this command's option parser. | ||
* | ||
* @see https://book.cakephp.org/4/en/console-commands/commands.html#defining-arguments-and-options | ||
* @param \Cake\Console\ConsoleOptionParser $parser The parser to be defined | ||
* @return \Cake\Console\ConsoleOptionParser The built parser. | ||
*/ | ||
public function buildOptionParser(ConsoleOptionParser $parser): ConsoleOptionParser | ||
{ | ||
$parser = parent::buildOptionParser($parser); | ||
|
||
return $parser; | ||
} | ||
|
||
/** | ||
* @param \Cake\Console\Arguments $args The command arguments. | ||
* @param \Cake\Console\ConsoleIo $io The console io | ||
* @return int|null|void The exit code or null for success | ||
*/ | ||
public function execute(Arguments $args, ConsoleIo $io) | ||
{ | ||
withMonitor( | ||
slug: 'too-good-to-go', | ||
callback: fn () => $this->_execute($args, $io), | ||
monitorConfig: new MonitorConfig( | ||
schedule: new MonitorSchedule( | ||
type: MonitorSchedule::TYPE_CRONTAB, | ||
value: '*/30 * * * 1-5', | ||
), | ||
checkinMargin: 5, | ||
maxRuntime: 10, | ||
timezone: 'UTC', | ||
), | ||
); | ||
} | ||
|
||
/** | ||
* @param \Cake\Console\Arguments $args The command arguments. | ||
* @param \Cake\Console\ConsoleIo $io The console io | ||
* @return int|null|void The exit code or null for success | ||
*/ | ||
protected function _execute(Arguments $args, ConsoleIo $io) | ||
{ | ||
$io->out('Sending out Too Good To Go notifications'); | ||
|
||
$slackClient = new SlackClient(); | ||
|
||
$logger = new SentryQueryLogger(); | ||
|
||
$connection = ConnectionManager::get('default'); | ||
$connection->getDriver()->setLogger($logger); | ||
|
||
$transactionContext = TransactionContext::make() | ||
->setOp('command') | ||
->setName('COMMAND too_good_to_go') | ||
->setSource(TransactionSource::task()); | ||
|
||
$transaction = startTransaction($transactionContext); | ||
|
||
SentrySdk::getCurrentHub()->setSpan($transaction); | ||
|
||
$usersTable = $this->fetchTable('Users'); | ||
$users = $usersTable->find() | ||
->where([ | ||
'slack_time_zone IN' => $this->_getApplicableTimeZones(), | ||
]) | ||
->all(); | ||
|
||
foreach ($users as $user) { | ||
if ( | ||
$user->notifications['too_good_to_go'] !== true | ||
|| $user->potatoLeftToday() <= 0 | ||
) { | ||
continue; | ||
} | ||
|
||
$spanContext = SpanContext::make() | ||
->setOp('command') | ||
->setDescription('Send notification'); | ||
$span = $transaction->startChild($spanContext); | ||
|
||
SentrySdk::getCurrentHub()->setSpan($span); | ||
|
||
try { | ||
$message = 'Hallo, just letting you know that you have *' . $user->potatoLeftToday() | ||
. '* 🥔 left to gib today 🌱' . PHP_EOL; | ||
$message .= 'Would be a bummer if they go to waste 😢' . PHP_EOL; | ||
$message .= 'If someone did something nice today, gib them 🥔😊!'; | ||
|
||
$slackClient->postMessage( | ||
channel: $user->slack_user_id, | ||
text: $message, | ||
); | ||
|
||
$span->setStatus(SpanStatus::ok()); | ||
} catch (Throwable $e) { | ||
captureException($e); | ||
$span->setStatus(SpanStatus::internalError()); | ||
} finally { | ||
$span->finish(); | ||
} | ||
} | ||
SentrySdk::getCurrentHub()->setSpan($transaction); | ||
|
||
$transaction->setStatus(SpanStatus::ok()) | ||
->finish(); | ||
|
||
$io->success("\n[DONE]"); | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
protected function _getApplicableTimeZones(): array | ||
{ | ||
$timeZones = DateTimeZone::listIdentifiers(); | ||
$applicableTimeZones = []; | ||
|
||
foreach ($timeZones as $timezone) { | ||
$localNow = new Chronos(timezone: $timezone); | ||
if ($localNow->hour === self::TARGET_HOUR) { | ||
$applicableTimeZones[] = $timezone; | ||
} | ||
} | ||
|
||
return $applicableTimeZones; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.