Skip to content

Commit 9b87ff7

Browse files
committed
fix: Add notification for new loves
1 parent 94158ed commit 9b87ff7

9 files changed

Lines changed: 347 additions & 0 deletions

File tree

website/app-templates/smarty/dialog/user_update_email.tpl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@
4646
<input type="checkbox" name="instant_notifications_move_comments" class="instant-notif-checkbox" {if $instant_notifications_move_comments}checked{/if}>{t}Comments on moves{/t}
4747
</label>
4848
</div>
49+
<div class="checkbox">
50+
<label>
51+
<input type="checkbox" name="instant_notifications_loves" class="instant-notif-checkbox" {if $instant_notifications_loves}checked{/if}>{t}Loves on my GeoKrety{/t}
52+
</label>
53+
</div>
4954
</div>
5055

5156
<hr />

website/app-templates/smarty/emails/daily-digest.tpl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,44 @@
193193
</tbody>
194194
</table>
195195
{/if}
196+
197+
{if $loves}
198+
<div class="s-6"></div>
199+
<h5>{t}GeoKrety loves ❤️{/t}</h5>
200+
<div class="s-3"></div>
201+
<table class="table table-striped thead-default table-bordered">
202+
<thead>
203+
<tr>
204+
<th>{t}GeoKret{/t}</th>
205+
<th>{t}Current position{/t}</th>
206+
<th>{t}Type{/t}</th>
207+
<th>{t}Loved by{/t}</th>
208+
<th>{t}Date{/t}</th>
209+
</tr>
210+
</thead>
211+
<tbody>
212+
{foreach from=$loves item=love}
213+
<tr>
214+
<td>
215+
{$love->geokret|gklink nofilter}<br>
216+
<small>{$love->geokret->gkid}</small>
217+
</td>
218+
<td nowrap>
219+
{if !is_null($love->geokret->lat) and !is_null($love->geokret->lon)}{$love->geokret->country|country:'html_email' nofilter}{/if}
220+
<small>{$love->geokret|cachelink nofilter}</small>
221+
</td>
222+
<td>
223+
{$love->geokret->type|gktype nofilter}
224+
</td>
225+
<td class="text-center text-sm" nowrap>
226+
{$love->user|userlink nofilter}
227+
</td>
228+
<td class="text-center text-sm" nowrap>
229+
{$love->created_on_datetime|print_date_iso_format nofilter}
230+
</td>
231+
</tr>
232+
{/foreach}
233+
</tbody>
234+
</table>
235+
{/if}
196236
{/block}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
{extends file='emails/base.tpl'}
2+
{assign "fluid" "false"}
3+
4+
{block name=title}{/block}
5+
{block name=preview}{t geokret=$geokret->name}Someone loved your %1! ❤️{/t}{/block}
6+
7+
{block name=reason}
8+
{t}You're getting this email because you've enabled instant notifications for loves.{/t}
9+
{t escape=no url={'user_update_email'|alias}}You can disable this by <a href="%1">changing your personal mail preferences</a>.{/t}
10+
{/block}
11+
12+
{block name=content}
13+
<h5>{t geokret=$geokret->name}Someone loved your %1! ❤️{/t}</h5>
14+
<div class="s-3"></div>
15+
<table class="table table-striped thead-default table-bordered">
16+
<thead>
17+
<tr>
18+
<th>{t}GeoKret{/t}</th>
19+
<th>{t}Current position{/t}</th>
20+
<th>{t}Type{/t}</th>
21+
<th>{t}Loved by{/t}</th>
22+
<th>{t}Date{/t}</th>
23+
</tr>
24+
</thead>
25+
<tbody>
26+
<tr>
27+
<td>
28+
{$geokret|gklink nofilter}<br>
29+
<small>{$geokret->gkid}</small>
30+
</td>
31+
<td nowrap>
32+
{if !is_null($geokret->lat) and !is_null($geokret->lon)}{$geokret->country|country:'html_email' nofilter}{/if}
33+
<small>{$geokret|cachelink nofilter}</small>
34+
</td>
35+
<td>
36+
{$geokret->type|gktype nofilter}
37+
</td>
38+
<td class="text-center text-sm" nowrap>
39+
{$lover|userlink nofilter}
40+
</td>
41+
<td class="text-center text-sm" nowrap>
42+
{$love->created_on_datetime|print_date_iso_format nofilter}
43+
</td>
44+
</tr>
45+
</tbody>
46+
</table>
47+
48+
<div class="s-3"></div>
49+
50+
<div class="text-center">
51+
<a href="{$geokret|geokrety_direct_link}" class="btn btn-primary" style="display: inline-block; padding: 10px 20px; background-color: #d9534f; color: white; text-decoration: none; border-radius: 5px;">
52+
{t}View GeoKret details{/t}
53+
</a>
54+
</div>
55+
56+
{/block}

website/app/GeoKrety/Controller/Cli/DailyDigest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,7 @@ protected function send() {
153153
$this->load_last_moves_owned_geokrety();
154154
$this->load_last_moves_watched_geokrety();
155155
$this->load_moves_comments();
156+
$this->load_loves();
156157
$this->load_near_home_dropped_geokrety();
157158

158159
if (!$this->updates_count) {
@@ -235,6 +236,34 @@ private function load_moves_comments() {
235236
Smarty::assign('comments', sizeof($comments) ? $comments : false);
236237
}
237238

239+
private function load_loves() {
240+
$this->console_writer->print([$this->user->id, $this->user->username, 'load loves']);
241+
$sql = <<<'SQL'
242+
SELECT gl.*, gk.id as geokret_id, gk.gkid, gk.name as geokret_name, u.id as lover_id, u.username as lover_username
243+
FROM gk_loves gl
244+
INNER JOIN gk_geokrety gk ON gl.geokret = gk.id
245+
INNER JOIN gk_users u ON gl.user = u.id
246+
WHERE (
247+
-- Loves on user's own GeoKrety
248+
gk.owner = ?
249+
OR
250+
-- Loves on user's watched GeoKrety
251+
gk.id IN (
252+
SELECT geokret
253+
FROM gk_watched
254+
WHERE "user" = ?
255+
)
256+
)
257+
AND gl.created_on_datetime >= ?
258+
ORDER BY gl.created_on_datetime DESC
259+
LIMIT 100
260+
SQL;
261+
$lovesDb = new \GeoKrety\Model\GeokretLove();
262+
$loves = $lovesDb->findByRawSQL($sql, [$this->user->id, $this->user->id, $this->since->format(GK_DB_DATETIME_FORMAT)]);
263+
$this->updates_count += $loves ? 1 : 0;
264+
Smarty::assign('loves', $loves ? $loves : false);
265+
}
266+
238267
/**
239268
* @throws Exception
240269
*/

website/app/GeoKrety/Controller/Pages/UserUpdateEmail.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public function get(\Base $f3) {
2424
Smarty::assign('instant_notifications_moves_watched_gk', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_MOVES_WATCHED_GK'));
2525
Smarty::assign('instant_notifications_moves_around_home', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_MOVES_AROUND_HOME'));
2626
Smarty::assign('instant_notifications_move_comments', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_MOVE_COMMENTS'));
27+
Smarty::assign('instant_notifications_loves', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_LOVES'));
2728
Smarty::render('extends:full_screen_modal.tpl|dialog/user_update_email.tpl');
2829
}
2930

@@ -38,6 +39,7 @@ public function get_ajax(\Base $f3) {
3839
Smarty::assign('instant_notifications_moves_watched_gk', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_MOVES_WATCHED_GK'));
3940
Smarty::assign('instant_notifications_moves_around_home', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_MOVES_AROUND_HOME'));
4041
Smarty::assign('instant_notifications_move_comments', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_MOVE_COMMENTS'));
42+
Smarty::assign('instant_notifications_loves', UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_LOVES'));
4143
Smarty::render('extends:base_modal.tpl|dialog/user_update_email.tpl');
4244
}
4345

@@ -53,6 +55,7 @@ public function post(\Base $f3) {
5355
$instant_notifications_moves_watched_gk = filter_var($f3->get('POST.instant_notifications_moves_watched_gk'), FILTER_VALIDATE_BOOLEAN);
5456
$instant_notifications_moves_around_home = filter_var($f3->get('POST.instant_notifications_moves_around_home'), FILTER_VALIDATE_BOOLEAN);
5557
$instant_notifications_move_comments = filter_var($f3->get('POST.instant_notifications_move_comments'), FILTER_VALIDATE_BOOLEAN);
58+
$instant_notifications_loves = filter_var($f3->get('POST.instant_notifications_loves'), FILTER_VALIDATE_BOOLEAN);
5659

5760
// If instant_notifications is enabled, default all granular settings to true if not explicitly set
5861
if ($instant_notifications) {
@@ -96,6 +99,11 @@ public function post(\Base $f3) {
9699
$changed = true;
97100
}
98101

102+
if (UserSettings::getForCurrentUser('INSTANT_NOTIFICATIONS_LOVES') !== $instant_notifications_loves) {
103+
$userSettings->put($user, 'INSTANT_NOTIFICATIONS_LOVES', $instant_notifications_loves ? 'true' : 'false');
104+
$changed = true;
105+
}
106+
99107
if ($changed) {
100108
\Flash::instance()->addMessage(_('Your email preferences were saved.'), 'success');
101109
}

website/app/GeoKrety/Email/InstantNotification.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace GeoKrety\Email;
44

55
use GeoKrety\Model\Geokret;
6+
use GeoKrety\Model\GeokretLove;
67
use GeoKrety\Model\Move;
78
use GeoKrety\Model\MoveComment;
89
use GeoKrety\Model\User;
@@ -81,6 +82,38 @@ public function sendCommentNotification(User $user, MoveComment $comment) {
8182
return false;
8283
}
8384

85+
/**
86+
* Send instant notification for a new love on a GeoKret.
87+
*
88+
* @throws \PHPMailer\PHPMailer\Exception
89+
*/
90+
public function sendLoveNotification(User $user, GeokretLove $love) {
91+
// Prepare template data
92+
\GeoKrety\Service\Smarty::assign('love', $love);
93+
\GeoKrety\Service\Smarty::assign('geokret', $love->geokret);
94+
\GeoKrety\Service\Smarty::assign('lover', $love->user);
95+
96+
// Set subject with GeoKret name
97+
$this->setSubject(
98+
sprintf(_('Someone loved your %s! ❤️'), $love->geokret->name),
99+
'❤️'
100+
);
101+
102+
$this->setTo($user);
103+
$this->addCustomHeader('List-Unsubscribe-Post', 'List-Unsubscribe=One-Click');
104+
$unsubscribe_url = GK_SITE_BASE_SERVER_URL.\Base::instance()->alias('user_update_email_token', '@token='.$user->list_unsubscribe_token);
105+
$this->addCustomHeader('List-Unsubscribe', "<$unsubscribe_url>");
106+
107+
if ($this->sendEmail('emails/instant-love-notification.tpl')) {
108+
$user->touch('last_mail_datetime');
109+
$user->save();
110+
111+
return true;
112+
}
113+
114+
return false;
115+
}
116+
84117
/**
85118
* @throws \PHPMailer\PHPMailer\Exception
86119
*/
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Phinx\Migration\AbstractMigration;
6+
7+
final class AddLovedGeokretyNotifications extends AbstractMigration {
8+
public function up(): void {
9+
// Add loved geokrety notification settings parameters
10+
$this->execute("
11+
INSERT INTO geokrety.gk_users_settings_parameters (name, type, \"default\", description, created_on_datetime, updated_on_datetime)
12+
VALUES
13+
('INSTANT_NOTIFICATIONS_LOVES', 'bool', 'true', 'Receive instant notifications when someone loves my GeoKrety', NOW(), NOW());
14+
");
15+
}
16+
17+
public function down(): void {
18+
// Remove loved geokrety notification settings parameters
19+
$this->execute("
20+
DELETE FROM geokrety.gk_users_settings_parameters
21+
WHERE name = 'INSTANT_NOTIFICATIONS_LOVES';
22+
");
23+
24+
// Clean up any user settings for these parameters
25+
$this->execute("
26+
DELETE FROM geokrety.gk_users_settings
27+
WHERE name = 'INSTANT_NOTIFICATIONS_LOVES';
28+
");
29+
}
30+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
use Phinx\Migration\AbstractMigration;
6+
7+
final class AddLovedGeokretyAmqpTrigger extends AbstractMigration {
8+
public function up(): void {
9+
// Add AMQP trigger for loved geokrety notifications
10+
$this->execute('
11+
CREATE TRIGGER after_99_notify_amqp_loves
12+
AFTER INSERT ON geokrety.gk_loves
13+
FOR EACH ROW EXECUTE FUNCTION notify_queues.amqp_notify_id();
14+
');
15+
}
16+
17+
public function down(): void {
18+
// Remove AMQP trigger for loved geokrety notifications
19+
$this->execute('
20+
DROP TRIGGER IF EXISTS after_99_notify_amqp_loves ON geokrety.gk_loves;
21+
');
22+
}
23+
}

0 commit comments

Comments
 (0)