feat: engagment notifications
This commit is contained in:
parent
df94a23a19
commit
f716a205ce
|
|
@ -3,6 +3,7 @@ APP_ENV=local
|
|||
APP_KEY=
|
||||
APP_DEBUG=true
|
||||
APP_URL=http://localhost
|
||||
APP_MOBILE_SCHEME=bowly
|
||||
APP_PORT=8003
|
||||
APP_LOCALE=fr
|
||||
APP_FALLBACK_LOCALE=en
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use App\Http\Requests\StravaCallbackRequest;
|
|||
use App\Http\Requests\StravaSyncRequest;
|
||||
use App\Models\StravaConnection;
|
||||
use App\Models\WorkoutSessions;
|
||||
use App\Services\MobileDeepLink;
|
||||
use App\Services\StravaClient;
|
||||
use Illuminate\Http\Client\ConnectionException;
|
||||
use Illuminate\Http\Client\RequestException;
|
||||
|
|
@ -40,10 +41,7 @@ class StravaController extends Controller
|
|||
->filter(fn ($value): bool => $value !== null && $value !== '')
|
||||
->all();
|
||||
|
||||
$query = http_build_query($params, '', '&', PHP_QUERY_RFC3986);
|
||||
$url = 'bowly://strava/callback'.($query ? "?{$query}" : '');
|
||||
|
||||
return redirect()->away($url);
|
||||
return redirect()->away(MobileDeepLink::to('strava/callback', $params));
|
||||
}
|
||||
|
||||
public function callback(StravaCallbackRequest $request, StravaClient $strava): JsonResponse
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
namespace App\Notifications;
|
||||
|
||||
use App\Models\PostReviews;
|
||||
use App\Services\MobileDeepLink;
|
||||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Notifications\Notification;
|
||||
use Illuminate\Support\Str;
|
||||
|
|
@ -42,7 +43,7 @@ class MealPostCommentedNotification extends Notification
|
|||
'sound' => 'default',
|
||||
'channelId' => 'default',
|
||||
'data' => [
|
||||
'url' => "bowly://meals/{$mealPostId}",
|
||||
'url' => MobileDeepLink::to("meals/{$mealPostId}"),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,6 +54,8 @@ return [
|
|||
|
||||
'url' => env('APP_URL', 'http://localhost'),
|
||||
|
||||
'mobile_scheme' => env('APP_MOBILE_SCHEME', 'bowly'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Application Timezone
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ env:
|
|||
APP_DEBUG: "false"
|
||||
APP_NAME: "Bowly"
|
||||
APP_URL: https://bemeal.leonmorival.com
|
||||
APP_MOBILE_SCHEME: bowly
|
||||
SERVER_NAME: ":80"
|
||||
APP_RUNTIME: "Laravel\\FrankenPHP\\Runtime"
|
||||
FILESYSTEM_DISK: s3
|
||||
|
|
|
|||
|
|
@ -37,17 +37,6 @@ services:
|
|||
networks:
|
||||
- internal
|
||||
|
||||
meilisearch:
|
||||
image: getmeili/meilisearch:latest
|
||||
container_name: bemeal-meilisearch
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
MEILI_NO_ANALYTICS: "true"
|
||||
MEILI_MASTER_KEY: "${MEILISEARCH_KEY:?MEILISEARCH_KEY is required}"
|
||||
volumes:
|
||||
- meilisearch-data:/meili_data
|
||||
networks:
|
||||
- internal
|
||||
|
||||
volumes:
|
||||
pgsql-data:
|
||||
|
|
@ -57,9 +46,6 @@ volumes:
|
|||
redis-data:
|
||||
name: bemeal_redis_data
|
||||
|
||||
meilisearch-data:
|
||||
name: bemeal_meilisearch_data
|
||||
|
||||
networks:
|
||||
internal:
|
||||
external: true
|
||||
|
|
|
|||
|
|
@ -38,6 +38,28 @@ return [
|
|||
'your_meal' => 'your meal',
|
||||
'moderation_threshold_title' => 'Reports need review',
|
||||
'moderation_threshold_body' => ':count reports received for :type.',
|
||||
'engagement_reminders' => [
|
||||
'publish_meal' => [
|
||||
'title' => 'Your next meal is waiting',
|
||||
'body' => "Do not hesitate to publish today's meal on Bowli.",
|
||||
],
|
||||
'meal_photo' => [
|
||||
'title' => 'A plate worth sharing?',
|
||||
'body' => 'Take a quick photo and keep track of your meal.',
|
||||
],
|
||||
'evening_checkin' => [
|
||||
'title' => 'Small Bowli reminder',
|
||||
'body' => "Add today's meal to keep your habits on track.",
|
||||
],
|
||||
'community_inspiration' => [
|
||||
'title' => 'Inspire the community',
|
||||
'body' => 'Publish your meal and give other users new ideas.',
|
||||
],
|
||||
'workout_checkin' => [
|
||||
'title' => 'Meal or workout?',
|
||||
'body' => 'If you moved today, add your workout in Bowli too.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'reports' => [
|
||||
'created' => 'Report sent. Thanks, our team will review this content.',
|
||||
|
|
|
|||
|
|
@ -38,6 +38,28 @@ return [
|
|||
'your_meal' => 'votre plat',
|
||||
'moderation_threshold_title' => 'Signalements à vérifier',
|
||||
'moderation_threshold_body' => ':count signalements reçus pour :type.',
|
||||
'engagement_reminders' => [
|
||||
'publish_meal' => [
|
||||
'title' => 'Ton prochain plat attend',
|
||||
'body' => 'N’hésite pas à publier ton repas du jour sur Bowli.',
|
||||
],
|
||||
'meal_photo' => [
|
||||
'title' => 'Une assiette à partager ?',
|
||||
'body' => 'Prends une photo rapide et garde une trace de ton repas.',
|
||||
],
|
||||
'evening_checkin' => [
|
||||
'title' => 'Petit rappel Bowli',
|
||||
'body' => 'Ajoute ton plat du jour pour suivre tes habitudes sans perdre le fil.',
|
||||
],
|
||||
'community_inspiration' => [
|
||||
'title' => 'Inspire la communauté',
|
||||
'body' => 'Publie ton plat et donne des idées aux autres utilisateurs.',
|
||||
],
|
||||
'workout_checkin' => [
|
||||
'title' => 'Repas ou workout ?',
|
||||
'body' => 'Si tu as bougé aujourd’hui, ajoute aussi ta séance dans Bowli.',
|
||||
],
|
||||
],
|
||||
],
|
||||
'reports' => [
|
||||
'created' => 'Signalement envoyé. Merci, notre équipe va examiner ce contenu.',
|
||||
|
|
|
|||
|
|
@ -53,7 +53,6 @@ Route::prefix('legal-documents')->group(function (): void {
|
|||
Route::middleware(['auth:sanctum', 'verified', 'not_suspended'])->group(function (): void {
|
||||
Route::post('device-tokens', [DeviceTokenController::class, 'store'])->middleware('throttle:device-token');
|
||||
Route::delete('device-tokens', [DeviceTokenController::class, 'destroy'])->middleware('throttle:device-token');
|
||||
Route::get('test-notifs', [DeviceTokenController::class, 'notifs'])->middleware('throttle:notifications');
|
||||
});
|
||||
|
||||
// Workouts
|
||||
|
|
|
|||
|
|
@ -25,3 +25,7 @@ Schedule::command('meal-posts:generate-ai')
|
|||
->daily()
|
||||
->withoutOverlapping(55)
|
||||
->onOneServer();
|
||||
Schedule::command('notifications:send-engagement-reminders')
|
||||
->dailyAt('12:30')
|
||||
->withoutOverlapping(30)
|
||||
->onOneServer();
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ it('creates one review per user for a meal post', function () {
|
|||
});
|
||||
|
||||
it('sends a push notification to the meal owner when another user comments on their meal', function () {
|
||||
config()->set('app.mobile_scheme', 'dailymeal');
|
||||
|
||||
Http::fake([
|
||||
'https://exp.host/*' => Http::response([
|
||||
'data' => [
|
||||
|
|
@ -77,7 +79,7 @@ it('sends a push notification to the meal owner when another user comments on th
|
|||
'sound' => 'default',
|
||||
'channelId' => 'default',
|
||||
'data' => [
|
||||
'url' => "bowly://meals/{$mealPost->id}",
|
||||
'url' => "dailymeal://meals/{$mealPost->id}",
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
|
||||
it('schedules expired auth and stale device token cleanup commands', function () {
|
||||
it('schedules maintenance and engagement commands', function () {
|
||||
Artisan::call('schedule:list', [
|
||||
'--json' => true,
|
||||
]);
|
||||
|
|
@ -13,5 +13,6 @@ it('schedules expired auth and stale device token cleanup commands', function ()
|
|||
expect($commands)
|
||||
->toContain('php artisan sanctum:prune-expired --hours=24')
|
||||
->toContain('php artisan auth:clear-resets')
|
||||
->toContain('php artisan device-tokens:prune-stale --days=180');
|
||||
->toContain('php artisan device-tokens:prune-stale --days=180')
|
||||
->toContain('php artisan notifications:send-engagement-reminders');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@ it('returns a strava authorization url for the api callback', function () {
|
|||
});
|
||||
|
||||
it('redirects the strava web callback to the mobile app', function () {
|
||||
config()->set('app.mobile_scheme', 'dailymeal');
|
||||
|
||||
$query = http_build_query([
|
||||
'code' => 'authorization-code',
|
||||
'scope' => 'read activity:read',
|
||||
|
|
@ -46,7 +48,7 @@ it('redirects the strava web callback to the mobile app', function () {
|
|||
|
||||
$this
|
||||
->get("/strava/callback?{$query}")
|
||||
->assertRedirect("bowly://strava/callback?{$query}");
|
||||
->assertRedirect("dailymeal://strava/callback?{$query}");
|
||||
});
|
||||
|
||||
it('stores strava tokens from an authorization code', function () {
|
||||
|
|
|
|||
Loading…
Reference in New Issue